Class: Lich::DragonRealms::EquipmentManager
- Inherits:
-
Object
- Object
- Lich::DragonRealms::EquipmentManager
- Defined in:
- documented/dragonrealms/commons/equipmanager.rb
Overview
Manages character equipment sets and gear swapping.
Handles wearing, removing, wielding, and tracking gear based on user configuration. Maintains state about equipment sets and provides methods for combat gear rotation.
Constant Summary collapse
- STOW_RECOVERY_PATTERNS =
Recovery patterns handled by stow_helper's retry logic. These are automatically appended to every stow_helper call so callers only need to pass success/failure patterns.
[ /unload/, /close the fan/, /You are a little too busy/, /You don't seem to be able to move/, /is too small to hold that/, /Your wounds hinder your ability to do that/, /Sheath your .* where/ ].freeze
- STOW_HELPER_MAX_RETRIES =
Maximum retry attempts for stow_helper before giving up.
10- UNTIE_EXHAUSTED_PATTERNS =
Non-recoverable untie failure patterns that should return false immediately in #get_item_helper. Contains every entry from DRCI::UNTIE_ITEM_FAILURE_PATTERNS EXCEPT the "too busy" patterns which are recoverable (retreat / stop playing) and live in the
:failuresarray instead.For
:wornand +:stowed+/+:transform+, exhausted is set directly to the full DRCI failure constant because their:failuresentries don't overlap.:tiedis the exception -- "too busy" appears in both DRCI failures and the recoverable:failuresarray, so this curated subset excludes them to prevent the exhausted branch from swallowing recovery.If a new pattern is added to DRCI::UNTIE_ITEM_FAILURE_PATTERNS, it must be categorized here or in
:failures-- the coverage spec enforces that no DRCI failure falls through to the timeout branch. [ /^You don't seem to be able to move/, /^You fumble with the ties/, /^Untie what/, /^What were you referring/ ].freeze
Instance Method Summary collapse
-
#desc_to_items(descs) ⇒ Array<DRC::Item>
Converts an array of description strings to matching DRC::Item objects.
-
#empty_hands ⇒ void
Empties both hands by returning held gear or falling back to DRCI.stow_hands.
-
#get_combat_items ⇒ Array<String>
private
Retrieves the list of currently worn combat equipment via the INV COMBAT command.
-
#get_item?(item) ⇒ Boolean
Retrieves an item from wherever it is stored (worn, tied, sheathed, container, or stowed).
-
#get_item_helper(item, type) ⇒ Boolean
private
Attempts to retrieve an item using the verb configuration for the given type.
-
#initialize(settings = nil) ⇒ EquipmentManager
constructor
Creates a new EquipmentManager and loads gear configuration.
-
#item_by_desc(description) ⇒ DRC::Item?
Finds a gear item matching the given description.
-
#item_noun_in_hands?(noun) ⇒ Boolean
private
Checks whether the given noun is in either hand via GameObj XML feed.
-
#items(settings = nil) ⇒ Array<DRC::Item>
Returns the list of gear items, loading from settings on first call.
-
#listed_item?(desc) ⇒ DRC::Item?
(also: #is_listed_item?)
Checks whether a description matches a configured gear item.
-
#matching_combat_items(list) ⇒ Array<DRC::Item>
(also: #worn_items)
Returns the subset of currently worn combat items that match the given description list.
-
#notify_missing(lost_items) ⇒ void
private
Alerts the user about equipment items that could not be found.
-
#remove_gear_by {|DRC::Item| ... } ⇒ Array<DRC::Item>
Removes currently worn combat items that match the given block condition.
-
#remove_item(item, retries: 2) ⇒ Boolean?
Removes an item from the character and stows it in its configured location.
-
#remove_unmatched_items(combat_items, target_items) ⇒ void
private
Removes currently worn combat items that are not in the target gear set.
-
#return_held_gear(gear_set = 'standard') ⇒ Boolean?
Stows whatever is currently held in hands back to the appropriate location.
-
#stow_by_type(item) ⇒ Boolean
private
Executes a stow action with automatic recovery on common failure conditions.
- #stow_helper(action, weapon_name, *accept_strings, failure_patterns: [], retries: STOW_HELPER_MAX_RETRIES) ⇒ Object private
-
#stow_weapon(description = nil, transform_depth: 3) ⇒ void
Stows a weapon in its configured location (sheath, wear, tie, container, or general stow).
-
#swap_to_skill?(noun, skill) ⇒ Boolean
Swaps a weapon to be used for a different weapon skill.
-
#turn_to_weapon?(old_noun, new_noun) ⇒ Boolean
Turns a multi-form weapon to a different weapon form (e.g., Damaris weapons).
-
#unload_weapon(name) ⇒ void
Unloads a ranged weapon (bow, crossbow) and stows the ammo.
-
#verb_data(item) ⇒ Hash{Symbol => Hash}
private
Builds a hash of verb configurations for retrieving an item by type.
-
#wear_equipment_set?(set_name) ⇒ Boolean
Switches to a named gear set, removing unneeded items and wearing missing ones.
-
#wear_item?(item) ⇒ Boolean
Retrieves an item and wears it.
-
#wear_items(items_list) ⇒ void
Wears a list of items and optionally sorts inventory head position.
-
#wear_missing_items(target_items, combat_items) ⇒ Array<DRC::Item>
private
Wears items from the target set that are not currently in the combat inventory.
-
#wield_weapon?(description, skill = nil) ⇒ Boolean?
(also: #wield_weapon)
Wields a weapon into the right hand, or left hand if skill is "Offhand Weapon".
-
#wield_weapon_offhand?(description, skill = nil) ⇒ Boolean?
(also: #wield_weapon_offhand)
Wields a weapon into the left (off) hand.
Constructor Details
#initialize(settings = nil) ⇒ EquipmentManager
Creates a new EquipmentManager and loads gear configuration.
42 43 44 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 42 def initialize(settings = nil) items(settings) end |
Instance Method Details
#desc_to_items(descs) ⇒ Array<DRC::Item>
Converts an array of description strings to matching DRC::Item objects.
129 130 131 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 129 def desc_to_items(descs) descs.map { |description| item_by_desc(description) }.compact end |
#empty_hands ⇒ void
This method returns an undefined value.
Empties both hands by returning held gear or falling back to DRCI.stow_hands.
468 469 470 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 468 def empty_hands return_held_gear || DRCI.stow_hands end |
#get_combat_items ⇒ Array<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.
Retrieves the list of currently worn combat equipment via the INV COMBAT command.
207 208 209 210 211 212 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 207 def get_combat_items 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) return [] unless snapshot snapshot.map(&:strip) - ["All of your worn combat equipment:", "You aren't wearing anything like that."] end |
#get_item?(item) ⇒ Boolean
Retrieves an item from wherever it is stored (worn, tied, sheathed, container, or stowed).
Checks hands first, then tries wield, transform, tie-to, worn, container, and general stow locations in order.
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 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 397 def get_item?(item) return true if DRCI.in_hands?(item) if item.wield case DRC.bput("wield my #{item.short_name}", *DRCI::WIELD_ITEM_SUCCESS_PATTERNS, *DRCI::WIELD_ITEM_FAILURE_PATTERNS) when *DRCI::WIELD_ITEM_SUCCESS_PATTERNS return true else Lich::Messaging.msg("bold", "EquipmentManager: Unable to wield #{item.short_name}") return false end elsif item.transforms_to transform_item = item_by_desc(item.transforms_to) unless transform_item Lich::Messaging.msg("bold", "EquipmentManager: Could not find transformed item matching '#{item.transforms_to}' in gear list") return false end unless transform_item.worn ? get_item_helper(transform_item, :worn) : get_item_helper(transform_item, :stowed) Lich::Messaging.msg("bold", "EquipmentManager: Unable to retrieve #{transform_item.short_name} for transform") return false end get_item_helper(transform_item, :transform) elsif (item.tie_to && get_item_helper(item, :tied)) || (item.worn && get_item_helper(item, :worn)) || (item.container && DRCI.get_item(item.short_name, item.container)) || get_item_helper(item, :stowed) true else Lich::Messaging.msg("bold", "EquipmentManager: Could not find #{item.short_name} anywhere") false end end |
#get_item_helper(item, type) ⇒ 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 retrieve an item using the verb configuration for the given type.
Issues the appropriate game command (remove, untie, get, or transform verb) and handles failures with recovery procs.
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 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 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 609 def get_item_helper(item, type) return false unless item data = verb_data(item)[type] snapshot = [DRC.left_hand, DRC.right_hand] waitrt? response = DRC.bput("#{data[:verb]} my #{item.short_name}", *data[:matches]) waitrt? # Handle empty/nil response (bput timeout) as failure if response.nil? || response.empty? Lich::Messaging.msg("bold", "EquipmentManager: No response from game for '#{data[:verb]} my #{item.short_name}' - command may have been lost") return false end # For non-transform types, verify success via the XML game-object # feed rather than trusting bput's text match. This prevents false # positives where an unrelated game message (e.g., "You get the # feeling...") matches /^You get/ in GET_ITEM_SUCCESS_PATTERNS, # causing bput to return "You get" which then triggers the failure # recovery proc and stows the item that was just retrieved. # See elanthia-online/lich-5#1286 for the same approach in # DRCI.get_item_unsafe. # Transform is excluded because the item changes identity (e.g., # orb -> armor) so noun verification against the original item # would fail. if type != :transform noun = DRC.get_noun(item.short_name) 10.times do break if item_noun_in_hands?(noun) pause 0.05 end return true if item_noun_in_hands?(noun) end case response when 'You are already holding' return true when *data[:exhausted] return false when *data[:failures] data[:failure_recovery].call(item.name, item, response) # Check if hands changed from pre-command snapshot, consistent with # the success (else) branch. Using in_hands?(item) here would fail # for :transform where the item changes identity (e.g., orb -> armor). return snapshot != [DRC.left_hand, DRC.right_hand] else # Wait for hands to change with a timeout to prevent infinite loop timeout = Time.now + 5 pause 0.05 while snapshot == [DRC.left_hand, DRC.right_hand] && Time.now < timeout if snapshot == [DRC.left_hand, DRC.right_hand] Lich::Messaging.msg("bold", "EquipmentManager: Hands did not change after '#{data[:verb]} my #{item.short_name}' - item may not have been retrieved") return false end return true end end |
#item_by_desc(description) ⇒ DRC::Item?
Finds a gear item matching the given description.
137 138 139 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 137 def item_by_desc(description) items.find { |item| item.short_regex =~ description } end |
#item_noun_in_hands?(noun) ⇒ 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 whether the given noun is in either hand via GameObj XML feed.
Uses DRC.left_hand_noun / DRC.right_hand_noun which read
GameObj.noun directly, bypassing fix_dr_bullshit name
truncation that can drop interior words from multi-word item
names (e.g., "steel foil with a sandalwood hilt" becomes
"steel hilt", losing the "foil" noun entirely).
678 679 680 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 678 def item_noun_in_hands?(noun) [DRC.left_hand_noun, DRC.right_hand_noun].compact.include?(noun) end |
#items(settings = nil) ⇒ Array<DRC::Item>
Returns the list of gear items, loading from settings on first call.
Parses the user's gear configuration into DRC::Item objects and caches the result. Also initializes gear sets from settings.
53 54 55 56 57 58 59 60 61 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 53 def items(settings = nil) return @items if @items settings ||= get_settings @gear_sets = {} settings.gear_sets.each { |set_name, gear_list| @gear_sets[set_name] = gear_list.flatten.uniq } @sort_head = settings.sort_auto_head @items = settings.gear.map { |item| DRC::Item.new(name: item[:name], leather: item[:is_leather], hinders_locks: item[:hinders_lockpicking], worn: item[:is_worn], swappable: item[:swappable], tie_to: item[:tie_to], adjective: item[:adjective], bound: item[:bound], wield: item[:wield], transforms_to: item[:transforms_to], transform_verb: item[:transform_verb], transform_text: item[:transform_text], lodges: item[:lodges], ranged: item[:ranged], needs_unloading: item[:needs_unloading], skip_repair: item[:skip_repair], container: item[:container]) } end |
#listed_item?(desc) ⇒ DRC::Item? Also known as: is_listed_item?
Checks whether a description matches a configured gear item.
431 432 433 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 431 def listed_item?(desc) items.find { |item| item.short_regex =~ desc } end |
#matching_combat_items(list) ⇒ Array<DRC::Item> Also known as: worn_items
Returns the subset of currently worn combat items that match the given description list.
218 219 220 221 222 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 218 def matching_combat_items(list) filter_gear = desc_to_items(list) gear = desc_to_items(get_combat_items) gear.select { |x| filter_gear.include?(x) } end |
#notify_missing(lost_items) ⇒ 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.
Alerts the user about equipment items that could not be found.
146 147 148 149 150 151 152 153 154 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 146 def notify_missing(lost_items) return unless lost_items && !lost_items.empty? DRC.beep Lich::Messaging.msg("bold", "EquipmentManager: MISSING EQUIPMENT - Please verify these items are in a closed container and not lost:") Lich::Messaging.msg("bold", "EquipmentManager: #{lost_items.map(&:short_name).join(', ')}") pause DRC.beep end |
#remove_gear_by {|DRC::Item| ... } ⇒ Array<DRC::Item>
Removes currently worn combat items that match the given block condition.
Yields each DRC::Item to the block and removes those for which the block returns true.
74 75 76 77 78 79 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 74 def remove_gear_by(&_block) combat_items = get_combat_items gear = desc_to_items(combat_items).select { |item| yield(item) } gear.each { |item| remove_item(item) } gear end |
#remove_item(item, retries: 2) ⇒ Boolean?
Removes an item from the character and stows it in its configured location.
Handles transform items (e.g., exoskeletal armor becoming an orb), tie-to items, sheathed weapons, container-specific items, and general stow. Empties hands if needed for two-handed removal.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 236 def remove_item(item, retries: 2) if retries <= 0 Lich::Messaging.msg("bold", "EquipmentManager: remove_item exceeded max retries for #{item.short_name}") return false end result = DRC.bput("remove my #{item.short_name}", *DRCI::REMOVE_ITEM_SUCCESS_PATTERNS, *DRCI::REMOVE_ITEM_FAILURE_PATTERNS, "then constricts tighter around your") waitrt? case result when /then constricts tighter around your/ # Items that auto-repair, like exoskeletal armor, # may have a timer on them that prevents you removing them. Lich::Messaging.msg("bold", "EquipmentManager: The #{item.short_name} is not ready to be removed yet. Try again later.") return false when *DRCI::REMOVE_ITEM_FAILURE_PATTERNS # We may need to empty our hands to remove the item. # For example, exoskeletal armor requires two hands. temp_left_item = DRC.left_hand temp_right_item = DRC.right_hand # Lower the items because that preserves loaded bows. # Stowing them in a container would require unloading. did_lower = [temp_left_item, temp_right_item].compact.all? { |item_in_hand| DRCI.lower_item?(item_in_hand) } if did_lower remove_item(item, retries: retries - 1) else Lich::Messaging.msg("bold", "EquipmentManager: Unable to empty your hands to remove #{item.short_name}") end # Pick up the items in reverse order you lowered them # so that they end up in the correct hands again. DRCI.get_item_if_not_held?(temp_right_item) if temp_right_item DRCI.get_item_if_not_held?(temp_left_item) if temp_left_item # In case they end up in different hands, swap. if DRC.left_hand != temp_left_item || DRC.right_hand != temp_right_item swap_result = DRC.bput('swap', *DRCI::SWAP_HANDS_SUCCESS_PATTERNS, *DRCI::SWAP_HANDS_FAILURE_PATTERNS) unless DRCI::SWAP_HANDS_SUCCESS_PATTERNS.any? { |p| p.match?(swap_result) } Lich::Messaging.msg("bold", "EquipmentManager: Unable to restore hand order after removing #{item.short_name}") end end when *DRCI::REMOVE_ITEM_SUCCESS_PATTERNS # If removing item transforms it (e.g. exoskeletal armor => orb) then continue with the transformed item. if item.transforms_to && DRCI.in_hands?(item.transforms_to) transform_desc = item.transforms_to item = item_by_desc(transform_desc) unless item Lich::Messaging.msg("bold", "EquipmentManager: Could not find transformed item matching '#{transform_desc}' in gear list") return false end end if item.tie_to || item.wield || item.container stow_by_type(item) elsif /more room|too long to fit/ =~ DRC.bput("stow my #{item.short_name}", *DRCI::PUT_AWAY_ITEM_SUCCESS_PATTERNS, 'There isn\'t any more room', 'straps have all been used', 'is too long to fit') wear_item?(item) end end waitrt? end |
#remove_unmatched_items(combat_items, target_items) ⇒ 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.
Removes currently worn combat items that are not in the target gear set.
190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 190 def remove_unmatched_items(combat_items, target_items) if UserVars.equipmanager_debug Lich::Messaging.msg("plain", "EquipmentManager: removing unmatched items between these two sets") Lich::Messaging.msg("plain", "EquipmentManager: combat: #{combat_items.join(',')}") Lich::Messaging.msg("plain", "EquipmentManager: target: #{target_items.map(&:short_name).join(',')}") end combat_items .reject { |description| target_items.find { |item| item.short_regex =~ description } } .map { |description| items.find { |item| item.short_regex =~ description } } .compact .each { |item| remove_item(item) } end |
#return_held_gear(gear_set = 'standard') ⇒ Boolean?
Stows whatever is currently held in hands back to the appropriate location.
For items in the specified gear set, wears them. For other known items, ties, sheathes, or stows them based on their configuration.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 445 def return_held_gear(gear_set = 'standard') return unless DRC.right_hand || DRC.left_hand todo = [DRC.left_hand, DRC.right_hand].compact gear_set_items = desc_to_items(@gear_sets[gear_set] || []) todo.all? do |held_item| if (info = gear_set_items.find { |item| item.short_regex =~ held_item }) unload_weapon(info.short_name) if info.needs_unloading stow_helper("wear my #{info.short_name}", info.short_name, *DRCI::WEAR_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::WEAR_ITEM_FAILURE_PATTERNS) elsif (info = items.find { |item| item.short_regex =~ held_item }) unload_weapon(info.short_name) if info.needs_unloading stow_by_type(info) else false end end end |
#stow_by_type(item) ⇒ 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.
Executes a stow action with automatic recovery on common failure conditions.
Handles unload prompts, fan close, combat busy, movement lock, container size, and wound/sheath failures by retrying with corrective actions.
Stows an item based on its configured storage type (tie, sheath, container, or default stow).
Handles the common tie/wield/container/stow decision shared by #remove_item, #return_held_gear, and #stow_weapon.
896 897 898 899 900 901 902 903 904 905 906 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 896 def stow_by_type(item) if item.tie_to stow_helper("tie my #{item.short_name} to my #{item.tie_to}", item.short_name, *DRCI::TIE_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::TIE_ITEM_FAILURE_PATTERNS) elsif item.wield stow_helper("sheath my #{item.short_name}", item.short_name, *DRCI::SHEATH_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::SHEATH_ITEM_FAILURE_PATTERNS) elsif item.container stow_helper("put my #{item.short_name} in my #{item.container}", item.short_name, *DRCI::PUT_AWAY_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::PUT_AWAY_ITEM_FAILURE_PATTERNS) else stow_helper("stow my #{item.short_name}", item.short_name, *DRCI::PUT_AWAY_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::PUT_AWAY_ITEM_FAILURE_PATTERNS) end end |
#stow_helper(action, weapon_name, *accept_strings, failure_patterns: [], retries: STOW_HELPER_MAX_RETRIES) ⇒ Object
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.
911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 911 def stow_helper(action, weapon_name, *accept_strings, failure_patterns: [], retries: STOW_HELPER_MAX_RETRIES) if retries <= 0 Lich::Messaging.msg("bold", "EquipmentManager: stow_helper exceeded max retries for '#{action}'") return false end result = DRC.bput(action, *accept_strings, *failure_patterns, *STOW_RECOVERY_PATTERNS) if result.nil? || result.empty? Lich::Messaging.msg("bold", "EquipmentManager: stow_helper got no response for '#{action}'") return false end case result when /unload/ unload_weapon(weapon_name) return stow_helper(action, weapon_name, *accept_strings, failure_patterns: failure_patterns, retries: retries - 1) when /close the fan/ fput("close my #{weapon_name}") return stow_helper(action, weapon_name, *accept_strings, failure_patterns: failure_patterns, retries: retries - 1) when /You are a little too busy/ DRC.retreat return stow_helper(action, weapon_name, *accept_strings, failure_patterns: failure_patterns, retries: retries - 1) when /You don't seem to be able to move/ pause 1 return stow_helper(action, weapon_name, *accept_strings, failure_patterns: failure_patterns, retries: retries - 1) when /is too small to hold that/ fput("swap my #{weapon_name}") return stow_helper(action, weapon_name, *accept_strings, failure_patterns: failure_patterns, retries: retries - 1) when /Your wounds hinder your ability to do that/, /Sheath your .* where/ return stow_helper("stow my #{weapon_name}", weapon_name, *DRCI::PUT_AWAY_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::PUT_AWAY_ITEM_FAILURE_PATTERNS, retries: retries - 1) when *STOW_RECOVERY_PATTERNS # Catch-all for any recovery pattern not explicitly handled above Lich::Messaging.msg("bold", "EquipmentManager: stow_helper unhandled recovery for '#{action}': #{result}") return false end # Check if the result matched an explicit failure pattern if failure_patterns.any? { |p| p.match?(result) } Lich::Messaging.msg("bold", "EquipmentManager: stow_helper failed for '#{action}': #{result}") return false end true end |
#stow_weapon(description = nil, transform_depth: 3) ⇒ void
This method returns an undefined value.
Stows a weapon in its configured location (sheath, wear, tie, container, or general stow).
When called without a description, stows whatever is in both hands. Unloads ranged weapons before stowing if configured.
843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 843 def stow_weapon(description = nil, transform_depth: 3) unless description return unless DRC.right_hand || DRC.left_hand stow_weapon(DRC.right_hand) if DRC.right_hand stow_weapon(DRC.left_hand) if DRC.left_hand return end weapon = item_by_desc(description) return unless weapon # Is this a weapon that needs to be unloaded before it is put away? # This is an optimization attempt so that the script # isn't trying to unload every weapon that gets put away. # Would be silly to try "unload my scimitar" wouldn't it? :grins: unload_weapon(weapon.short_name) if weapon.needs_unloading if weapon.worn stow_helper("wear my #{weapon.short_name}", weapon.short_name, *DRCI::WEAR_ITEM_SUCCESS_PATTERNS, failure_patterns: DRCI::WEAR_ITEM_FAILURE_PATTERNS) elsif weapon.transforms_to if transform_depth <= 0 Lich::Messaging.msg("bold", "EquipmentManager: stow_weapon exceeded max transform depth for #{weapon.short_name}") return end stow_helper("#{weapon.transform_verb} my #{weapon.short_name}", weapon.short_name, weapon.transform_text) stow_weapon(weapon.transforms_to, transform_depth: transform_depth - 1) else stow_by_type(weapon) end end |
#swap_to_skill?(noun, skill) ⇒ Boolean
Swaps a weapon to be used for a different weapon skill.
Handles multi-skill weapons such as bastard swords, bar maces, and ristes. For fans, opens or closes them based on skill type.
708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 708 def swap_to_skill?(noun, skill) if noun =~ /\bfan\b/i command = skill =~ /edged/i ? 'open' : 'close' DRC.bput("#{command} my fan", 'you snap', 'already') return true end proper_skill = case skill when /^he$|heavy edge|large edge|one-handed/i 'heavy edged' when /^2he$|^the$|twohanded edge|two-handed edge/i 'two-handed edged' when /^hb$|heavy blunt|large blunt/i 'heavy blunt' when /^2hb$|^thb$|twohanded blunt|two-handed blunt/i 'two-handed blunt' when /^se$|small edged|light edge|medium edge/i '(light edged|medium edged)' when /^sb$|small blunt|light blunt|medium blunt/i '(light blunt|medium blunt)' when /^lt$|light thrown/i 'light thrown' when /^ht$|heavy thrown/i 'heavy thrown' when /stave/i '(short|quarter) staff' when /polearms/i '(halberd|pike)' when /^ow$|offhand weapon/i return true # just use weapon in your left hand else Lich::Messaging.msg("bold", "EquipmentManager: Unsupported weapon swap: #{noun} to #{skill}. Please report this to https://github.com/elanthia-online/lich-5/issues") return false end # All possible weapon skills to swap into. weapon_skills = [ 'light edged', 'medium edged', 'heavy edged', 'two-handed edged', 'light blunt', 'medium blunt', 'heavy blunt', 'two-handed blunt', 'light thrown', 'heavy thrown', 'short staff', 'quarter staff', 'halberd', 'pike' ] failure_matches = [ /You have nothing to swap/, /Your (left|right) hand is too injured/, /Will alone cannot conquer the paralysis that has wracked your body/, /^You move a .* to your (left|right) hand/ ] # The spaces in the regex are deliberate skill_match = / #{proper_skill} /i swapped_count = 0 loop do pause 0.25 # Avoid infinite loop where weapon can't swap to desired skill. return false if swapped_count > weapon_skills.length swapped_count += 1 # Try to swap weapon to desired skill. case DRC.bput("swap my #{noun}", skill_match, /\b#{noun}\b.*(#{weapon_skills.join('|')})/, "You must have two free hands", *failure_matches) when /You must have two free hands/ DRCI.stow_hand('left') if DRC.left_hand && DRC.left_hand !~ /#{noun}/i DRCI.stow_hand('right') if DRC.right_hand && DRC.right_hand !~ /#{noun}/i hands_free = [DRC.left_hand, DRC.right_hand].compact.all? { |h| h =~ /#{noun}/i } unless hands_free Lich::Messaging.msg("bold", "EquipmentManager: Unable to free hands for weapon swap") return false end when *failure_matches return false when skill_match return true end end end |
#turn_to_weapon?(old_noun, new_noun) ⇒ Boolean
Turns a multi-form weapon to a different weapon form (e.g., Damaris weapons).
687 688 689 690 691 692 693 694 695 696 697 698 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 687 def turn_to_weapon?(old_noun, new_noun) return true if old_noun == new_noun result = DRC.bput("turn my #{old_noun} to #{new_noun}", /^Turn what?/i, /^Which weapon did you want to pull out/i, /^Your .*\b#{old_noun}.* shifts .*/i) waitrt? # turning may incur roundtime case result when /^Your .*\b#{old_noun}.* shifts .* before resolving itself into .*\b#{new_noun}/i true else false end end |
#unload_weapon(name) ⇒ void
This method returns an undefined value.
Unloads a ranged weapon (bow, crossbow) and stows the ammo.
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 799 def unload_weapon(name) result = DRC.bput("unload my #{name}", *DRCI::UNLOAD_WEAPON_SUCCESS_PATTERNS, *DRCI::UNLOAD_WEAPON_FAILURE_PATTERNS) waitrt? # wait out the unload roundtime so the ammo/hand state has settled before we act on it ammo_match = result&.match(/^(?:Your .*?\b(?<ammo>[\w]+)\b fall.* from your .* to your feet\.)$/) ground_match = result&.match?(/As you release the string/) ? result.match(/the (?<ammo>\w+) tumbles/) : nil if ammo_match || ground_match # Ammo ended up on the GROUND (hands were full, or it tumbled). Lower the # weapon, stow the ammo from your feet, then pick the weapon back up. ammo = (ammo_match || ground_match)[:ammo] unless DRCI.lower_item?(name) Lich::Messaging.msg("bold", "EquipmentManager: Unable to lower #{name} to pick up ammo") return end DRCI.put_away_item?(ammo) unless DRCI.get_item?(name) Lich::Messaging.msg("bold", "EquipmentManager: Unable to pick #{name} back up after unloading") end elsif result && DRCI::UNLOAD_WEAPON_SUCCESS_PATTERNS.any? { |pattern| pattern.match?(result) } # Unload succeeded with the ammo now in a hand. Stow whichever hand is NOT # the weapon, comparing by NOUN against the actual hand contents -- robust to # the <dialogData ...AimTimer...> tag the game prepends (which the old # ^-anchored /^(?:You unload|...)/ branch missed) and to ammo nouns that # contain the weapon noun (e.g. "crossbow bolt"). Guarded on a positive # success match so an unload failure or a bput timeout can't stow an # unrelated off-hand item. weapon_noun = DRC.get_noun(name) [['left', DRC.left_hand], ['right', DRC.right_hand]].each do |side, held| next if held.nil? || DRC.get_noun(held) == weapon_noun Lich::Messaging.msg("bold", "EquipmentManager: Unable to stow ammo from #{side} hand") unless DRCI.stow_hand(side) end end end |
#verb_data(item) ⇒ Hash{Symbol => 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.
Builds a hash of verb configurations for retrieving an item by type.
Each type (+:worn+, :tied, :stowed, :transform) maps to a hash
with the game verb, match patterns, failure patterns, and recovery procs.
Match patterns reference DRCI constants so that new game messages added
to DRCI are automatically picked up here.
The matches array is passed to bput and must include success,
failure, and exhausted patterns so bput returns promptly.
get_item_helper then triages the response:
exhausted: non-recoverable failure -- return false immediatelyfailures: recoverable error -- runfailure_recoveryproc- everything else: success -- wait for hand contents to change
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 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 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 517 def verb_data(item) { worn: { verb: 'remove', matches: [ /^You .*#{item.short_regex}/, /^You (get|sling|pull|work|loosen|slide|remove|yank|unbuckle).*#{item.name}/, *DRCI::REMOVE_ITEM_SUCCESS_PATTERNS, *DRCI::REMOVE_ITEM_FAILURE_PATTERNS ], failures: [/^You (get|sling|pull|work|slide|remove|yank|unbuckle) $/], failure_recovery: proc { |noun| DRC.bput("wear my #{noun}", '^You ') }, exhausted: DRCI::REMOVE_ITEM_FAILURE_PATTERNS }, tied: { verb: 'untie', matches: [ /^You .*#{item.short_regex}/, /^You remove.*#{item.name}/, /^.*you untie your .*#{item.short_regex} from it./, *DRCI::UNTIE_ITEM_SUCCESS_PATTERNS, *DRCI::UNTIE_ITEM_FAILURE_PATTERNS ], # NOTE: /^You remove$/ (with end anchor) prevents matching successful # untie responses like "You remove a sword from your belt" -- only # matches the bare "You remove" edge case. failures: [/^You remove$/, /^You are a little too busy/, /^You are a bit too busy/], # NOTE: response is accepted as a single String (not *splat) so that # case/when uses Regexp#=== for proper pattern matching. The original # *matches splat wrapped the response in an Array, making Regexp-based # when clauses silently fall through to else. failure_recovery: proc { |_noun, item_to_recover, response| case response when /You are a little too busy/ DRC.retreat get_item?(item_to_recover) when /You are a bit too busy/ DRC. get_item?(item_to_recover) else stow_weapon end }, exhausted: UNTIE_EXHAUSTED_PATTERNS }, stowed: { verb: 'get', matches: [ /^You .*#{item.short_regex}/, /^You .*#{item.name}/, *DRCI::GET_ITEM_SUCCESS_PATTERNS, *DRCI::GET_ITEM_FAILURE_PATTERNS, /^The.* slides easily out/, /But that is already/ ], failures: [/^You get$/, /But that is already/], failure_recovery: proc { |noun| DRC.bput("stow my #{noun}", 'You put', 'But that is already in') }, exhausted: DRCI::GET_ITEM_FAILURE_PATTERNS }, transform: { verb: item.transform_verb, matches: [ item.transform_text, /You'll need a free hand to do that!/, /You don't seem to be holding/, *DRCI::GET_ITEM_FAILURE_PATTERNS ], failures: [/You'll need a free hand to do that!/, /You don't seem to be holding/], failure_recovery: proc do |noun| DRCI.stow_hand('left') if DRC.left_hand && DRC.left_hand !~ /#{noun}/i DRCI.stow_hand('right') if DRC.right_hand && DRC.right_hand !~ /#{noun}/i if (DRC.left_hand && DRC.left_hand !~ /#{noun}/i) || (DRC.right_hand && DRC.right_hand !~ /#{noun}/i) Lich::Messaging.msg("bold", "EquipmentManager: Unable to free hands for transform") next end item.worn ? DRC.bput("remove my #{noun}", '^You') : DRC.bput("get my #{noun}", '^You') DRC.bput("#{item.transform_verb} my #{item.short_name}", *verb_data(item)[:transform][:matches]) end, exhausted: DRCI::GET_ITEM_FAILURE_PATTERNS } } end |
#wear_equipment_set?(set_name) ⇒ Boolean
Switches to a named gear set, removing unneeded items and wearing missing ones.
Compares currently worn combat items against the target gear set, removes items not in the set, and wears any missing items. Notifies the user about items that could not be found.
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 102 def wear_equipment_set?(set_name) return false unless set_name unless @gear_sets[set_name] Lich::Messaging.msg("bold", "EquipmentManager: Could not find gear set '#{set_name}'") return false end gear_set_items = desc_to_items(@gear_sets[set_name]) Lich::Messaging.msg("plain", "EquipmentManager: expected worn items: #{gear_set_items.map(&:short_name).join(',')}") if UserVars.equipmanager_debug combat_items = get_combat_items remove_unmatched_items(combat_items, gear_set_items) lost_items = wear_missing_items(gear_set_items, combat_items) notify_missing(lost_items) DRC.bput('sort auto head', /^Your inventory is now arranged/) if @sort_head lost_items.empty? end |
#wear_item?(item) ⇒ Boolean
Retrieves an item and wears it.
297 298 299 300 301 302 303 304 305 306 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 297 def wear_item?(item) if item.nil? Lich::Messaging.msg("bold", "EquipmentManager: Failed to match an item, try turning on debugging with #{$clean_lich_char}e UserVars.equipmanager_debug = true") return false end if get_item?(item) return DRCI.wear_item?(item.short_name) end return false end |
#wear_items(items_list) ⇒ void
This method returns an undefined value.
Wears a list of items and optionally sorts inventory head position.
85 86 87 88 89 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 85 def wear_items(items_list) items_list.each { |item| wear_item?(item) } DRC.bput('sort auto head', /^Your inventory is now arranged/) if @sort_head end |
#wear_missing_items(target_items, combat_items) ⇒ Array<DRC::Item>
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.
Wears items from the target set that are not currently in the combat inventory.
Stows any target items found in hands before wearing. Returns items that could not be worn (missing from containers).
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 165 def wear_missing_items(target_items, combat_items) if UserVars.equipmanager_debug Lich::Messaging.msg("plain", "EquipmentManager: wearing missing items between these two sets") Lich::Messaging.msg("plain", "EquipmentManager: combat: #{combat_items.join(',')}") Lich::Messaging.msg("plain", "EquipmentManager: target: #{target_items.map(&:short_name).join(',')}") end missing_items = target_items .reject { |item| combat_items.find { |c_item| item.short_regex =~ c_item } } .reject { |item| [DRC.right_hand, DRC.left_hand].grep(item.short_regex).any? ? (stow_weapon(item.short_name) || true) : false } Lich::Messaging.msg("plain", "EquipmentManager: wear missing items #{missing_items}") if !missing_items.empty? && UserVars.equipmanager_debug missing_items.reject do |item| item_copy = item.dup item_copy.instance_variable_set(:@worn, false) wear_item?(item_copy) end end |
#wield_weapon?(description, skill = nil) ⇒ Boolean? Also known as: wield_weapon
Wields a weapon into the right hand, or left hand if skill is "Offhand Weapon".
Stows any currently held instance of the weapon first, then retrieves and optionally swaps it to the desired skill.
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 355 def wield_weapon?(description, skill = nil) return unless description && !description.empty? offhand = skill == 'Offhand Weapon' weapon = item_by_desc(description) unless weapon Lich::Messaging.msg("bold", "EquipmentManager: Failed to match a weapon for #{description}:#{skill}") return false end if [DRC.left_hand, DRC.right_hand].grep(weapon.short_regex).any? stow_weapon end if get_item?(weapon) swap_to_skill?(weapon.name, skill) if skill && weapon.swappable if offhand && DRCI.in_right_hand?(weapon) case DRC.bput('swap', *DRCI::SWAP_HANDS_SUCCESS_PATTERNS, *DRCI::SWAP_HANDS_FAILURE_PATTERNS) when *DRCI::SWAP_HANDS_SUCCESS_PATTERNS return true else return false end end return true end return false end |
#wield_weapon_offhand?(description, skill = nil) ⇒ Boolean? Also known as: wield_weapon_offhand
Wields a weapon into the left (off) hand.
Retrieves the weapon, optionally swaps it to the desired skill, then swaps it from the right hand to the left hand.
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 |
# File 'documented/dragonrealms/commons/equipmanager.rb', line 316 def wield_weapon_offhand?(description, skill = nil) return unless description && !description.empty? weapon = item_by_desc(description) unless weapon Lich::Messaging.msg("bold", "EquipmentManager: Failed to match a weapon for #{description}:#{skill}") return false end return false unless get_item?(weapon) swap_to_skill?(weapon.name, skill) if skill && weapon.swappable # We want the weapon in the LEFT (off) hand. If it landed in the right hand # (e.g. get placed it there), swap it over; if it's already in the left # hand, we're done -- previously this returned false in that case. if DRCI.in_right_hand?(weapon) case DRC.bput('swap', *DRCI::SWAP_HANDS_SUCCESS_PATTERNS, *DRCI::SWAP_HANDS_FAILURE_PATTERNS) when *DRCI::SWAP_HANDS_SUCCESS_PATTERNS return true else return false end end DRCI.in_left_hand?(weapon) end |