diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index e670d866a..1fc55cfa2 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -15,9 +15,29 @@
game: Gemstone
tags: loot
required: Lich >= 5.12.9
- version: 2.7.0
+ version: 2.8.0
Improvements:
Major_change.feature_addition.bugfix
+ v2.8.0 (2026-01-27)
+ - replaced overflow_container and secondary_overflow with single overflow_containers setting (comma-separated)
+ - added configurable "Trash to Dump" section, instead of hardcoded herb/food/junk
+ - bugfix inbetween script(s) added erroneous commas between script parameters
+ - allow custom bank withdraw amount
+ - bugfix when trying to store box in non-group disk
+ - bugfix in box_loot_ground locked box message
+ - bugfix in single_drag_box cycling thru all group disks even when use_disk_group was false
+ - bugfix for eonake gauntlet missing XML to properly match
+ - bugfix for in_region check if already in destination room
+ - reset sacks full when using --sellable/type/sell CLI
+ - locksmith pool remove silver withdraw
+ - fix to process boxes from default/overflows first, then box/disk container to prevent sacks_full emptying loot
+ - add skin bounty creatures only
+ - bugfix in keep scrolls option to skip if adding non-number to entries
+ - expand F2P silver withdraw to support Teras
+ - bugfix in process_boxes and always check pool
+ - bugfix for frozen bramble looting
+ - bugfix for manual deposit hoard when items in left hand
+ - bugfix for hoarding when valid hoard items have same name as none valid items
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -245,7 +265,7 @@ module ELoot # Data
# inventory type
@sacks_closed = []
- @sacks_full = []
+ @sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
@checked_bags = []
@sell_containers = []
@ready_lines = []
@@ -622,8 +642,7 @@ module ELoot # UI Setup
loot_phase: { default: false },
use_disk: { default: true },
loot_defensive: { default: false },
- overflow_container: { default: '' },
- secondary_overflow: { default: '' },
+ overflow_containers: { default: '' },
coin_hand_name: { default: '' },
charm_name: { default: '' },
sigil_determination_on_fail: { default: false },
@@ -724,6 +743,7 @@ module ELoot # UI Setup
next if setting.include?(text)
spell_no = text[/^\d+/]
+ next if spell_no.nil?
next if Spell[spell_no].nil?
setting.push(text)
@@ -743,12 +763,14 @@ module ELoot # UI Setup
sell_aspect: { default: false },
sell_keep_silver: { default: 0 },
sell_deposit_coinhand: { default: false },
+ trash_dump_types: { default: ["herb", "junk", "food"] },
},
skin: {
skin_enable: { default: false },
skin_kneel: { default: false },
skin_604: { default: false },
skin_resolve: { default: false },
+ skin_bounty_only: { default: false },
skin_sheath: { default: '' },
skin_weapon: { default: '' },
skin_sheath_blunt: { default: '' },
@@ -802,7 +824,8 @@ module ELoot # UI Setup
gem_everything_list: { default: false },
gem_only_list: { default: false },
gem_horde_container: { default: '' },
- gem_horde_containers: { default: ['default', 'gem', 'overflow1', 'overflow2'] },
+ gem_horde_containers: { default: ['default', 'gem'] },
+ gem_horde_use_overflow: { default: false },
gem_locker: { default: '' },
gem_locker_name: { default: '' },
gem_horde_locker_che: { default: false },
@@ -855,7 +878,8 @@ module ELoot # UI Setup
alchemy_everything_list: { default: false },
alchemy_only_list: { default: false },
alchemy_horde_container: { default: '' },
- alchemy_horde_containers: { default: ['default', 'reagent', 'overflow1', 'overflow2'] },
+ alchemy_horde_containers: { default: ['default', 'reagent'] },
+ alchemy_horde_use_overflow: { default: false },
alchemy_locker: { default: '' },
alchemy_locker_name: { default: '' },
alchemy_horde_locker_che: { default: false },
@@ -948,11 +972,9 @@ module ELoot # UI Setup
0001
20240411
- FalseTrue100Use town locksmithTrueTrueFalsestart510True
01Display box contentsTrueTrueFalsestart510True
11Always check pool (?)TrueTrueFalsestart510True
- 10TrueFalsestart1010Locksmith Withdraw Amount03
+ 10TrueFalsestart1010Bank Withdraw Amount03
TrueTrueHow much to withdraw from the bank before going to the town locksmith.start10105locksmith_withdraw_amount_adjustment
04Default to using locksmith when gem bounty activeTrueTrueFalse510True
022TrueFalseLocksmithing00
@@ -1061,7 +1083,7 @@ module ELoot # UI Setup
Share silversTrueTrueFalsestart55True20
TrueTruestart305300sell_keep_silver_adjustmentTrue312
TrueFalseOther Settings002FalseTrue3
- 3TrueFalseSelling3FalseTrueTrueinTrueFalseTrueFalse10150150TrueFalse50TrueFalsecenter5525Add80TrueTrueTruestart5
+ TrueFalse100TrueFalse5525TrueAlchemyTrueTrueFalsestart5True00FoodTrueTrueFalsestartTrue10Locksmith TrapsTrueTrueFalsestartTrue20BoxTrueTrueFalsestartTrue30HerbTrueTrueFalsestart5True01ReagentTrueTrueFalsestartTrue11WandTrueTrueFalsestartTrue21BreakableTrueTrueFalsestartTrue31ClothingTrueTrueFalsestart5True02JunkTrueTrueFalsestartTrue12LockpickTrueTrueFalsestartTrue22TrueFalseTrash to Dump (?)Will attempt to TRASH type after selling is done, requires type to be enabled for selling to dumpFalseTrue43TrueFalseSelling3FalseTrueTrueinTrueFalseTrueFalse10150150TrueFalse50TrueFalsecenter5525Add80TrueTrueTruestart5
00Delete80TrueTrueTrueend520
TrueTrueTrueEnter exclusion (e.g. uncut diamond)10200TrueTrue5555TrueinTrueFalseTrueTruesell_exclude_storeFalse0True
fixedExclusion0013TrueFalseExclusions (?)
@@ -1071,11 +1093,11 @@ module ELoot # UI Setup
Spell Number0Spell Name1Vibrant2
013TrueFalseKeep Scrolls (?)
104TrueFalseSelling Grid
- 4FalseTrueTrueinTrueFalsestartTrueFalse10verticalTrueFalse50TrueFalse55True1025TrueTrueFalse
+ 4FalseTrueTrueinTrueFalsestartTrueFalse10verticalTrueFalse50TrueFalse5510210TrueFalse
30Enable skinningTrueTrueFalsestartTrue00
Kneel to skinTrueTrueFalsestartTrue10Use Sigil of ResolveTrueTrueFalsestartTrue
20Use 604TrueTrueFalsestartTrue30
- TrueFalseSettingsFalseTrue0820TrueFalsestartTrueTrueFalsestart50TrueFalsecenterTrueTrueFalsestart1055Skin Sheath (blunt)
+ Skin Bounty OnlyTrueTrueFalsestartTrue40TrueFalseSettingsFalseTrue0820TrueFalsestartTrueTrueFalsestart50TrueFalsecenterTrueTrueFalsestart1055Skin Sheath (blunt)
00TrueTrue10102001TrueFalsestart2055Skin Weapon (blunt)
10TrueTrue2010102011
TrueFalseBlunt Skinning01TrueFalsestart50TrueFalsecenter55TrueTrueTrueFalsestart1055Skin Sheath (edged)
@@ -1099,9 +1121,8 @@ module ELoot # UI Setup
00TrueFalseend10Entry Verb01TrueFalseend10Exit Verb
0214TrueFalsestartstart1520
04TrueFalseGeneral SettingsFalseTrue0TrueFalse50TrueFalseTrueDefaultTrueTrueFalsestart101010True
- 00First OverflowTrueTrueFalsestart55True
- 20Second OverflowTrueTrueFalsestart55True
- 30GemTrueTrueFalsestart55True
+ 00Use All Overflow ContainersTrueTrueFalsestart55True
+ 20GemTrueTrueFalsestart55True
10TrueFalseOnly Hoard Gems from these ContainersFalseTrue1
TrueFalse50TrueFalseHoard all gems except those excluded belowTrueTrueFalsestart1010True
00ONLY hoard gems listed belowTrueTrueFalsestart1010True
@@ -1128,9 +1149,8 @@ module ELoot # UI Setup
0214Hoard reagents in a house locker?TrueTrueFalsestartend201010True
13TrueFalsestartstart152004
TrueFalseGeneral SettingsFalseTrue0TrueFalse50TrueFalseTrueDefaultTrueTrueFalsestart101010True
- 00First OverflowTrueTrueFalsestart55True
- 20Second OverflowTrueTrueFalsestart55True
- 30ReagentTrueTrueFalsestart55True
+ 00Use All Overflow ContainersTrueTrueFalsestart55True
+ 20ReagentTrueTrueFalsestart55True
10TrueFalseOnly Hoard Alchemy Ingredients from these ContainersFalseTrue1
TrueFalse50TrueFalseHoard all alchemy ingredients except those excluded belowTrueTrueFalsestart1010True
00ONLY hoard alchemy ingredients listed belowTrueTrueFalsestart1010True
@@ -1302,6 +1322,9 @@ module ELoot # UI Setup
elsif obj.class == Gtk::Entry
obj.text = @settings[key].strip
obj.signal_connect('changed') { on_update(obj) }
+ elsif obj.class == Gtk::TextView
+ obj.buffer.text = @settings[key].to_s.strip
+ obj.buffer.signal_connect('changed') { on_update(obj) }
elsif obj.class == Gtk::SpinButton
obj.value = @settings[key]
obj.adjustment.value = @settings[key]
@@ -1501,6 +1524,8 @@ module ELoot # UI Setup
end
elsif obj.class == Gtk::Entry
@settings[key] = obj.text.strip
+ elsif obj.class == Gtk::TextView
+ @settings[key] = obj.buffer.text.strip
elsif obj.class == Gtk::SpinButton
@settings[key] = obj.buffer.text
end
@@ -1755,10 +1780,68 @@ module ELoot # Profile loading/saving and settings
def self.load(settings)
@@data = Data.new(settings)
+ # Migrate old overflow settings to new format
+ ELoot.migrate_overflow_settings(ELoot.data.settings)
end
- def self.load_defaults()
- default_hash = {
+ def self.migrate_overflow_settings(settings)
+ migrated_settings = ELoot.seed_missing_defaults(settings)
+ # Migration helper: Convert old overflow_container and secondary_overflow to new overflow_containers format
+ if settings.key?(:overflow_container) || settings.key?(:secondary_overflow)
+ containers = []
+ containers << settings[:overflow_container].to_s.strip unless settings[:overflow_container].to_s.strip.empty?
+ containers << settings[:secondary_overflow].to_s.strip unless settings[:secondary_overflow].to_s.strip.empty?
+
+ unless containers.empty?
+ settings[:overflow_containers] = containers.join(', ')
+ ELoot.msg(text: " Migrated old overflow container settings to new format: #{settings[:overflow_containers]}")
+ end
+
+ # Remove old keys
+ settings.delete(:overflow_container)
+ settings.delete(:secondary_overflow)
+ migrated_settings = true
+ end
+
+ # Migration: Convert old gem/alchemy hoarding overflow checkboxes to new use_overflow boolean
+ ['gem', 'alchemy'].each do |type|
+ containers_key = "#{type}_horde_containers".to_sym
+ use_overflow_key = "#{type}_horde_use_overflow".to_sym
+
+ # Check if the old format with overflow1/overflow2 is present in the containers array
+ if settings[containers_key] && settings[containers_key].is_a?(Array)
+ old_containers = settings[containers_key]
+
+ # Check if overflow1 or overflow2 are in the array
+ has_overflow = old_containers.include?('overflow1') || old_containers.include?('overflow2')
+
+ if has_overflow
+ # Set the new use_overflow boolean to true
+ settings[use_overflow_key] = true
+
+ # Remove overflow1 and overflow2 from the array
+ settings[containers_key] = old_containers.reject { |c| c == 'overflow1' || c == 'overflow2' }
+
+ ELoot.msg(text: " Migrated #{type} hoarding overflow settings: enabled 'Use All Overflow Containers'")
+ migrated_settings = true
+ elsif !settings.key?(use_overflow_key)
+ # If the key doesn't exist and no old overflows were found, set to false
+ settings[use_overflow_key] = false
+ migrated_settings = true
+ end
+ end
+ end
+
+ if migrated_settings
+ ELoot.save_profile()
+ end
+ end
+
+ # Returns the canonical defaults hash with no side-effects.
+ # Used by load_defaults (which also persists it to disk) and by
+ # seed_missing_defaults (which backfills missing keys at load time).
+ def self.defaults_hash
+ {
:loot_types => ["alchemy", "armor", "box", "breakable", "clothing", "collectible", "food", "gem", "jewelry", "lockpick", "lm trap", "magic", "reagent", "scroll", "skin", "uncommon", "valuable", "wand"],
:loot_exclude => ["black ora", "urglaes"],
:loot_phase => false,
@@ -1767,8 +1850,7 @@ module ELoot # Profile loading/saving and settings
:coin_hand_name => "",
:sigil_determination_on_fail => false,
:charm_name => "",
- :overflow_container => "",
- :secondary_overflow => "",
+ :overflow_containers => "",
:sell_loot_types => ["alchemy", "armor", "breakable", "clothing", "food", "gem", "jewelry", "lockpick", "magic", "reagent", "scroll", "skin", "uncommon", "valuable", "wand", "box", "lm trap"],
:sell_container => ["default", "overflow", "box", "collectible", "forageable", "gem", "herb", "lockpick", "potion", "reagent", "scroll", "skin", "treasure", "trinket", "wand"],
:sell_exclude => [],
@@ -1791,10 +1873,12 @@ module ELoot # Profile loading/saving and settings
:sell_shroud => false,
:sell_aspect => false,
:sell_keep_silver => 0,
+ :trash_dump_types => ["herb", "junk", "food"],
:skin_enable => false,
:skin_kneel => false,
:skin_604 => false,
:skin_resolve => false,
+ :skin_bounty_only => false,
:skin_sheath => "",
:skin_weapon => "",
:skin_sheath_blunt => "",
@@ -1810,6 +1894,23 @@ module ELoot # Profile loading/saving and settings
:favor_left => false,
:log_unlootables => false
}
+ end
+
+ # Backfill any keys present in defaults_hash but absent from +settings+.
+ # Returns true if at least one key was added, so the caller knows to
+ # persist the profile. Safe to call without GTK.
+ def self.seed_missing_defaults(settings)
+ added = false
+ defaults_hash.each do |key, default_value|
+ next if settings.key?(key)
+ settings[key] = default_value
+ added = true
+ end
+ added
+ end
+
+ def self.load_defaults()
+ default_hash = defaults_hash
Dir.mkdir(File.join(DATA_DIR, XMLData.game)) unless File.exist?(File.join(DATA_DIR, XMLData.game))
Dir.mkdir(File.join(DATA_DIR, XMLData.game, Char.name)) unless File.exist?(File.join(DATA_DIR, XMLData.game, Char.name))
@@ -1914,7 +2015,7 @@ module ELoot # Sets Inventory
end
end
- if list[key].nil? && caller_locations(1, 1)[0].label != 'set_inventory'
+ if list[key].nil? && !caller_locations(1, 1)[0].label.include?('set_inventory')
ELoot.msg(text: " Can't find #{key}: #{item_name}. Please check ;eloot setup.", space: true)
end
end
@@ -2026,11 +2127,27 @@ module ELoot # Sets Inventory
# Remove any extra keys and repopulate them
ReadyList.ready_list.delete_if { |k, _| [:skin_weapon, :skin_weapon_blunt, :skin_sheath, :skin_sheath_blunt].include?(k) }
- StowList.stow_list.delete_if { |k, _| [:overflow_container, :secondary_overflow, :appraisal_container].include?(k) }
+ # Remove old overflow container keys (they may use sequential numbering now)
+ StowList.stow_list.delete_if { |k, _| k.to_s.start_with?('overflow_container') || k == :secondary_overflow || k == :appraisal_container }
+ StowList.stow_list.delete(:secondary_overflow)
+
+ # Find the stow containers we need: overflow, appraisal
+ # Parse comma-separated overflow containers and add them dynamically
+ overflow_list = ELoot.data.settings[:overflow_containers].to_s.split(',').map(&:strip).reject(&:empty?)
+ overflow_list.each_with_index do |container_name, index|
+ # Create a unique key for each overflow container
+ key = index == 0 ? :overflow_container : "overflow_container_#{index + 1}".to_sym
+ # Temporarily set the setting for this specific container so ensure_items can find it
+ temp_settings_key = "overflow_temp_#{index}".to_sym
+ ELoot.data.settings[temp_settings_key] = container_name
+ ELoot.ensure_items(key: temp_settings_key, list: StowList.stow_list)
+ # Move the found item to the proper key
+ if StowList.stow_list[temp_settings_key]
+ StowList.stow_list[key] = StowList.stow_list.delete(temp_settings_key)
+ end
+ ELoot.data.settings.delete(temp_settings_key)
+ end
- # Find the stow containers we need: stow, overflow, appraisal
- ELoot.ensure_items(key: 'overflow_container', list: StowList.stow_list)
- ELoot.ensure_items(key: 'secondary_overflow', list: StowList.stow_list)
ELoot.ensure_items(key: 'appraisal_container', list: StowList.stow_list)
# Find skin sheaths
@@ -2079,26 +2196,32 @@ module ELoot # Sets Inventory
container_array = []
- # Add the specific type container if it's in the sell list
- if type && ELoot.data.settings[:sell_container].include?(type)
- container = StowList.stow_list[type.to_sym]
- container_array << container if container
- end
-
# Add the default container
if ELoot.data.settings[:sell_container].include?("default")
container_array << StowList.default
end
- # Handle overflow containers
+ # Handle overflow containers - dynamically find all overflow container keys
if ELoot.data.settings[:sell_container].include?("overflow")
- [:overflow_container, :secondary_overflow].each do |key|
- ELoot.ensure_items(key: key, list: StowList.stow_list)
+ overflow_keys = StowList.stow_list.keys.select { |k| k.to_s.start_with?('overflow_container') }
+ overflow_keys.each do |key|
container = StowList.stow_list[key]
container_array << container if container
end
end
+ # Add the specific type container if it's in the sell list
+ if type && ELoot.data.settings[:sell_container].include?(type)
+ container = StowList.stow_list[type.to_sym]
+ if container
+ unless type.eql?('box')
+ container_array.unshift(container)
+ else
+ container_array << container
+ end
+ end
+ end
+
# Remove duplicates and ensure an array is always returned
container_array.compact.uniq
end
@@ -2107,8 +2230,6 @@ module ELoot # Sets Inventory
need_exit = false
checks = [
- [:overflow_container, StowList.stow_list[:overflow_container], "primary overflow container"],
- [:secondary_overflow, StowList.stow_list[:secondary_overflow], "secondary overflow container"],
[:appraisal_container, StowList.stow_list[:appraisal_container], "appraisal container"],
[:skin_sheath, ReadyList.ready_list[:skin_sheath], "bladed skinning sheath", :skin_enable],
[:skin_sheath_blunt, ReadyList.ready_list[:skin_sheath_blunt], "blunt skinning sheath", :skin_enable],
@@ -2118,13 +2239,26 @@ module ELoot # Sets Inventory
[:charm_name, ELoot.data.charm, "fossil charm"],
]
- checks.each do |setting_key, found_obj, label, conditional_key|
+ # Dynamically add overflow container checks
+ overflow_list = ELoot.data.settings[:overflow_containers].to_s.split(',').map(&:strip).reject(&:empty?)
+ overflow_list.each_with_index do |container_name, index|
+ key = index == 0 ? :overflow_container : "overflow_container_#{index + 1}".to_sym
+ label = index == 0 ? "primary overflow container" : "overflow container #{index + 1}"
+ # For validation, we check against the overflow_containers setting (comma-separated list)
+ # but we look up the actual found object in StowList
+ if !container_name.empty?
+ checks << [:overflow_containers, StowList.stow_list[key], label, nil, container_name]
+ end
+ end
+
+ checks.each do |setting_key, found_obj, label, conditional_key, configured_name|
# Only check if setting is non-empty and optional condition (like :skin_enable) is satisfied
- next if ELoot.data.settings[setting_key].to_s.empty?
+ next if setting_key != :overflow_containers && ELoot.data.settings[setting_key].to_s.empty?
next if conditional_key && !ELoot.data.settings[conditional_key]
if found_obj.nil?
- ELoot.msg(text: " Not able to find the #{label}: #{ELoot.data.settings[setting_key]}")
+ container_name = configured_name || ELoot.data.settings[setting_key]
+ ELoot.msg(text: " Not able to find the #{label}: #{container_name}")
need_exit = true
end
end
@@ -2181,12 +2315,29 @@ module ELoot # Regional bounty Selling
def self.tag_for_town(town, tag)
ELoot.msg(type: "debug", text: "tag: #{tag} | town: #{town}")
- self.by_town(tag).find { |k, _v| k.downcase.include?(town.downcase) }.last
+ match = self.by_town(tag).find { |k, _v| k.downcase.include?(town.downcase) }
+ match&.last
end
- def self.in_region(place) # Determine if the bounty town is within the characters region
+ # Determine if the bounty town is within the characters region
+ # vaalor ferry, west cart, east cart, RR boot
+ def self.in_region(place)
ELoot.msg(type: "debug", text: "place: #{place}")
- # vaalor ferry, west cart, east cart, RR boot
+
+ bounty_town = Bounty.town.eql?("Cold River") ? "Hinterwilds" : Bounty.town
+ destination = self.tag_for_town(bounty_town, place)
+ return nil unless destination
+
+ place = destination.id
+
+ # Early return if already at destination
+ return place if Room.current.eql?(Room[place])
+
+ # Calculate path once
+ path = Room.current.path_to(Room[place])
+ return nil unless path
+
+ # Lazy evaluation - only compute boundaries if we need to check them
boundaries = [
Map.ids_from_uid(14001002).first, # Ta'Vaalor Ferry
Map.ids_from_uid(13002021).first, # Western Spine Mine Cart
@@ -2204,12 +2355,8 @@ module ELoot # Regional bounty Selling
Map.ids_from_uid(7133026).first, # Portmaster - Icemule Trace
]
- bounty_town = Bounty.town == "Cold River" ? "Hinterwilds" : Bounty.town
-
- place = self.tag_for_town(bounty_town, place).id
- path = Room.current.path_to(Room[place])
-
- return place if path && boundaries.none? { |fence| path.include?(fence) }
+ # Use array intersection instead of iterating through each boundary
+ (path & boundaries).empty? ? place : nil
end
def self.furrier
@@ -2453,7 +2600,9 @@ module ELoot # Script utility type methods
rows << [{ value: " *** Full Disk/Sack Check ***", colspan: 7 }]
rows << :separator
rows << [{ value: "Disk Full: #{ELoot.data.disk_full.inspect}", colspan: 7 }]
- rows << [{ value: "Sacks Full: #{ELoot.data.sacks_full.map(&:name)}", colspan: 7 }]
+ ELoot.data.sacks_full.each do |container, information|
+ rows << [{ value: "Sacks Full[#{container}]: #{information}", colspan: 7 }]
+ end
rows << :separator
rows << [{ value: " *** Contents ***", colspan: 7 }]
@@ -2637,7 +2786,7 @@ module ELoot # Game utility type methods
end
unless ELoot.data.gauntlet.nil?
- lines = ELoot.get_command("look ##{ELoot.data.gauntlet.id}", /You are currently wearing the eonake gauntlet/, silent: true, quiet: true)
+ lines = ELoot.get_command("look ##{ELoot.data.gauntlet.id}", /You are currently wearing the eonake gauntlet<\/a>/, silent: true, quiet: true)
if lines.any? { |l| l =~ /(right|left) hand/ }
gauntlet_hand = Regexp.last_match(1)
end
@@ -3022,7 +3171,7 @@ module ELoot # Game utility type methods
balance = 0
lines = ELoot.get_command("check balance", /(?:The|A prim) teller/, silent: true, quiet: true)
- if lines.find { |line| line.match(/Your balance is currently at (?[\d,]+)/) }
+ if lines.find { |line| line.match(/(?:Your balance is currently at |his temple for a moment. ")(?[\d,]+)/) }
balance = Regexp.last_match[:silver].gsub(',', '').to_i
end
@@ -3045,8 +3194,8 @@ module ELoot # Game utility type methods
# deposit the note and then attempt to withdraw the amount of silver needed
Inventory.drag(note)
- lines = ELoot.get_command("deposit ##{note.id}", /You (?:deposit|hand your)/, silent: true, quiet: true)
- break if lines.find { |line| line.match(/worth (?[\d,]+)/) }.nil?
+ lines = ELoot.get_command("deposit ##{note.id}", /You (?:deposit|hand your)|takes your/, silent: true, quiet: true)
+ break if lines.find { |line| line.match(/(?:worth|for) (?[\d,]+)/) }.nil?
note_amount = Regexp.last_match[:silver].gsub(',', '').to_i
withdraw_amount = note_amount >= amount ? amount : note_amount
dothistimeout("withdraw #{withdraw_amount} silver", 2, /The teller/)
@@ -3345,8 +3494,12 @@ module ELoot # Inventory methods
return unless ELoot.data.settings[:keep_closed]
Inventory.open_single_container(StowList.stow_list[:default])
- Inventory.open_single_container(StowList.stow_list[:overflow_container])
- Inventory.open_single_container(StowList.stow_list[:secondary_overflow])
+
+ # Dynamically open all overflow containers
+ overflow_keys = StowList.stow_list.keys.select { |k| k.to_s.start_with?('overflow_container') }
+ overflow_keys.each do |key|
+ Inventory.open_single_container(StowList.stow_list[key])
+ end
containers = Array.new
item.each { |loot|
@@ -3433,32 +3586,39 @@ module ELoot # Inventory methods
return if item&.name == "Empty"
return if Inventory.single_drag_box(item)
- # Try sacks in order of priority: item-specific, default, overflow, secondary overflow
+ # Try sacks in order of priority: item-specific, default, overflow containers (in order)
containers = [
StowList.stow_list[item.type.to_sym],
- StowList.stow_list[:default],
- StowList.stow_list[:overflow_container],
- StowList.stow_list[:secondary_overflow]
+ StowList.stow_list[:default]
]
+ # Dynamically add all overflow containers in order
+ overflow_keys = StowList.stow_list.keys.select { |k| k.to_s.start_with?('overflow_container') }.sort_by do |k|
+ # Sort by extracting number from key (overflow_container = 0, overflow_container_2 = 2, etc.)
+ k.to_s.match(/overflow_container_?(\d*)$/)[1].to_i
+ end
+ overflow_keys.each { |key| containers << StowList.stow_list[key] }
+
begin
containers.each_with_index do |bag, index|
if stunned?
ELoot.wait_rt
raise
end
- next if ELoot.data.sacks_full.include?(bag)
+ next if bag && ELoot.data.sacks_full.keys.include?(bag.name)
if bag.nil?
case index
+ when 0
+ # Skip if item-specific container not set (this is normal)
when 1
ELoot.msg(type: "yellow", text: " No default container identified. This shouldn't happen.")
ELoot.msg(type: "yellow", text: " Check your STOW settings. Exiting")
exit
- when 2
- ELoot.msg(type: "info", text: " Skipping primary overflow. No container identified.")
- when 3
- ELoot.msg(type: "info", text: " Skipping secondary overflow. No container identified.")
+ else
+ # Overflow container not identified (this is normal if not all overflow containers are set)
+ overflow_num = index - 1
+ ELoot.msg(type: "info", text: " Skipping overflow container #{overflow_num}. No container identified.")
end
else
result = Inventory.store_item(bag, item)
@@ -3478,6 +3638,11 @@ module ELoot # Inventory methods
if Room.current.tags.any?(/locksmith|locksmith pool/i) && (gold_ingot = [GameObj.right_hand, GameObj.left_hand].find { |obj| obj.name =~ /gold ingot/ })
Sell.handle_ingot(gold_ingot)
else
+ if ELoot.data.sacks_full.keys.count > 1
+ ELoot.data.sacks_full.each do |container, information|
+ ELoot.msg(type: "info", text: " Sacks Full[#{container}]: #{information}")
+ end
+ end
ELoot.msg(type: "info", text: " Failed to store the #{item.name}.")
ELoot.msg(type: "info", text: " Pausing the script to handle it yourself")
ELoot.msg(type: "info", text: " ;unpause #{Script.current.name} after addressing to continue!")
@@ -3501,7 +3666,9 @@ module ELoot # Inventory methods
ELoot.wait_for_disk unless ELoot.data.disk.nil?
# sort to prioritize characters disk
- disks = Group.disks.sort_by { |d| d.name == Char.name ? 0 : 1 }
+ disks = Group.disks
+ disks = disks.select { |d| d.name == Char.name } unless ELoot.data.settings[:use_disk_group]
+ disks.sort_by! { |d| d.name == Char.name ? 0 : 1 }
disks.each do |disk|
next if ELoot.data.disk_full[disk.name] # make sure its not full
next unless Disk.find_by_name(disk.name) # skip the disk unless its present
@@ -3524,9 +3691,9 @@ module ELoot # Inventory methods
# loot item will fallback to the default sack but if both are full we need to loot manually
bag = StowList.stow_list[item.type.to_sym]
- bag = nil if bag.nil? || ELoot.data.sacks_full.include?(bag)
+ bag = nil if bag.nil? || ELoot.data.sacks_full.keys.include?(bag.name)
bag ||= StowList.stow_list[:default]
- bag = nil if bag.nil? || ELoot.data.sacks_full.include?(bag)
+ bag = nil if bag.nil? || ELoot.data.sacks_full.keys.include?(bag.name)
unless bag
Inventory.single_drag(item)
@@ -3580,7 +3747,10 @@ module ELoot # Inventory methods
lines = ELoot.get_command("_drag ##{item.id} ##{bag.id}", ELoot.data.put_regex)
end
- return true if lines.any? { |l| l =~ /You are unable to handle|That is not yours|Hey, that belongs to|Get what|I could not find what you were referring/ }
+ lines.each do |line|
+ return false if line.match?(/Hey, that belongs to/)
+ return true if line.match?(/You are unable to handle|That is not yours|Get what|I could not find what you were referring/)
+ end
if lines.any? { |l| l =~ /put something that you can't hold/ }
ELoot.unlootable(item)
@@ -3591,7 +3761,7 @@ module ELoot # Inventory methods
if lines.any? { |l| l =~ /won't fit/i }
unless item.name =~ /gold ingot/
ELoot.msg(type: "debug", text: "sacks_full(#{bag.name}) - item: #{item.inspect}")
- ELoot.data.sacks_full.push(bag)
+ ELoot.data.sacks_full[bag.name] = [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, "#{item.name}(#{item.id})"]
end
return false
end
@@ -4245,8 +4415,17 @@ module ELoot # Gem and Reagent hoarding
ELoot.data.items_to_hoard = []
obj_type = ELoot.data.hoard_type == 'alchemy' ? 'reagent' : ELoot.data.hoard_type
+ # Get containers from the container_settings array
item_containers = ELoot.data.container_settings.filter_map { |key| StowList.stow_list[key.to_sym] }
+ # If use_overflow is enabled, dynamically add all overflow containers
+ use_overflow_key = "#{ELoot.data.hoard_type}_horde_use_overflow".to_sym
+ if ELoot.data.settings[use_overflow_key]
+ overflow_keys = StowList.stow_list.keys.select { |k| k.to_s.start_with?('overflow_container') }
+ overflow_containers = overflow_keys.filter_map { |key| StowList.stow_list[key] }
+ item_containers.concat(overflow_containers)
+ end
+
item_containers.each do |container|
next unless container
@@ -4254,7 +4433,7 @@ module ELoot # Gem and Reagent hoarding
ELoot.data.items_to_hoard.concat(container.contents.to_a)
end
- return ELoot.data.items_to_hoard.select { |item| item.name =~ /#{single}/ } if single
+ return ELoot.data.items_to_hoard.select { |item| item.name =~ /#{single}/ && item.type =~ /#{obj_type}/ } if single
ELoot.data.items_to_hoard.reject! { |item| item.type !~ /#{obj_type}/ }
@@ -4334,7 +4513,7 @@ module ELoot # Gem and Reagent hoarding
if bottle
3.times do
- Inventory.drag(bottle)
+ Inventory.drag(bottle, 'left')
break if ELoot.in_hand?(bottle)
# assuming if we are still here and its a locker it reset on us
if ELoot.data.locker || ELoot.data.use_house_locker
@@ -4345,7 +4524,7 @@ module ELoot # Gem and Reagent hoarding
jar = [GameObj.right_hand, GameObj.left_hand].find { |i| i.noun =~ /^(?:jar|bottle|beaker)$/ }
elsif empty
3.times do
- Inventory.drag(empty)
+ Inventory.drag(empty, 'left')
break if ELoot.in_hand?(empty)
# assuming if we are still here and its a locker it reset on us
if ELoot.data.locker || ELoot.data.use_house_locker
@@ -4376,7 +4555,7 @@ module ELoot # Gem and Reagent hoarding
items_to_hoard.each do |thing|
thing_name = Hoard.normalize_name(thing.name)
- Inventory.drag(thing)
+ Inventory.drag(thing, 'right')
result = ELoot.get_res("_drag ##{thing.id} ##{jar.id}", /You (add|put)|The.*?is full/)
@@ -4563,7 +4742,7 @@ module ELoot # Room looting
box_list.each do |box|
line = ELoot.get_res("open ##{box.id}", /open|locked/)
- next if line&.match?(/That is locked/)
+ next if line&.match?(/It appears to be locked/)
quiet_msg = ELoot.data.settings[:display_box_contents] ? false : true
ELoot.get_command("look in ##{box.id}", ELoot.data.look_regex, silent: quiet_msg, quiet: quiet_msg)
@@ -4646,7 +4825,7 @@ module ELoot # Room looting
items_opened = Array.new
items.each { |item|
item_type = item.type.to_sym
- if StowList.stow_list[item_type] && !ELoot.data.sacks_full.include?(StowList.stow_list[item_type])
+ if StowList.stow_list[item_type] && !ELoot.data.sacks_full.keys.include?(StowList.stow_list[item_type].name)
bag = StowList.stow_list[item_type]
else
bag = StowList.stow_list[:default]
@@ -4909,7 +5088,7 @@ module ELoot # Room looting
# Loot it
3.times do
waitrt?
- results = ELoot.get_command("loot ##{thing.id}", /You (search|plunge|break)|not in any condition|see well enough to search|You can only loot creatures|Geez! It's still alive! Not a good time for that\./, silent: false, quiet: false)
+ results = ELoot.get_command("loot ##{thing.id}", /You (search|plunge|break|tentatively)|not in any condition|see well enough to search|You can only loot creatures|Geez! It's still alive! Not a good time for that\.|As you move to search/, silent: false, quiet: false)
ELoot.msg(type: "debug", text: "Thing: #{thing.id}-#{thing.name}, Results: #{results.first}")
if results.any? { |line| line =~ /not in any condition/ } &&
@@ -4930,7 +5109,7 @@ module ELoot # Room looting
end
end
- break if results.any? { |line| line =~ /You (search|plunge|break)|not in any condition|see well enough to search|You can only loot creatures|Geez! It's still alive! Not a good time for that\./ } ||
+ break if results.any? { |line| line =~ /You (search|plunge|break|tentatively)|not in any condition|see well enough to search|You can only loot creatures|Geez! It's still alive! Not a good time for that\./ } ||
thing.nil? || thing.status =~ /gone/
end
@@ -5067,6 +5246,12 @@ module ELoot # Room looting
ELoot.data.settings[:critter_exclude].length.positive? && obj.name =~ Regexp.union(ELoot.data.settings[:critter_exclude])
end
+ if ELoot.data.settings[:skin_bounty_only]
+ return unless Bounty.task.skin?
+ bounty_creature = Bounty.task.creature.to_s.downcase
+ objs = objs.select { |obj| obj.name.to_s.downcase.include?(bounty_creature) }
+ end
+
return if objs.empty?
blunts = objs.find_all { |obj| obj.name =~ /krynch|stone mastiff|krag dweller|cavern urchin/i }
@@ -5733,14 +5918,15 @@ module ELoot # Sells the loot
end
def self.dump_herbs_junk
- # Determine which types of loot we are supposed to dump
- dump_stuff = ["herb", "junk", "food"].select { |type| ELoot.data.settings[:sell_loot_types].include?(type) }
+ # Determine which types of loot we are supposed to dump based on trash_dump_types setting
+ dump_stuff = ELoot.data.settings[:trash_dump_types].select { |type| ELoot.data.settings[:sell_loot_types].include?(type) }
alchemy_regex = /^(some ground|flask of pure water|some powdered|some mashed|handful of sea salt|spirit shard|tincture of)/
# Collect items to dump
dump_items = ELoot.set_selling_containers.flat_map(&:contents).select do |item|
next false unless dump_stuff.any? { |type| item.type =~ /#{type}/ } || (ELoot.data.alchemy_mode && item.name =~ alchemy_regex)
next false if ELoot.data.alchemy_mode && Vars.needed_reagents.any? { |r| item.name =~ /#{r}/ }
+ next false if !ELoot.data.settings[:sell_exclude].empty? && item.name =~ /#{ELoot.data.settings[:sell_exclude].join('|')}/
true
end
@@ -6134,7 +6320,7 @@ module ELoot # Sells the loot
ELoot.data.settings[:between].each do |i|
tokens = i.split(/\s+/)
if (tokens.size > 1)
- Script.run(tokens[0], tokens[1..-1].join(", "))
+ Script.run(tokens[0], tokens[1..-1].join(" "))
else
Script.run(tokens[0])
end
@@ -6235,13 +6421,7 @@ module ELoot # Sells the loot
# if we're here, assume we will empty out the disk
ELoot.reset_disk_full
- if boxes.length.positive? && ELoot.data.settings[:use_standard_tipping]
- amount = ELoot.data.settings[:locksmith_withdraw_amount]
- ELoot.silver_withdraw(amount)
- end
-
ELoot.go2('locksmith pool')
- original_pool = Room.current.id
worker = ELoot.find_worker
# if using incremental tipping, need to find out how many boxes are in the pool
@@ -6250,11 +6430,6 @@ module ELoot # Sells the loot
if pool_count > 99
pool_count = handle_full_pool(worker) { return true if deposit }
return if pool_count > 99
- else
- total_tips = Sell.locksmith_determine_tip(pool_count + 1, boxes.length) + 15_000
- ELoot.silver_withdraw(total_tips)
- ELoot.go2(original_pool)
- worker = ELoot.find_worker
end
end
@@ -6294,9 +6469,7 @@ module ELoot # Sells the loot
pool_count = handle_full_pool(worker) { return true if deposit }
end
when /You don't have that much/
- ELoot.silver_withdraw(ELoot.data.settings[:locksmith_withdraw_amount])
- ELoot.go2(original_pool)
- redo_needed = true
+ redo_needed = false
when /already holding as many boxes/
Inventory.single_drag(box) unless box_in_hand
pool_count = handle_full_pool(worker) { return true if deposit }
@@ -6553,7 +6726,7 @@ module ELoot # Sells the loot
def self.process_boxes
boxes = ELoot.find_boxes
- return unless boxes.any?
+ return unless boxes.any? || ELoot.data.settings[:always_check_pool]
ELoot.msg(type: "debug", text: "length: #{boxes.length}")
@@ -6714,14 +6887,14 @@ module ELoot # Starts the script
# Initialize/Load settings
unless ELoot.data && ELoot.data.respond_to?(:version) && ELoot.data.version == ELoot.get_script_version
waitrt?
- ELoot.load(ELoot.load_profile())
+ ELoot.load(ELoot.load_profile)
ELoot.set_inventory
ELoot.disk_usage
exit if Script.current.vars[0] =~ /load/
end
if !ELoot.data.settings[:track_full_sacks]
- ELoot.data.sacks_full = []
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
ELoot.reset_disk_full
end
@@ -6799,7 +6972,7 @@ module ELoot # Starts the script
ELoot.wait_rt
# Set bags as empty to avoid false full status
- ELoot.data.sacks_full = []
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
if Script.current.vars[2] == "alchemy_mode"
ELoot.data.alchemy_mode = true
@@ -6809,7 +6982,7 @@ module ELoot # Starts the script
ELoot.sell
# Reset bags to empty after all the selling is done
- ELoot.data.sacks_full = []
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
ELoot.go2(ELoot.data.start_room)
ELoot::Sell.breakdown
@@ -6818,6 +6991,8 @@ module ELoot # Starts the script
ELoot.data.debug_logger = ELoot::DebugLogger.new if ELoot.data.settings[:debug_file]
arg = Script.current.vars[2]
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
+
if arg.nil?
check = true
deposit = true
@@ -6829,16 +7004,23 @@ module ELoot # Starts the script
ELoot.disk_usage
ELoot::Sell.pool(deposit: deposit, check: check)
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
+
ELoot::Sell.breakdown
when /--(sellable|type|sell)\b\s*=?\s*(\/?[a-zA-Z,\s|]+\/?)/
ELoot.data.debug_logger = ELoot::DebugLogger.new if ELoot.data.settings[:debug_file]
type = Regexp.last_match(1)
things = Regexp.last_match(2)
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
+ ELoot::Sell.box_in_hand(false)
+
ELoot::Sell.custom_sellable(things) if type == 'sellable'
ELoot::Sell.custom_type(things) if type == 'type'
ELoot::Sell.custom_list(things) if type == 'sell'
+ ELoot.data.sacks_full = { "last cleared" => [Time.now.strftime('%Y-%m-%d %H:%M:%S'), Room.current.id, Script.current.vars[0]] }
+
ELoot.go2(ELoot.data.start_room)
ELoot::Sell.breakdown
when /settings|setup/i