Module: Lich::DragonRealms::DRCA
- Defined in:
- documented/dragonrealms/commons/common-arcana.rb
Overview
DragonRealms Common Arcana: utility functions for spell preparation, casting, and magical item management. Provides the contract for spell-casting scripts in DragonRealms.
Constant Summary collapse
- CYCLIC_RELEASE_SUCCESS_PATTERNS =
Patterns matched when successfully releasing a cyclic spell. Each regex corresponds to the end-of-spell message for a cyclic ability across Ranger, Empath, Bard, Warrior Mage, Cleric, Paladin, Moon Mage, Trader, and Necromancer spell lines.
[ # Ranger spells /^The world seems to accelerate around you as the spirit of the cheetah escapes you/, # Cheetah Swiftness /^You feel distinctly frail and vulnerable as the spirit of the bear leaves you/, # Bear Strength /^The forces of nature that you roused are no longer with you/, # Awaken Forest # Empath spells /^Aesandry Darlaeth loses cohesion, returning your reaction time to normal/, # Aesandry Darlaeth /^You sense your hold on your Guardian Spirit weaken, then evaporate entirely/, # Guardian Spirit /^The signs of empathic atrocity escape to the deepest pits of your personality, your touch no longer deadly/, # Icutu Zaharenela /^The tingling across your body diminishes as you feel the motes of energy fade away/, # Regenerate # Bard spells /^You sing, purposely warbling some of the held notes for effec/, # Abandoned Heart (ABAN) /^The final tones of your enchante end with an abrupt flourish that leaves stark silence in its wake/, # Aether Wolves (AEWO) /^With a rising crescendo in your voice, you reprise the strong lines of the chorus of Albreda's Balm before bringing it to an abrupt conclusion/, # Albreda's Balm (ALB) /^The final, quiet notes of Blessing of the Fae stir the air gently, and die away/, # Blessing of the Fae (BOTF) /^The warm air swirling around you stills and begins to cool/, # Caress of the Sun (CARE) /^A few fleeting, soporific notes tarry in the air before your lullaby slowly dies down like the night receding at Anduwen/, # Damaris' Lullaby (DALU) /^You no longer feel the clarity of vision you had, as shadows creep across the area/, # Eye of Kertigen (EYE) /^You let your voice fade even as the pace of Faenella's Grace slows, winding down to a quiet conclusion/, # Faenella's Grace (FAE) /^The aethereal static subsides, returning your spellcasting abilities to normal/, # Glythtide's Joy (GJ) /^As your rendition of Hodierna's Lilt winds down to a close, you let each note linger on the air a moment, drawing out the final moment with a reluctance to let the soothing melody fade/, # Hodierna's Lilt (HODI) /^You build the final notes of Phoenix's Pyre with an upward scale that rises into a steep crescendo, and end with an abrupt silence/, # Phoenix's Pyre (PYRE) /^The dome of light extinguishes as the final notes of music die away/, # Sanctuary # Warrior Mage spells /^The dark mantle of aether surrounding you fades away/, # Aether Cloak (AC) /^You release your connection to the Elemental Plane of Electricity, allowing the static electricity to dissipate/, # Electrostatic Eddy (EE) /^Your link to the Fire Rain matrix has been severed/, # Fire Rain (FR) /^The chilling vapor surrounding you dissipates slowly/, # Rimefang (spell) (RIM) /^The frost-covered blade circling around you shatters into a fine icy mist/, # Rimefang (spell) (RIM) /^The jagged stone spears surrounding you at .* range tremble slightly, then crumble into a grey dust that is quickly reclaimed by the earth/, # Ring of Spears (ROS) # Cleric spells /^The deadening murk around you subsides/, # Hydra Hex (HYH) /^The dark patch of grime around you subsides/, # Hydra Hex (HYH) /^You sense the dark presence depart/, # Soul Attrition (SA) # Resurrection (REZZ) does not have messaging that makes it usable here. /^The heightened sense of spiritual awareness leaves you/, # Revelation (REV) /^The swirling fog dissipates from around you/, # Ghost Shroud (GHS) # Paladin spells /^The holy golden radiance of your soul subsides, retreating into your body/, # Holy Warrior (HOW) /^Truffenyi's Rally ends, leaving behind a momentary sensation of something stuck in your throat/, # Truffenyi's Rally (TR) # Moon Mage spells /^The web of shadows twitches one last time and then goes inert/, # Shadow Web (SHW) /^You release your mental hold on the lunar energy that sustains your moongate/, # Moongate (MG) /^The refractive field surrounding you fades away/, # Steps of Vuan (SOV) /^A .* sphere suddenly flares with a cold light and vaporizes/, # Starlight Sphere (SLS) # Trader spells /^Your calligraphy of light assailing/, # Arbiter's Stylus (ARS) /^The .* moonsmoke blows away from your face/, # Mask of the Moons (MOM) # Necromancer spells /^The Rite of Contrition matrix loses cohesion, leaving your aura naked/, # Rite of Contrition (ROC) /^The Rite of Forbearance matrix loses cohesion, leaving you to wallow in temptation/, # Rite of Forbearance (ROF) /^The Rite of Grace matrix loses cohesion, leaving your body exposed/, # Rite of Grace (ROG) /^The greenish hues about you vanish as the Universal Solvent matrix loses its cohesion/, # Universal Solvent (USOL) /^You sense your Call from Within spell weaken and disperse/ # Call from Within (CFW) ].freeze
- INFUSE_OM_SUCCESS_PATTERNS =
Patterns matched when Infuse Osrel Meraud succeeds. Includes messages for reaching full capacity, sensing fullness, or environmental interference.
[ 'having reached its full capacity', 'A sense of fullness', 'Something in the area is interfering with your attempt to harness' ].freeze
- INFUSE_OM_FAILURE_PATTERNS =
Patterns matched when Infuse Osrel Meraud fails. Includes messages for insufficient mana, hunger, and user error.
[ 'as if it hungers for more', 'Your infusion fails completely', "You don't have enough harnessed mana to infuse that much", 'You have no harnessed' ].freeze
- INFUSE_OM_MAX_RETRIES =
20- PREPARE_MAX_RETRIES =
3- CAST_MAX_RETRIES =
3- BARB_BUFF_MAX_RETRIES =
3- STOW_FOCUS_MAX_RETRIES =
3- WIELD_FOCUS_SUCCESS_PATTERNS =
Patterns matched when successfully wielding a spell focus.
[ /^You draw out/, /^You grab/, /^You slip/, /^You deftly remove/ ].freeze
- WIELD_FOCUS_FAILURE_PATTERNS =
Patterns matched when failing to wield a spell focus.
[ /^What were you/, /^Wield what/, /^You need a free hand/ ].freeze
- SHEATHE_FOCUS_SUCCESS_PATTERNS =
Patterns matched when successfully sheathing a spell focus.
[ /^You sheathe/, /^Sheathing/, /^You secure/, /^You slip/, /^You hang/, /^You strap/, /^You easily strap/ ].freeze
- SHEATHE_FOCUS_FAILURE_PATTERNS =
Patterns matched when failing to sheathe a spell focus.
[ /^Sheathe your .* where/, /^There's no room/ ].freeze
- STARLIGHT_MESSAGES =
Progression of Trader aura growth messages from lowest to highest starlight level. Used to determine aura level when perceiving aura.
[ 'The smallest hint of starlight flickers within your aura', 'A bare flicker of starlight plays within your aura', 'A faint amount of starlight illuminates your aura', 'Your aura pulses slowly with starlight', 'A steady pulse of starlight runs through your aura', 'Starlight dances vividly across the confines of your aura', 'Strong pulses of starlight flare within your aura', 'Your aura seethes with brilliant starlight', 'Your aura is blinding', 'The power contained in your aura' ].freeze
- CHARGE_LEVELS =
Patterns matched to determine a Warrior Mage's elemental charge level. Ranges from level 0 (no charge) to level 11 (maximum charge). Used by #check_elemental_charge to infer readiness for abilities like barrage.
[ /^You sense nothing out of the ordinary. Only magic could detect the useless trace of .* still in your system.$/, /^A small charge lingers within your body, just above the threshold of perception.$/, /^A small charge lingers within your body.$/, /^A charge dances through your body.$/, /^A charge dances just below the threshold of discomfort.$/, /^A charge circulates through your body, causing a low hum to vibrate through your bones.$/, /^Elemental essence floats freely within your body, leaving little untouched.$/, /^Elemental essence has infused every inch of your body. While you could contain more, you'd do so at the risk of your health.$/, /^Extraplanar power crackles within your body, leaving you feeling mildly feverish.$/, /^Extraplanar power crackles within your body, leaving you feeling acutely ill.$/, /^Your body sings and crackles with a barely contained charge, destroying what little cenesthesia you had left.$/, /^You have reached the limits of your body's capacity to store a charge. The laws of the Elemental Plane of .* scream demands upon your physiology, threatening your life.$/ ].freeze
- PERC_MANA_START_PATTERN =
Regex pattern that marks the start of "perc mana" output for Moon Mages. Matches lines containing mana stream descriptions.
/streams of .* mana/- PERC_MANA_END_PATTERN =
Regex pattern that marks the end of "perc mana" output. Matches the Roundtime line that terminates command output.
/Roundtime/- SYMBIOSIS_PATTERN =
Regex pattern that captures active symbiotic research type. Named capture group 'type' extracts the research school name.
/combine the weaves of the (?<type>\w+) symbiosis/- DISCERN_SORCERY_PATTERN =
Regex pattern that captures minimum mana streams for sorcery spells. Named capture group 'min' extracts the minimum stream count.
/requires at minimum (?<min>\d+) mana streams/- DISCERN_FULL_PATTERN =
Regex pattern that captures minimum and additional mana streams for spells. Named capture groups 'min' (base) and 'more' (reinforcement) extract stream counts. Used when discerning spell mana requirements.
/minimum (?<min>\d+) mana streams and you think you can reinforce it with (?<more>\d+) more/i- USELESS_RUNESTONE_PATTERNS =
Patterns matched when retrieving a useless runestone (exhausted charge).
[ /^You get a useless/ ].freeze
- GET_RUNESTONE_SUCCESS_PATTERNS =
Patterns matched when successfully retrieving a runestone from storage.
[ /^You get/, /^You pick up/ ].freeze
- GET_RUNESTONE_FAILURE_PATTERNS =
Patterns matched when failing to retrieve a runestone from storage.
[ /^What were you referring to/, /^I could not find/ ].freeze
Class Method Summary collapse
-
.activate_barb_buff?(name, meditation_pause_timer = 20, sit_to_meditate = false, retries: BARB_BUFF_MAX_RETRIES) ⇒ Boolean
Activates a Barbarian ability, with automatic retry on failure conditions.
-
.activate_khri?(settings_kneel, ability) ⇒ Boolean
Needs to handle (based on current usage): - Hasten - Delay Hasten - Hasten Focus - Delay Hasten Focus - Khri Hasten - Khri Delay Hasten - Khri Delay Hasten Focus.
-
.backfired? ⇒ Boolean
Returns whether the most recent spell cast backfired.
-
.calculate_mana(min, more, discern_data, cyclic_or_ritual, settings) ⇒ void
private
Calculates mana harness and cambrinth charge amounts from discern results.
-
.cast?(cast_command = 'cast', symbiosis = false, before = [], after = [], retries: CAST_MAX_RETRIES) ⇒ Boolean
Casts a prepared spell, handling failure modes, barrage fallback, and cyclic/prep wait.
-
.cast_spell(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ Boolean?
Casts a single spell from preparation through invoke and cast.
-
.cast_spell?(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ Boolean
Convenience wrapper that casts a single spell and returns a boolean result.
-
.cast_spells(spells, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ void
Casts a collection of spells, infusing OM first if configured.
-
.charge?(cambrinth, mana) ⇒ Boolean
private
Charges cambrinth with the specified mana amount.
-
.charge_and_invoke(cambrinth, dedicated_camb_use, charges, invoke_exact_amount = nil) ⇒ void
private
Charges cambrinth with each amount in sequence, then invokes it.
-
.charge_avtalia(cambrinth, charge_amount) ⇒ void
private
Charges Avtalia cambrinth if avtalia script is running.
-
.charge_cambrinth_items(data, settings) ⇒ void
private
Charges and invokes each cambrinth item in the configured list.
-
.check_discern(data, settings, spell_is_sorcery = false, more_override = nil) ⇒ Hash
Discerns a spell to determine mana and cambrinth requirements.
-
.check_elemental_charge ⇒ Object
Determine the numerical range of a Warrior Mage's elemental charge.
-
.check_to_harness(should_harness) ⇒ Boolean
private
Determines whether to use harnessing instead of cambrinth charging.
-
.choose_avtalia(charge_needed, mana_percentage) ⇒ Hash?
private
Selects the best Avtalia cambrinth by mana availability and freshness.
-
.crafting_cast_spell(data, settings) ⇒ Boolean
private
Casts a prepared spell during crafting, handling cambrinth or harnessing.
-
.crafting_magic_routine(settings) ⇒ void
private
Conducts spell-based training during crafting: casts queued spells if ready, then prepares low-XP training spells (Warding, Utility, Augmentation, optionally Sorcery).
-
.crafting_prepare_spell(data, settings) ⇒ String, ...
private
Prepares a spell during crafting, handling lunar/moon data and cyclic cleanup.
-
.do_buffs(settings, set_name) ⇒ void
Activates all buffs in a named waggle set.
-
.find_cambrinth(cambrinth, stored_cambrinth, cambrinth_cap) ⇒ Boolean, void
private
Ensures cambrinth is in hand (either held or worn) based on configuration and skill.
-
.find_charge_invoke_stow(cambrinth, stored_cambrinth, cambrinth_cap, dedicated_camb_use, charges, invoke_exact_amount = nil) ⇒ void
Wrapper that finds cambrinth, charges and invokes it, then stows it.
-
.find_focus(focus, worn, tied, sheathed) ⇒ void
Locates and retrieves a spell focus based on its storage location.
-
.get_runestone?(runestone, settings) ⇒ Boolean
private
Retrieves a runestone from configured storage or hands (if already held).
-
.harness?(mana) ⇒ Boolean
private
Harnesses the specified amount of mana and returns whether it succeeded.
-
.harness_mana(amounts) ⇒ void
Harnesses each amount of mana in sequence, stopping at the first failure.
-
.infuse_om(harness, amount) ⇒ void
Infuses mana into Osrel Meraud (OM) if it is active and below 90 percent.
-
.invoke(cambrinth, dedicated_camb_use, invoke_amount) ⇒ void
private
Invokes cambrinth, releasing stored mana.
-
.invoke_avtalia(cambrinth, dedicated_camb_use, invoke_amount) ⇒ void
private
Invokes Avtalia cambrinth if the avtalia script is running.
-
.kneel_for_khri?(kneel, ability) ⇒ Boolean
private
Determines whether to kneel before activating a specific khri ability.
-
.need_buffs?(buff_list) ⇒ Boolean
Checks whether any buffs in the list are missing or need recasting.
-
.normalize_cambrinth_items(settings) ⇒ void
private
Converts legacy single-cambrinth settings into the multi-item format.
-
.parse_mana_message(mana_msg) ⇒ Integer
private
Parses a mana perception message to extract and return the mana level as an integer (1-4).
-
.parse_regalia ⇒ Array<String>?
Parses worn combat regalia and returns nouns of crystal items found.
-
.perc_aura ⇒ Hash?
Perceives Trader aura and returns level, saturation, and growth status.
-
.perc_mana ⇒ Hash, ...
Perceives mana streams and returns level information.
-
.perc_symbiotic_research ⇒ Object
check which symbiotic research is active.
-
.prepare?(abbrev, mana, symbiosis = false, command = 'prepare', tattoo_tm = false, runestone_name = nil, runestone_tm = false, custom_prep = nil, retries: PREPARE_MAX_RETRIES) ⇒ String, false
Prepares a spell for casting, handling symbiosis setup and various failure modes.
-
.prepare_to_cast_runestone?(spell, settings) ⇒ Boolean
private
Checks if a runestone is available in storage and retrieves it.
-
.release_cyclics(cyclic_no_release = []) ⇒ void
Releases all active cyclic spells except those in the exclusion list.
-
.release_magical_research ⇒ Object
release symbiotic research.
-
.ritual(data, settings) ⇒ void
Performs a complete spell ritual: prepare, find focus, invoke, stow focus, and cast.
-
.segue?(abbrev, mana) ⇒ Boolean
private
Attempts to segue into a new cyclic spell from an active cyclic.
-
.shatter_regalia?(worn_regalia = nil) ⇒ Boolean
Shatters (removes) worn crystal regalia, converting them to motes.
-
.skilled_to_charge_while_worn?(cambrinth_cap) ⇒ Boolean
private
Determines if Arcana skill is high enough to charge cambrinth while wearing it.
-
.spell_prepared? ⇒ Boolean
Returns true if you're prepared to cast your spell.
-
.spell_preparing ⇒ Object
Returns name of the spell being prepared, or nil if not preparing one.
-
.spell_preparing? ⇒ Boolean
Returns true if preparing a spell, false otherwise.
-
.start_barb_abilities(abilities, settings) ⇒ void
Activates each Barbarian ability in the list.
-
.start_khris(khris, settings) ⇒ void
Activates each khri set in the list, kneeling if configured to do so.
-
.stow_cambrinth(cambrinth, stored_cambrinth, _cambrinth_cap) ⇒ Boolean, void
private
Returns cambrinth to its configured storage location (stowed or worn).
-
.stow_focus(focus, worn, tied, sheathed, retries: STOW_FOCUS_MAX_RETRIES) ⇒ Boolean, void
Stows a spell focus back to its configured location.
-
.update_avtalia ⇒ void
private
Updates Avtalia cambrinth focus state by sensing mana charge.
Class Method Details
.activate_barb_buff?(name, meditation_pause_timer = 20, sit_to_meditate = false, retries: BARB_BUFF_MAX_RETRIES) ⇒ Boolean
Activates a Barbarian ability, with automatic retry on failure conditions. Returns true if already active, or if successfully activated. Handles meditation pause timing and sitting requirement. Requires Power Meditation or Powermonger mastery for active abilities to be detected by DRSpells.
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 381 def (name, meditation_pause_timer = 20, sit_to_meditate = false, retries: BARB_BUFF_MAX_RETRIES) # Note, you must know Power meditation or Powermonger mastery # for your active abilities to be detected by DRSpells. return true if DRSpells.active_spells[name] if retries <= 0 Lich::Messaging.msg("bold", "DRCA: activate_barb_buff? exhausted #{BARB_BUFF_MAX_RETRIES} retries for '#{name}' - giving up") return false end activated = false ability_data = get_data('spells').[name] if ability_data['type'].eql?('meditation') && sit_to_meditate DRC.retreat DRC.bput('sit', 'You sit', 'You are already', 'You rise', 'While swimming?') end case DRC.bput(ability_data['start_command'], ability_data['activated_message'], 'You have not been trained', 'But you are already', 'Your inner fire lacks', 'find yourself lacking the inner fire', 'You should stand', 'You must be sitting', 'You must be unengaged', 'While swimming?') when 'You must be unengaged' DRC.retreat activated = (name, meditation_pause_timer, sit_to_meditate, retries: retries - 1) when 'You must be sitting' DRC.retreat case DRC.bput('sit', 'You sit', 'You are already', 'You rise', 'While swimming?') when 'While swimming?' Lich::Messaging.msg("bold", "DRCA: cannot sit to activate '#{name}' - water is too deep") activated = false else activated = (name, meditation_pause_timer, sit_to_meditate, retries: retries - 1) end when 'You should stand' DRC.fix_standing activated = (name, meditation_pause_timer, sit_to_meditate, retries: retries - 1) when /#{ability_data['activated_message']}/ # Pause at least for the preferred amount of time # to let the meditation take effect else it may fail. if ability_data['type'].eql?('meditation') && meditation_pause_timer pause meditation_pause_timer end # Wait for any remaining RT before proceeding waitrt? activated = true else activated = false end DRC.fix_standing activated end |
.activate_khri?(settings_kneel, ability) ⇒ Boolean
Needs to handle (based on current usage):
- Hasten
- Delay Hasten
- Hasten Focus
- Delay Hasten Focus
- Khri Hasten
- Khri Delay Hasten
- Khri Delay Hasten Focus
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 321 def activate_khri?(settings_kneel, ability) abilities = ability.split.map(&:capitalize) # Standardize for with/without 'Khri' on the front abilities = abilities.drop(1) if abilities.first.casecmp('khri') == 0 # Handling for 'Delay' should_delay = abilities.first.casecmp('delay') == 0 abilities = abilities.drop(1) if should_delay # Check each khri in the list against Active Spells, Drop any that are active needed_abilities = abilities.select { |ability_to_check| DRSpells.active_spells["Khri #{ability_to_check}"].nil? } return true if needed_abilities.empty? kneel = needed_abilities.any? { |ability_to_check| kneel_for_khri?(settings_kneel, ability_to_check) } DRC.retreat if kneel DRC.bput('kneel', 'You kneel', 'You are already', 'You rise', "While swimming? Don't be silly") if kneel && !kneeling? result = DRC.bput("Khri #{should_delay ? 'Delay ' : ''}#{needed_abilities.join(' ')}", get_data('spells').khri_preps) waitrt? DRC.fix_standing return ['Your mind and body are willing', 'Your body is willing', 'You have not recovered'].none?(result) end |
.backfired? ⇒ Boolean
Returns whether the most recent spell cast backfired.
619 620 621 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 619 def backfired? @backfired_status || false end |
.calculate_mana(min, more, discern_data, cyclic_or_ritual, settings) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Calculates mana harness and cambrinth charge amounts from discern results. Applies prep_scaling_factor, distributes remaining mana across cambrinth items proportionally, and handles cases where total > available cambrinth capacity.
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1241 def calculate_mana(min, more, discern_data, cyclic_or_ritual, settings) total = min + more total = (total * settings.prep_scaling_factor).floor discern_data['mana'] = [(total / 5.0).ceil, min].max remaining = total - discern_data['mana'] normalize_cambrinth_items(settings) # Ignore cambrinth if charges to use is nil or 0 settings.cambrinth_num_charges ||= 0 settings.cambrinth_items = [] if settings.cambrinth_num_charges == 0 total_cambrinth_cap = settings.cambrinth_items.map { |x| x['cap'] }.inject(&:+) || 0 charges_count_floor = remaining >= settings.cambrinth_num_charges ? settings.cambrinth_num_charges : 1 settings.cambrinth_items.each do |item| item['charges'] = ((item['cap'].to_f / total_cambrinth_cap) * charges_count_floor).ceil end total_cambrinth_charges = settings.cambrinth_items.map { |x| x['charges'] }.inject(&:+) || 0 if remaining > total_cambrinth_cap discern_data['mana'] = discern_data['mana'] + (remaining - total_cambrinth_cap) remaining = total - discern_data['mana'] end if cyclic_or_ritual || total_cambrinth_charges == 0 discern_data['cambrinth'] = nil discern_data['mana'] = discern_data['mana'] + remaining elsif remaining > 0 total_cambrinth_mana = [remaining, total_cambrinth_cap].min settings.cambrinth_items.each_with_index do |item, index| discern_data['cambrinth'] ||= [] charge_amount = (total_cambrinth_mana / total_cambrinth_charges) * item['charges'] discern_data['cambrinth'][index] = [] charge_amount.times do |i| discern_data['cambrinth'][index][i % item['charges']] += 1 end end else discern_data['cambrinth'] = nil end end |
.cast?(cast_command = 'cast', symbiosis = false, before = [], after = [], retries: CAST_MAX_RETRIES) ⇒ Boolean
Casts a prepared spell, handling failure modes, barrage fallback, and cyclic/prep wait. Sets up and clears flags for unknown commands, barrage failure, spell failure, and backfiring. Executes before/after action blocks. Retries on cyclic-too-recent or full-prep-required. Cleans up spell and mana on certain failures.
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 635 def cast?(cast_command = 'cast', symbiosis = false, before = [], after = [], retries: CAST_MAX_RETRIES) before.each { |action| DRC.bput(action['message'], action['matches']) } Flags.add('unknown-command', "Please rephrase that command") Flags.add('barrage-fail', "That was an invalid attack choice.", "Wouldn't it be better if you used a melee weapon?", "You'll need to be using a weapon to BARRAGE your target", "You must have a fully developed target matrix to make a barrage attack", "You are unable to muster the energy to do that", "You do not know how to manipulate that pathway.", "You cannot BARRAGE with that spell.") Flags.add('spell-fail', 'Currently lacking the skill to complete the pattern', "You don't have a spell prepared!", /^Your spell .*backfires/, 'Something is interfering with the spell', 'There is nothing else to face', 'You strain, but are too mentally fatigued', 'The spell pattern resists the influx of unfocused mana', 'Your target pattern dissipates because') Flags.add('cyclic-too-recent', 'The mental strain of initiating a cyclic spell so recently prevents you from formulating the spell pattern') Flags.add('spell-full-prep', /^This pattern may only be cast with full preparation/) Flags.add('spell-backfired', /^Your spell .*backfires/) case DRC.bput(cast_command || 'cast', get_data('spells').) when /^Your target pattern dissipates/, /^You can't cast that at yourself/, /^You need to specify a body part to consume/, /^There is nothing else to face/ DRC.bput('release spell', 'You let your concentration lapse', "You aren't preparing a spell") DRC.bput('release mana', 'You release all', "You aren't harnessing any mana") when /You gesture/ pause 0.25 end waitrt? # Warrior Mage failed to use (or doesn't know) barrage ability. Do regular cast instead. if cast_command =~ /\b(barrage)\b/i && (Flags['unknown-command'] || Flags['barrage-fail']) return cast?('cast', symbiosis, [], after, retries: retries - 1) if retries > 0 Lich::Messaging.msg("bold", "DRCA: cast? barrage fallback exhausted retries - giving up") return false end if Flags['cyclic-too-recent'] || Flags['spell-full-prep'] if retries <= 0 Lich::Messaging.msg("bold", "DRCA: cast? exhausted #{CAST_MAX_RETRIES} retries waiting for cyclic/full-prep - giving up") return false end pause 1 Flags.delete('spell-full-prep') return cast?(cast_command, symbiosis, [], after, retries: retries - 1) end after.each { |action| DRC.bput(action['message'], action['matches']) } if symbiosis && Flags['spell-fail'] DRC.bput('release mana', 'You release all', "You aren't harnessing any mana") DRC.bput('release symbiosis', 'You release', 'But you haven\'t prepared') elsif Flags['spell-fail'] DRC.bput('release mana', 'You release all', "You aren't harnessing any mana") end @backfired_status = Flags['spell-backfired'] !Flags['spell-fail'] end |
.cast_spell(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ Boolean?
Casts a single spell from preparation through invoke and cast. Handles astral data updates, Clear Vision prerequisite, rituals, runestones, segue casting, and lifecycle callbacks. Returns nil on early exit.
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1105 def cast_spell(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) return unless data return unless settings data = DRCMM.update_astral_data(data, settings) return unless data # DRCMM.update_astral_data returns nil on failure if (data['abbrev'] =~ /locat/i) && !DRSpells.active_spells['Clear Vision'] cast_spell({ 'abbrev' => 'cv', 'mana' => 1, 'prep_time' => 5 }, settings) end if data['ritual'] ritual(data, settings) return end if data['runestone_name'] return unless prepare_to_cast_runestone?(data, settings) end cast_lifecycle_lambda&.call('pre-prep', data, settings) command = 'prep' command = data['prep'] if data['prep'] command = data['prep_type'] if data['prep_type'] if command == 'segue' return if segue?(data['abbrev'], data['mana']) command = 'prep' end release_cyclics if data['cyclic'] DRC.bput('release spell', 'You let your concentration lapse', "You aren't preparing a spell") unless checkprep == 'None' DRC.bput('release mana', 'You release all', "You aren't harnessing any mana") return unless prepare?(data['abbrev'], data['mana'], data['symbiosis'], command, data['tattoo_tm'], data['runestone_name'], data['runestone_tm'], settings['custom_spell_prep']) DRCI.put_away_item?(data['runestone_name'], settings.runestone_storage) if DRCI.in_hands?(data['runestone_name']) prepare_time = Time.now normalize_cambrinth_items(settings) if check_to_harness(settings.use_harness_when_arcana_locked) && !force_cambrinth harness_mana(data['cambrinth'].flatten) else charge_cambrinth_items(data, settings) end cast_lifecycle_lambda&.call('post-prep', data, settings) if data['prep_time'] pause until Time.now - prepare_time >= data['prep_time'] else waitcastrt? end cast_lifecycle_lambda&.call('pre-cast', data, settings) spell_cast = cast?(data['cast'], data['symbiosis'], data['before'], data['after']) cast_lifecycle_lambda&.call('post-cast', data, settings) spell_cast end |
.cast_spell?(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ Boolean
Convenience wrapper that casts a single spell and returns a boolean result.
1091 1092 1093 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1091 def cast_spell?(data, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) !!cast_spell(data, settings, force_cambrinth, cast_lifecycle_lambda) end |
.cast_spells(spells, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) ⇒ void
This method returns an undefined value.
Casts a collection of spells, infusing OM first if configured. Skips spells that are already active (unless non-cyclic with nil recast). Waits on mana and concentration thresholds.
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1070 def cast_spells(spells, settings, force_cambrinth = false, cast_lifecycle_lambda = nil) infuse_om(!settings.osrel_no_harness, settings.osrel_amount) spells.each do |name, data| next if DRSpells.active_spells[name] && (data['recast'].nil? || DRSpells.active_spells[name].to_i > data['recast']) while DRStats.mana < settings.waggle_spells_mana_threshold || DRStats.concentration < settings.waggle_spells_concentration_threshold Lich::Messaging.msg("plain", "DRCA: waiting on mana over #{settings.waggle_spells_mana_threshold} or concentration over #{settings.waggle_spells_concentration_threshold}...") pause 15 end cast_spell(data, settings, force_cambrinth, cast_lifecycle_lambda) end end |
.charge?(cambrinth, mana) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Charges cambrinth with the specified mana amount. Handles worn/held cambrinth and skill checks. Falls back to harnessing if body condition prevents charging. Retries find_cambrinth if cambrinth is missing.
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 893 def charge?(cambrinth, mana) charged = false result = DRC.bput("charge my #{cambrinth} #{mana}", get_data('spells')., 'I could not find') pause waitrt? case result when /You are in no condition to do that/ charged = harness?(mana) when /You'll have to hold it/ # You're not wearing nor holding your cambrinth item, go find it again. # Likely it's configured in your yaml that you wear it but it's stowed for some reason. # Try to find the cambrinth and get it to your hands. Lich::Messaging.msg("bold", "DRCA: where did your cambrinth go?") retry_find_cambrinth = true when /you find it too clumsy/ Lich::Messaging.msg("bold", "DRCA: your arcana skill is too low to charge your cambrinth while worn") retry_find_cambrinth = true else charged = result =~ /absorbs? all of the energy/ end if retry_find_cambrinth # If the cambrinth is in your hands and you can't charge it, nothing else to do. unless DRCI.in_hands?(cambrinth) # Otherwise, try to find the cambrinth and get it to your hands. find_cambrinth(cambrinth, false, 999) # If you were able to get the cambrinth into a hand then retry charging it. # You might not have been able to if your hands were full. if DRCI.in_hands?(cambrinth) charged = charge?(cambrinth, mana) stow_cambrinth(cambrinth, false, 999) end end end charged end |
.charge_and_invoke(cambrinth, dedicated_camb_use, charges, invoke_exact_amount = nil) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Charges cambrinth with each amount in sequence, then invokes it. Returns early if charges is nil or empty.
841 842 843 844 845 846 847 848 849 850 851 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 841 def charge_and_invoke(cambrinth, dedicated_camb_use, charges, invoke_exact_amount = nil) return unless charges&.any? charges.each do |mana| break unless charge?(cambrinth, mana) end invoke_amount = invoke_exact_amount ? charges.inject(0, :+) : nil invoke(cambrinth, dedicated_camb_use, invoke_amount) end |
.charge_avtalia(cambrinth, charge_amount) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Charges Avtalia cambrinth if avtalia script is running. Updates tracking with charge success or assumed reserve (with 10% falloff per 5 minutes).
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1435 def charge_avtalia(cambrinth, charge_amount) return unless cambrinth return unless Script.running?('avtalia') if !charge?(cambrinth, charge_amount) UserVars.avtalia[cambrinth]['mana'] = UserVars.avtalia[cambrinth]['cap'] else # Experiments show very roughly 10% falloff regardless of cap every 10 minutes # Assume 10% every 5 minutes. No falloff in starlight, but that's not tracked ATM. time_diff = Time.now - UserVars.avtalia[cambrinth]['time_seen'] time_mod = (time_diff / 300.0).floor time_adjust = 1 - [time_mod * 0.10, 1.0].min assumed_reserve = (UserVars.avtalia[cambrinth]['mana'] * time_adjust).floor + charge_amount UserVars.avtalia[cambrinth]['mana'] = [assumed_reserve, UserVars.avtalia[cambrinth]['cap']].min end UserVars.avtalia[cambrinth]['time_seen'] = Time.now end |
.charge_cambrinth_items(data, settings) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Charges and invokes each cambrinth item in the configured list. Handles both array (per-item charges) and flat (shared charges) formats.
1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1516 def charge_cambrinth_items(data, settings) settings.cambrinth_items.each_with_index do |item, index| case data['cambrinth'].first when Array find_charge_invoke_stow(item['name'], item['stored'], item['cap'], settings.dedicated_camb_use, data['cambrinth'][index], settings.cambrinth_invoke_exact_amount) when Integer find_charge_invoke_stow(item['name'], item['stored'], item['cap'], settings.dedicated_camb_use, data['cambrinth'], settings.cambrinth_invoke_exact_amount) end end end |
.check_discern(data, settings, spell_is_sorcery = false, more_override = nil) ⇒ Hash
Discerns a spell to determine mana and cambrinth requirements. Caches results per spell abbreviation in UserVars.discerns. For sorcery or symbiosis, caches only min streams. For others, rechecks periodically or if overridden. Updates spell data with mana and cambrinth arrays.
1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1195 def check_discern(data, settings, spell_is_sorcery = false, more_override = nil) UserVars.discerns = {} unless UserVars.discerns discern_data = UserVars.discerns[data['abbrev']] || {} if data['symbiosis'] || spell_is_sorcery if discern_data.empty? || discern_data['min'].nil? || more_override DRC.retreat discern_result = DRC.bput("discern #{data['abbrev']}", 'requires at minimum \d+ mana streams') match = discern_result.match(DISCERN_SORCERY_PATTERN) if match discern_data['mana'] = match[:min].to_i discern_data['cambrinth'] = nil discern_data['min'] = match[:min].to_i discern_data['more'] = (more_override || 0) end end calculate_mana(discern_data['min'], discern_data['more'], discern_data, false, settings) elsif discern_data.empty? || discern_data['time_stamp'].nil? || Time.now - discern_data['time_stamp'] > settings.check_discern_timer_in_hours * 60 * 60 || !discern_data['more'].nil? discern_data['time_stamp'] = Time.now DRC.retreat case discern = DRC.bput("discern #{data['abbrev']}", 'The spell requires at minimum \d+ mana streams and you think you can reinforce it with \d+ more', 'You don\'t think you are able to cast this spell', 'You have no idea how to cast that spell', 'You don\'t seem to be able to move to do that') when /you don't think you are able/i, 'You have no idea how to cast that spell', 'You don\'t seem to be able to move to do that' discern_data['mana'] = 1 discern_data['cambrinth'] = nil else match = discern.match(DISCERN_FULL_PATTERN) calculate_mana(match[:min].to_i, match[:more].to_i, discern_data, data['cyclic'] || data['ritual'], settings) if match end end waitrt? UserVars.discerns[data['abbrev']] = discern_data data['mana'] = discern_data['mana'] data['cambrinth'] = discern_data['cambrinth'] data end |
.check_elemental_charge ⇒ Object
Determine the numerical range of a Warrior Mage's elemental charge. This can be used to know if the mage is ready to perform certain abilities, like barrage. Returns a number between 0 (no charge) and 11 (max charge). https://elanthipedia.play.net/Summoning_skill#Charge_levels
1473 1474 1475 1476 1477 1478 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1473 def check_elemental_charge return 0 unless DRStats.warrior_mage? result = DRC.bput("pathway sense", *CHARGE_LEVELS) CHARGE_LEVELS.find_index { |pattern| pattern =~ result } end |
.check_to_harness(should_harness) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Determines whether to use harnessing instead of cambrinth charging. Returns true only if harnessing is enabled and Attunement XP <= Arcana XP.
1284 1285 1286 1287 1288 1289 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1284 def check_to_harness(should_harness) return false unless should_harness return false if DRSkill.getxp('Attunement') > DRSkill.getxp('Arcana') true end |
.choose_avtalia(charge_needed, mana_percentage) ⇒ Hash?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Selects the best Avtalia cambrinth by mana availability and freshness. Filters for items with time_seen within 10 minutes, mana >= mana_percentage, and mana > charge_needed / 10.
1461 1462 1463 1464 1465 1466 1467 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1461 def choose_avtalia(charge_needed, mana_percentage) UserVars.avtalia.select { |_camb, data| data['time_seen'] && data['cap'] && data['mana'] } .select { |_camb, data| Time.now - data['time_seen'] < 600.0 } .select { |_camb, data| (data['mana'].to_f / data['cap'].to_f) * 100 >= mana_percentage } .select { |_camb, data| data['mana'] > charge_needed / 10 } .max_by { |_camb, data| data['mana'] } end |
.crafting_cast_spell(data, settings) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Casts a prepared spell during crafting, handling cambrinth or harnessing. Does not handle preparation; assume spell is already prepared.
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1298 def crafting_cast_spell(data, settings) return unless data return unless settings normalize_cambrinth_items(settings) if check_to_harness(settings.use_harness_when_arcana_locked) harness_mana(data['cambrinth'].flatten) else charge_cambrinth_items(data, settings) end cast?(data['cast'], data['symbiosis'], data['before'], data['after']) end |
.crafting_magic_routine(settings) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Conducts spell-based training during crafting: casts queued spells if ready, then prepares low-XP training spells (Warding, Utility, Augmentation, optionally Sorcery). Returns early if no training spells, low mana, or casting in progress.
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1344 def crafting_magic_routine(settings) training_spells = settings.crafting_training_spells return if training_spells.empty? return if DRStats.mana <= settings.waggle_spells_mana_threshold if checkcastrt > 0 return elsif !XMLData.prepared_spell.eql?('None') && checkcastrt == 0 spell = XMLData.prepared_spell data = training_spells.find { |_skill, info| info['name'] == spell }.last crafting_cast_spell(data, settings) end return if checkcastrt > 0 needs_training = %w[Warding Utility Augmentation] needs_training.append("Sorcery") if (settings.crafting_training_spells_enable_sorcery && !Script.running?('forge')) || (settings.crafting_training_spells_enable_sorcery && settings.crafting_training_spells_enable_sorcery_forging) needs_training = needs_training.select { |skill| training_spells[skill] } .select { |skill| DRSkill.getxp(skill) < 31 } .sort_by { |skill| [DRSkill.getxp(skill), DRSkill.getrank(skill)] } .first return unless needs_training crafting_prepare_spell(training_spells[needs_training], settings) end |
.crafting_prepare_spell(data, settings) ⇒ String, ...
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Prepares a spell during crafting, handling lunar/moon data and cyclic cleanup. Does not handle casting.
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1319 def crafting_prepare_spell(data, settings) return unless data return unless settings # Skip preparing lunar spell if no moons available return unless DRCMM.set_moon_data(data) release_cyclics if data['cyclic'] DRC.bput('release spell', 'You let your concentration lapse', "You aren't preparing a spell") unless checkprep == 'None' DRC.bput('release mana', 'You release all', "You aren't harnessing any mana") command = 'prep' command = data['prep'] if data['prep'] command = data['prep_type'] if data['prep_type'] prepare?(data['abbrev'], data['mana'], data['symbiosis'], command, data['tattoo_tm'], data['runestone_name'], data['runestone_tm'], settings['custom_spell_prep']) end |
.do_buffs(settings, set_name) ⇒ void
This method returns an undefined value.
Activates all buffs in a named waggle set. For Barbarians, activates abilities; for Thieves, activates khris; for other guilds, filters by day/night and casts spells.
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1381 def do_buffs(settings, set_name) return unless settings.waggle_sets[set_name] spells = settings.waggle_sets[set_name] if DRStats. (spells, settings) elsif DRStats.thief? start_khris(spells, settings) else spells .select! { |_name, data| data['night'] ? UserVars.sun['night'] : true } .select! { |_name, data| data['day'] ? UserVars.sun['day'] : true } spells.values .select { |spell| spell['use_auto_mana'] } .each { |spell| check_discern(spell, settings) } cast_spells(spells, settings, settings.waggle_force_cambrinth) end end |
.find_cambrinth(cambrinth, stored_cambrinth, cambrinth_cap) ⇒ Boolean, void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Ensures cambrinth is in hand (either held or worn) based on configuration and skill. If kept stowed, retrieves it. If not skilled to charge while worn, removes from wear or retrieves. Otherwise assumes it is being worn without verification.
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 773 def find_cambrinth(cambrinth, stored_cambrinth, cambrinth_cap) if stored_cambrinth # Your config says you keep your cambrinth stowed. # If item not in your hands, maybe you're wearing it by accident? DRCI.get_item_if_not_held?(cambrinth) || DRCI.remove_item?(cambrinth) elsif !skilled_to_charge_while_worn?(cambrinth_cap) # Your config says you wear your cambrinth. # But you're not skilled to charge it while worn. # If item not in your hands, maybe you're wearing it or stowed it by accident? DRCI.in_hands?(cambrinth) || DRCI.remove_item?(cambrinth) || DRCI.get_item?(cambrinth) else # Your config says you wear your cambrinth # and you're skilled to charge it while worn. # Let's hope you're wearing or holding it :) # To verify that would require more commands # and more time, and be more spammy. # For now, no validation or recovery for this scenario. true end end |
.find_charge_invoke_stow(cambrinth, stored_cambrinth, cambrinth_cap, dedicated_camb_use, charges, invoke_exact_amount = nil) ⇒ void
This method returns an undefined value.
Wrapper that finds cambrinth, charges and invokes it, then stows it. Returns early if charges are nil or empty.
697 698 699 700 701 702 703 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 697 def find_charge_invoke_stow(cambrinth, stored_cambrinth, cambrinth_cap, dedicated_camb_use, charges, invoke_exact_amount = nil) return unless charges find_cambrinth(cambrinth, stored_cambrinth, cambrinth_cap) charge_and_invoke(cambrinth, dedicated_camb_use, charges, invoke_exact_amount) stow_cambrinth(cambrinth, stored_cambrinth, cambrinth_cap) end |
.find_focus(focus, worn, tied, sheathed) ⇒ void
This method returns an undefined value.
Locates and retrieves a spell focus based on its storage location. Does nothing if focus is nil.
714 715 716 717 718 719 720 721 722 723 724 725 726 727 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 714 def find_focus(focus, worn, tied, sheathed) return unless focus if worn DRCI.remove_item?(focus) elsif tied DRCI.untie_item?(focus, tied) elsif sheathed result = DRC.bput("wield my #{focus}", WIELD_FOCUS_SUCCESS_PATTERNS, WIELD_FOCUS_FAILURE_PATTERNS) WIELD_FOCUS_FAILURE_PATTERNS.none? { |pattern| pattern =~ result } else DRCI.get_item?(focus) end end |
.get_runestone?(runestone, settings) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Retrieves a runestone from configured storage or hands (if already held). Returns false and disposes a useless (exhausted) runestone if found.
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 597 def get_runestone?(runestone, settings) return true if DRCI.in_hands?(runestone) result = DRC.bput( "get my #{runestone} from my #{settings.runestone_storage}", USELESS_RUNESTONE_PATTERNS, GET_RUNESTONE_SUCCESS_PATTERNS, GET_RUNESTONE_FAILURE_PATTERNS ) if USELESS_RUNESTONE_PATTERNS.any? { |pat| pat.match?(result) } DRCI.dispose_trash(runestone) Lich::Messaging.msg("bold", "DRCA: got a useless #{runestone} - disposing and giving up") return false elsif GET_RUNESTONE_FAILURE_PATTERNS.any? { |pat| pat.match?(result) } Lich::Messaging.msg("bold", "DRCA: could not find #{runestone} in #{settings.runestone_storage}") return false end true end |
.harness?(mana) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Harnesses the specified amount of mana and returns whether it succeeded.
282 283 284 285 286 287 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 282 def harness?(mana) result = DRC.bput("harness #{mana}", 'You tap into', 'Strain though you may') pause 0.5 waitrt? return result =~ /You tap into/ end |
.harness_mana(amounts) ⇒ void
This method returns an undefined value.
Harnesses each amount of mana in sequence, stopping at the first failure.
294 295 296 297 298 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 294 def harness_mana(amounts) amounts.each do |mana| break unless harness?(mana) end end |
.infuse_om(harness, amount) ⇒ void
This method returns an undefined value.
Infuses mana into Osrel Meraud (OM) if it is active and below 90 percent. Harnesses mana beforehand if requested. Retries up to INFUSE_OM_MAX_RETRIES times before giving up.
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 256 def infuse_om(harness, amount) return unless DRSpells.active_spells['Osrel Meraud'] && DRSpells.active_spells['Osrel Meraud'] < 90 return unless amount retries = 0 loop do if retries >= INFUSE_OM_MAX_RETRIES Lich::Messaging.msg("bold", "DRCA: infuse_om exhausted #{INFUSE_OM_MAX_RETRIES} retries - giving up") break end retries += 1 pause 5 while DRStats.mana <= 40 harness_mana([amount]) if harness break if INFUSE_OM_SUCCESS_PATTERNS.include?(DRC.bput("infuse om #{amount}", INFUSE_OM_SUCCESS_PATTERNS, INFUSE_OM_FAILURE_PATTERNS)) pause 0.5 waitrt? end end |
.invoke(cambrinth, dedicated_camb_use, invoke_amount) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Invokes cambrinth, releasing stored mana. Returns early if cambrinth is nil. If invoke fails due to low Arcana ("too clumsy"), attempts to move cambrinth to hand and retry. Logs a warning if Arcana is too low to invoke while worn.
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 862 def invoke(cambrinth, dedicated_camb_use, invoke_amount) return unless cambrinth result = DRC.bput("invoke my #{cambrinth} #{invoke_amount} #{dedicated_camb_use}".strip, get_data('spells')., 'Invoke what?') pause waitrt? case result when /you find it too clumsy/ Lich::Messaging.msg("bold", "DRCA: your arcana skill is too low to invoke your cambrinth while worn") # If the cambrinth is in your hands and you can't invoke it, nothing else to do. unless DRCI.in_hands?(cambrinth) # Otherwise, try to find the cambrinth and get it to your hands. find_cambrinth(cambrinth, false, 999) # If you were able to get the cambrinth into a hand then retry invoking it. # You might not have been able to if your hands were full. if DRCI.in_hands?(cambrinth) invoke(cambrinth, dedicated_camb_use, invoke_amount) stow_cambrinth(cambrinth, false, 999) end end end end |
.invoke_avtalia(cambrinth, dedicated_camb_use, invoke_amount) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Invokes Avtalia cambrinth if the avtalia script is running. Updates UserVars.avtalia mana tracking.
1420 1421 1422 1423 1424 1425 1426 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1420 def invoke_avtalia(cambrinth, dedicated_camb_use, invoke_amount) return unless cambrinth return unless Script.running?('avtalia') invoke(cambrinth, dedicated_camb_use, invoke_amount) UserVars.avtalia[cambrinth]['mana'] -= [DRStats.mana, invoke_amount].min end |
.kneel_for_khri?(kneel, ability) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Determines whether to kneel before activating a specific khri ability.
352 353 354 355 356 357 358 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 352 def kneel_for_khri?(kneel, ability) if kneel.is_a? Array kneel.map(&:downcase).include? ability.downcase.sub('khri ', '') else kneel end end |
.need_buffs?(buff_list) ⇒ Boolean
Checks whether any buffs in the list are missing or need recasting. Behavior varies by guild: Barbarians check ability names directly; Thieves extract khri names and check by "Khri name"; other guilds check duration against recast timer.
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 437 def need_buffs?(buff_list) # no need to iterate if list of buffs is already empty return false if buff_list.nil? || buff_list.size == 0 # commoner's don't really have a way to check buffs so assume always yes return true if DRStats.guild == "Commoner" # no need to iterate if no buffs active and buff_list is not empty return true if DRSpells.active_spells.empty? case DRStats.guild when 'Barbarian' # barbarian buffs are an array of strings so we can just iterate over it and check if any are not in the active spells hash buff_list.each { |buff| return true if !DRSpells.active_spells.key?("#{buff}") } when 'Thief' # thieves need special handling to convert buff_list to an array of JUST khri names due to the different options supported buff_list.map { |buff| buff.sub(/khri /i, '') } .map { |buff| buff.sub(/delay /i, '') } .join(' ') .split(' ') .each { |khri| return true if !DRSpells.active_spells.key?("Khri #{khri}") } else # for MUs check list of required buffs against list of active spells and their durations/recast buff_list.each do |spell, data| # ignore spells which don't recast (ignite, etf, etc.) but not cyclics next if data['recast'] < 0 && !data['cyclic'] # if any buff is not in the active spells, or whose duration is less than recast, need to buff return true if !DRSpells.active_spells.key?(spell) || DRSpells.active_spells[spell] <= (data['recast'] ? data['recast'] : 1) end end # all buffs were in active spells with longer durations than recast, no need to buff return false end |
.normalize_cambrinth_items(settings) ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Converts legacy single-cambrinth settings into the multi-item format. If settings.cambrinth_items has no 'name' key, wraps legacy fields into a single-item array.
1499 1500 1501 1502 1503 1504 1505 1506 1507 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1499 def normalize_cambrinth_items(settings) return if settings.cambrinth_items[0]['name'] settings.cambrinth_items = [{ 'name' => settings.cambrinth, 'cap' => settings.cambrinth_cap, 'stored' => settings.stored_cambrinth }] end |
.parse_mana_message(mana_msg) ⇒ Integer
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parses a mana perception message to extract and return the mana level as an integer (1-4). Uses the global $MANA_MAP to categorize weakness, development, improvement, or goodness.
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 983 def (mana_msg) manalevels = if mana_msg.include? 'weak' $MANA_MAP['weak'] elsif mana_msg.include? 'developing' $MANA_MAP['developing'] elsif mana_msg.include? 'improving' $MANA_MAP['improving'] else $MANA_MAP['good'] end adj = mana_msg.split(' ')[-1] manalevels.index(adj).to_i + 1 end |
.parse_regalia ⇒ Array<String>?
Parses worn combat regalia and returns nouns of crystal items found. Returns nil if not a Trader.
949 950 951 952 953 954 955 956 957 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 949 def parse_regalia return unless DRStats.trader? snapshot = Lich::Util.issue_command("inv combat", /All of your worn combat|You aren't wearing anything like that/, /Use INVENTORY HELP for more options/, usexml: false, include_end: false) .map(&:strip) regalia_items = snapshot - ["All of your worn combat equipment:", "You aren't wearing anything like that."] regalia_items.select { |item| item.include?('rough-cut crystal') || item.include?('faceted crystal') || item.include?('resplendent crystal') } .map { |item| DRC.get_noun(item) } end |
.perc_aura ⇒ Hash?
Perceives Trader aura and returns level, saturation, and growth status. Returns nil if not a Trader.
1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1043 def perc_aura return unless DRStats.trader? Flags.add('aura-level', Regexp.union(STARLIGHT_MESSAGES)) Flags.add('aura-capped?', 'Your aura contains as much starlight as you can safely handle') Flags.add('aura-growing?', 'Local conditions permit optimal growth of your aura', 'Local conditions are hindering the growth of your aura') aura = {} DRC.bput('perceive aura', 'Roundtime') aura['level'] = Flags['aura-level'] ? STARLIGHT_MESSAGES.index(Flags['aura-level'][0]) : 0 aura['capped'] = Flags['aura-capped?'] ? true : false aura['growing'] = Flags['aura-growing?'] ? true : false Flags.delete('aura-level') Flags.delete('aura-capped?') Flags.delete('aura-growing?') aura end |
.perc_mana ⇒ Hash, ...
Perceives mana streams and returns level information. For Moon Mages, returns a hash with mana levels for each school. For other guilds, returns a single integer (1–4). Returns nil for Barbarians, Thieves, Traders, Commoners, and on command failure.
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1006 def perc_mana return nil if DRStats. || DRStats.thief? || DRStats.trader? || DRStats.commoner? if DRStats.moon_mage? lines = Lich::Util.issue_command( 'perc mana', PERC_MANA_START_PATTERN, PERC_MANA_END_PATTERN, usexml: false, include_end: false, quiet: true, timeout: 5 ) return nil if lines.nil? mana_msgs = lines.map(&:strip).select { |line| line.include?('streams') }[0..3] return nil if mana_msgs.length < 4 mana_msgs.collect! { |mana_msg| mana_msg.split(' streams')[0] } { 'enlightened_geometry' => (mana_msgs[0]), 'moonlight_manipulation' => (mana_msgs[1]), 'perception' => (mana_msgs[2]), 'psychic_projection' => (mana_msgs[3]) } else mana_msg = DRC.bput('perc', '^You reach out with your .* and (see|hear) \w+') (mana_msg) end end |
.perc_symbiotic_research ⇒ Object
check which symbiotic research is active
1481 1482 1483 1484 1485 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1481 def perc_symbiotic_research result = DRC.bput('perceive', SYMBIOSIS_PATTERN, /Roundtime/) match = result.match(SYMBIOSIS_PATTERN) match ? match[:type] : nil end |
.prepare?(abbrev, mana, symbiosis = false, command = 'prepare', tattoo_tm = false, runestone_name = nil, runestone_tm = false, custom_prep = nil, retries: PREPARE_MAX_RETRIES) ⇒ String, false
Prepares a spell for casting, handling symbiosis setup and various failure modes. Retries on false preparation (mind and body unwilling) up to PREPARE_MAX_RETRIES times.
486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 486 def prepare?(abbrev, mana, symbiosis = false, command = 'prepare', tattoo_tm = false, runestone_name = nil, runestone_tm = false, custom_prep = nil, retries: PREPARE_MAX_RETRIES) return false unless abbrev = !custom_prep ? get_data('spells'). : (get_data('spells'). + [custom_prep]) DRC.bput('prepare symbiosis', 'You recall the exact details of the', 'But you\'ve already prepared', 'Please don\'t do that here') if symbiosis if runestone_name.nil? match = DRC.bput("#{command} #{abbrev} #{mana}", ) else match = DRC.bput("#{command} my #{runestone_name}", get_data('spells').) end case match when 'Your desire to prepare this offensive spell suddenly slips away' if retries <= 0 Lich::Messaging.msg("bold", "DRCA: prepare? exhausted #{PREPARE_MAX_RETRIES} retries for '#{abbrev}' - giving up") return false end pause 1 return prepare?(abbrev, mana, symbiosis, command, tattoo_tm, runestone_name, runestone_tm, custom_prep, retries: retries - 1) when 'Something in the area interferes with your spell preparations', 'You shouldn\'t disrupt the area right now', 'You have no idea how to cast that spell', 'You have yet to receive any training in the magical arts', 'Please don\'t do that here', 'You cannot use the tattoo while maintaining the effort to stay hidden' DRC.bput('release symbiosis', 'You release the', 'But you haven\'t') if symbiosis return false when 'Well, that was fun' DRCI.dispose_trash(runestone_name) return false when 'You\'ll have to hold it' return false end DRC.bput("target", ) if tattoo_tm || runestone_tm match end |
.prepare_to_cast_runestone?(spell, settings) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Checks if a runestone is available in storage and retrieves it. Returns false if the runestone is out of stock or retrieval fails.
580 581 582 583 584 585 586 587 588 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 580 def prepare_to_cast_runestone?(spell, settings) if DRCI.inside?("#{spell['runestone_name']}", settings.runestone_storage) return false unless get_runestone?(spell['runestone_name'], settings) else Lich::Messaging.msg("bold", "DRCA: out of #{spell['runestone_name']}!") return false end true end |
.release_cyclics(cyclic_no_release = []) ⇒ void
This method returns an undefined value.
Releases all active cyclic spells except those in the exclusion list.
934 935 936 937 938 939 940 941 942 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 934 def release_cyclics(cyclic_no_release = []) get_data('spells') .spell_data .select { |_name, properties| properties['cyclic'] } .select { |name, _properties| DRSpells.active_spells.keys.include?(name) } .reject { |name| cyclic_no_release.include?(name) } .map { |_name, properties| properties['abbrev'] } .each { |abbrev| DRC.bput("release #{abbrev}", CYCLIC_RELEASE_SUCCESS_PATTERNS, 'Release what?') } end |
.release_magical_research ⇒ Object
release symbiotic research
1488 1489 1490 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1488 def release_magical_research 2.times { DRC.bput("release symbiosis", "Are you sure", "You intentionally wipe", "But you haven't") } end |
.ritual(data, settings) ⇒ void
This method returns an undefined value.
Performs a complete spell ritual: prepare, find focus, invoke, stow focus, and cast. Handles positioning, stance, and visibility. Does not cast if preparation fails.
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 544 def ritual(data, settings) DRC.retreat(settings.ignored_npcs) unless data['skip_retreat'] DRC.release_invisibility DRC.set_stance('shield') unless data['skip_retreat'] command = 'prepare' command = data['prep'] if data['prep'] command = data['prep_type'] if data['prep_type'] return unless prepare?(data['abbrev'], data['mana'], data['symbiosis'], command, data['tattoo_tm'], data['runestone_name'], data['runestone_tm'], settings['custom_spell_prep']) prepare_time = Time.now find_focus(data['focus'], data['worn_focus'], data['tied_focus'], data['sheathed_focus']) invoke(data['focus'], nil, nil) stow_focus(data['focus'], data['worn_focus'], data['tied_focus'], data['sheathed_focus']) DRC.retreat(settings.ignored_npcs) unless data['skip_retreat'] if data['prep_time'] pause until Time.now - prepare_time >= data['prep_time'] else waitcastrt? end return unless cast?(data['cast'], data['symbiosis'], data['before'], data['after']) DRC.retreat(settings.ignored_npcs) unless data['skip_retreat'] end |
.segue?(abbrev, mana) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Attempts to segue into a new cyclic spell from an active cyclic. Returns false on failure conditions: not performing a cyclic, too soon to segue, or lacking bardic flair.
1176 1177 1178 1179 1180 1181 1182 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1176 def segue?(abbrev, mana) case DRC.bput("segue #{abbrev} #{mana}", get_data('spells').) when 'You must be performing a cyclic spell to segue from', 'It is too soon to segue', 'You are lacking the bardic flair' return false end true end |
.shatter_regalia?(worn_regalia = nil) ⇒ Boolean
Shatters (removes) worn crystal regalia, converting them to motes. Parses regalia if not provided. Returns false if not a Trader or regalia is empty.
965 966 967 968 969 970 971 972 973 974 975 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 965 def shatter_regalia?(worn_regalia = nil) return false unless DRStats.trader? worn_regalia ||= parse_regalia return false if worn_regalia.empty? worn_regalia.each do |item| DRC.bput("remove my #{item}", 'into motes of silvery', 'Remove what?', "You .*#{item}") end true end |
.skilled_to_charge_while_worn?(cambrinth_cap) ⇒ Boolean
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Determines if Arcana skill is high enough to charge cambrinth while wearing it. Requires Arcana rank >= (capacity * 2) + 100.
828 829 830 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 828 def skilled_to_charge_while_worn?(cambrinth_cap) DRSkill.getrank('Arcana').to_i >= ((cambrinth_cap.to_i * 2) + 100) end |
.spell_prepared? ⇒ Boolean
Returns true if you're prepared to cast your spell. Infers this if you're preparing a spell and there's no more prep time to wait.
526 527 528 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 526 def spell_prepared? spell_preparing? && checkcastrt <= 0 end |
.spell_preparing ⇒ Object
Returns name of the spell being prepared, or nil if not preparing one.
531 532 533 534 535 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 531 def spell_preparing name = XMLData.prepared_spell name = nil if name.empty? || name.eql?('None') name end |
.spell_preparing? ⇒ Boolean
Returns true if preparing a spell, false otherwise.
520 521 522 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 520 def spell_preparing? !spell_preparing.nil? end |
.start_barb_abilities(abilities, settings) ⇒ void
This method returns an undefined value.
Activates each Barbarian ability in the list.
366 367 368 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 366 def (abilities, settings) abilities.each { |name| (name, settings.meditation_pause_timer, settings.sit_to_meditate) } end |
.start_khris(khris, settings) ⇒ void
This method returns an undefined value.
Activates each khri set in the list, kneeling if configured to do so.
306 307 308 309 310 311 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 306 def start_khris(khris, settings) khris .each do |khri_set| activate_khri?(settings.kneel_khri, khri_set) end end |
.stow_cambrinth(cambrinth, stored_cambrinth, _cambrinth_cap) ⇒ Boolean, void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns cambrinth to its configured storage location (stowed or worn). Handles cases where it is in hand or worn unexpectedly.
802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 802 def stow_cambrinth(cambrinth, stored_cambrinth, _cambrinth_cap) if stored_cambrinth # Your config says you keep your cambrinth stowed. # If item not in your hands and not stowed, maybe you're wearing it by accident? DRCI.get_item_if_not_held?(cambrinth) || DRCI.remove_item?(cambrinth) DRCI.stow_item?(cambrinth) elsif DRCI.in_hands?(cambrinth) # Your config says you wear your cambrinth. # For some reason it's currently in your hands. # If can't wear item for some reason then stow it. DRCI.wear_item?(cambrinth) || DRCI.stow_item?(cambrinth) else # Your config says you wear your cambrinth # and you're not currently holding it so # we'll assume you're wearing it. # No further action needed. true end end |
.stow_focus(focus, worn, tied, sheathed, retries: STOW_FOCUS_MAX_RETRIES) ⇒ Boolean, void
Stows a spell focus back to its configured location. Retries tie attempts up to STOW_FOCUS_MAX_RETRIES times with retreat. Does nothing if focus is nil.
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 740 def stow_focus(focus, worn, tied, sheathed, retries: STOW_FOCUS_MAX_RETRIES) return unless focus if worn DRCI.wear_item?(focus) elsif tied result = DRCI.tie_item?(focus, tied) unless result if retries <= 0 Lich::Messaging.msg("bold", "DRCA: stow_focus exhausted #{STOW_FOCUS_MAX_RETRIES} retries tying #{focus} - giving up") return false end DRC.retreat return stow_focus(focus, worn, tied, sheathed, retries: retries - 1) end result elsif sheathed result = DRC.bput("sheathe my #{focus}", SHEATHE_FOCUS_SUCCESS_PATTERNS, SHEATHE_FOCUS_FAILURE_PATTERNS) SHEATHE_FOCUS_FAILURE_PATTERNS.none? { |pattern| pattern =~ result } else DRCI.stow_item?(focus) end end |
.update_avtalia ⇒ void
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
This method returns an undefined value.
Updates Avtalia cambrinth focus state by sensing mana charge.
1407 1408 1409 1410 |
# File 'documented/dragonrealms/commons/common-arcana.rb', line 1407 def update_avtalia DRC.bput("focus cambrinth", /^The .+ pulses? .+ (\d+)/, 'dim, almost magically null', '^You let your magical senses wander') waitrt? end |