From 84e4d39c7105aff883662a15f83b4251cb216157 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Tue, 27 Jan 2026 22:07:57 -0500
Subject: [PATCH 01/40] fix(eloot.lic): v2.7.1 multiple fixes
- 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
---
scripts/eloot.lic | 133 ++++++++++++++++++++++++++++++++++------------
1 file changed, 99 insertions(+), 34 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index e670d866a..30fbdac08 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -15,9 +15,12 @@
game: Gemstone
tags: loot
required: Lich >= 5.12.9
- version: 2.7.0
+ version: 2.7.1
Improvements:
Major_change.feature_addition.bugfix
+ v2.7.1 (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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -622,8 +625,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 },
@@ -743,6 +745,7 @@ 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 },
@@ -948,11 +951,9 @@ module ELoot # UI Setup
0001
20240411
- FalseTrue1TrueFalseOther Settings002FalseTrue3
- 3TrueFalseSelling3FalseTrueTrueinTrueFalseTrueFalse10150150TrueFalse50TrueFalsecenter5525Add80TrueTrueTruestart5
+ TrueFalse100TrueFalse5525TrueAlchemyTrueTrueFalsestart5True00FoodTrueTrueFalsestartTrue10Locksmith TrapsTrueTrueFalsestartTrue20BoxTrueTrueFalsestartTrue30HerbTrueTrueFalsestart5True01ReagentTrueTrueFalsestartTrue11WandTrueTrueFalsestartTrue21BreakableTrueTrueFalsestartTrue31ClothingTrueTrueFalsestart5True02JunkTrueTrueFalsestartTrue12LockpickTrueTrueFalsestartTrue22TrueFalseTrash to DumpFalseTrue43TrueFalseSelling3FalseTrueTrueinTrueFalseTrueFalse10150150TrueFalse50TrueFalsecenter5525Add80TrueTrueTruestart5
00Delete80TrueTrueTrueend520
TrueTrueTrueEnter exclusion (e.g. uncut diamond)10200TrueTrue5555TrueinTrueFalseTrueTruesell_exclude_storeFalse0True
fixedExclusion0013TrueFalseExclusions (?)
@@ -1302,6 +1303,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 +1505,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
@@ -1757,6 +1763,26 @@ module ELoot # Profile loading/saving and settings
@@data = Data.new(settings)
end
+ def self.migrate_overflow_settings(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)
+ end
+
+ settings
+ end
+
def self.load_defaults()
default_hash = {
:loot_types => ["alchemy", "armor", "box", "breakable", "clothing", "collectible", "food", "gem", "jewelry", "lockpick", "lm trap", "magic", "reagent", "scroll", "skin", "uncommon", "valuable", "wand"],
@@ -1767,8 +1793,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,6 +1816,7 @@ 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,
@@ -1824,6 +1850,8 @@ module ELoot # Profile loading/saving and settings
filename = File.join(DATA_DIR, XMLData.game, name, "eloot.yaml")
if File.exist?(filename) && name == Char.name
settings_hash = YAML.load_file(filename)
+ # Migrate old overflow settings to new format
+ settings_hash = ELoot.migrate_overflow_settings(settings_hash)
elsif !File.exist?(filename) && name != Char.name
ELoot.msg(type: "error", text: " ELoot.load_profile: Attempt to load a profile that does not exist.")
elsif !File.exist?(filename) && name == Char.name
@@ -2026,11 +2054,26 @@ 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 == :appraisal_container }
+
+ # 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
@@ -2090,10 +2133,10 @@ module ELoot # Sets Inventory
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
@@ -2107,8 +2150,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 +2159,26 @@ module ELoot # Sets Inventory
[:charm_name, ELoot.data.charm, "fossil charm"],
]
+ # 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]
+ end
+ end
+
checks.each do |setting_key, found_obj, label, conditional_key|
# 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 = setting_key == :overflow_containers ? label.split(' ').last : ELoot.data.settings[setting_key]
+ ELoot.msg(text: " Not able to find the #{label}: #{container_name}")
need_exit = true
end
end
@@ -3345,8 +3399,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,14 +3491,19 @@ 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?
@@ -3451,14 +3514,16 @@ module ELoot # Inventory methods
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)
@@ -5733,8 +5798,8 @@ 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
From a71929d37ca0293ac5fc30ff0a5063e0ced2a9bf Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 28 Jan 2026 09:29:28 -0500
Subject: [PATCH 02/40] fix: add tooltip to new trash to dump section
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 30fbdac08..6a09da382 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -1062,7 +1062,7 @@ module ELoot # UI Setup
Share silversTrueTrueFalsestart55True20
TrueTruestart305300sell_keep_silver_adjustmentTrue312
TrueFalseOther Settings002FalseTrue3
- TrueFalse100TrueFalse5525TrueAlchemyTrueTrueFalsestart5True00FoodTrueTrueFalsestartTrue10Locksmith TrapsTrueTrueFalsestartTrue20BoxTrueTrueFalsestartTrue30HerbTrueTrueFalsestart5True01ReagentTrueTrueFalsestartTrue11WandTrueTrueFalsestartTrue21BreakableTrueTrueFalsestartTrue31ClothingTrueTrueFalsestart5True02JunkTrueTrueFalsestartTrue12LockpickTrueTrueFalsestartTrue22TrueFalseTrash to DumpFalseTrue43TrueFalseSelling3FalseTrueTrueinTrueFalseTrueFalse10150150TrueFalse50TrueFalsecenter5525Add80TrueTrueTruestart5
+ 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 (?)
From bf474dfa4b5df2717aaf5957cb857faa948c5f63 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 30 Jan 2026 09:42:59 -0500
Subject: [PATCH 03/40] fix: between script(s) added erroneous commas between
script parameters
---
scripts/eloot.lic | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 6a09da382..a0b321074 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -21,6 +21,7 @@
v2.7.1 (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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -6199,7 +6200,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
From fe6a9655a4ca41e620a04ebca227b046157a8e22 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 30 Jan 2026 16:32:09 -0500
Subject: [PATCH 04/40] fix rubocop
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index a0b321074..be5f314f7 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -21,7 +21,7 @@
v2.7.1 (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
+ - bugfix inbetween script(s) added erroneous commas between script parameters
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
From bdb422bb488150a1f7d83f90f0e8805895db0542 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Sat, 31 Jan 2026 20:04:53 -0500
Subject: [PATCH 05/40] fix: update gem/alchemy to support new overflow
structure
force saving of migrated settings for overflow upon migration
---
scripts/eloot.lic | 57 ++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 49 insertions(+), 8 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index be5f314f7..c263667f2 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -806,7 +806,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 },
@@ -859,7 +860,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 },
@@ -1101,9 +1103,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
@@ -1130,9 +1131,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
@@ -1765,6 +1765,7 @@ module ELoot # Profile loading/saving and settings
end
def self.migrate_overflow_settings(settings)
+ migrated_settings = false
# Migration helper: Convert old overflow_container and secondary_overflow to new overflow_containers format
if settings.key?(:overflow_container) || settings.key?(:secondary_overflow)
containers = []
@@ -1779,8 +1780,39 @@ module ELoot # Profile loading/saving and settings
# 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
+
+ ELoot.save_profile() if migrated_settings
settings
end
@@ -4311,8 +4343,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
From 967cef513a218dc2c1db3c735b1c21913817d224 Mon Sep 17 00:00:00 2001
From: Deysh <61760541+Deysh@users.noreply.github.com>
Date: Sun, 1 Feb 2026 06:33:47 -0500
Subject: [PATCH 06/40] Modify total tips calculation for locksmith
Updated the total tips calculation to include a custom withdraw amount setting for the locksmith.
---
scripts/eloot.lic | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index c263667f2..eed54b124 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -22,6 +22,7 @@
- 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 tip amount
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -981,7 +982,7 @@ module ELoot # UI Setup
00Use 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
@@ -6358,7 +6359,7 @@ module ELoot # Sells the loot
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
+ total_tips = Sell.locksmith_determine_tip(pool_count + 1, boxes.length) + ELoot.data.settings[:locksmith_withdraw_amount]
ELoot.silver_withdraw(total_tips)
ELoot.go2(original_pool)
worker = ELoot.find_worker
From 79c926e7d331ecdd73cb21ed1e2bb32b0b358ae8 Mon Sep 17 00:00:00 2001
From: Deysh <61760541+Deysh@users.noreply.github.com>
Date: Sun, 1 Feb 2026 07:33:54 -0500
Subject: [PATCH 07/40] bugfix for box group looting msg and box disk storage
---
scripts/eloot.lic | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index eed54b124..1c66694bf 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -22,7 +22,10 @@
- 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 tip amount
+ - 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -3600,6 +3603,7 @@ module ELoot # Inventory methods
ELoot.wait_for_disk unless ELoot.data.disk.nil?
# sort to prioritize characters disk
+ disks = disks.select { |d| d.name == Char.name } unless ELoot.data.settings[:use_disk_group]
disks = 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
@@ -3679,7 +3683,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)
@@ -4671,7 +4678,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)
From f5a8a1c5e669bb9d62c6ac658838b6e96879cd2d Mon Sep 17 00:00:00 2001
From: Deysh <61760541+Deysh@users.noreply.github.com>
Date: Sun, 1 Feb 2026 07:44:44 -0500
Subject: [PATCH 08/40] Refactor disk sorting to use sort_by! method and
rubocop
---
scripts/eloot.lic | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 1c66694bf..aa61b91c1 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -3603,8 +3603,9 @@ module ELoot # Inventory methods
ELoot.wait_for_disk unless ELoot.data.disk.nil?
# sort to prioritize characters disk
+ disks = Group.disks
disks = disks.select { |d| d.name == Char.name } unless ELoot.data.settings[:use_disk_group]
- disks = Group.disks.sort_by { |d| d.name == Char.name ? 0 : 1 }
+ 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
From c47f050d173f0248ab692d650d729130ceeadf79 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 4 Feb 2026 16:35:02 -0500
Subject: [PATCH 09/40] fix: bugfix for eonake gauntlet missing XML to properly
match
---
scripts/eloot.lic | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index aa61b91c1..68a4ad5e5 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -26,6 +26,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -2728,7 +2729,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
From fe806e86e86795c976b3ad04307e4b8e1b1d74a5 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Thu, 5 Feb 2026 09:31:15 -0500
Subject: [PATCH 10/40] fix: refactor in_region method and fix bug in
destination check
Refactor in_region method to improve boundary check logic and add a bugfix for destination room check.
---
scripts/eloot.lic | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 68a4ad5e5..b9aa2411d 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -27,6 +27,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -2276,9 +2277,20 @@ module ELoot # Regional bounty Selling
self.by_town(tag).find { |k, _v| k.downcase.include?(town.downcase) }.last
end
- def self.in_region(place) # Determine if the bounty town is within the characters region
+ def self.in_region(place)
ELoot.msg(type: "debug", text: "place: #{place}")
- # vaalor ferry, west cart, east cart, RR boot
+
+ bounty_town = Bounty.town == "Cold River" ? "Hinterwilds" : Bounty.town
+ place = self.tag_for_town(bounty_town, place).id
+
+ # Early return if already at destination
+ return place if Room.current == 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
@@ -2296,12 +2308,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
From 2287bf0527cae3e4ce94b3b6cac08fe7c8efc28c Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Thu, 5 Feb 2026 09:32:22 -0500
Subject: [PATCH 11/40] docs: add clarification comment in in_region method
Add comment to clarify bounty town region check
---
scripts/eloot.lic | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index b9aa2411d..f92aefb25 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2277,6 +2277,7 @@ module ELoot # Regional bounty Selling
self.by_town(tag).find { |k, _v| k.downcase.include?(town.downcase) }.last
end
+ # Determine if the bounty town is within the characters region
def self.in_region(place)
ELoot.msg(type: "debug", text: "place: #{place}")
From 0b215b2e2591093778ec8afdbfe1579c177684aa Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Thu, 5 Feb 2026 09:34:21 -0500
Subject: [PATCH 12/40] refactor: string comparison for bounty town and current
room
---
scripts/eloot.lic | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index f92aefb25..4dd538e3e 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2278,14 +2278,15 @@ module ELoot # Regional bounty Selling
end
# 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}")
- bounty_town = Bounty.town == "Cold River" ? "Hinterwilds" : Bounty.town
+ bounty_town = Bounty.town.eql?("Cold River") ? "Hinterwilds" : Bounty.town
place = self.tag_for_town(bounty_town, place).id
# Early return if already at destination
- return place if Room.current == Room[place]
+ return place if Room.current.eql?(Room[place])
# Calculate path once
path = Room.current.path_to(Room[place])
From 8cd39f00dc44dabdb64dde6380a777df57336cd7 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Sat, 7 Feb 2026 11:27:26 -0500
Subject: [PATCH 13/40] fix: reset sacks full when using --sellable/type/sell
CLI
---
scripts/eloot.lic | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 4dd538e3e..8087fd9eb 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -28,6 +28,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -6962,10 +6963,15 @@ module ELoot # Starts the script
type = Regexp.last_match(1)
things = Regexp.last_match(2)
+ ELoot.data.sacks_full = []
+ 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 = []
+
ELoot.go2(ELoot.data.start_room)
ELoot::Sell.breakdown
when /settings|setup/i
From 014aa4d4419ebfb16169bcb6ba6ca8c9c373befd Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Sun, 8 Feb 2026 14:51:21 -0500
Subject: [PATCH 14/40] fix: LOOT match for quest corpse looting
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 8087fd9eb..9cf42db36 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -5037,7 +5037,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)|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/ } &&
From c6b2e672ac85ece3ff11e79b6c190aebcb47f136 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 9 Feb 2026 16:06:46 -0500
Subject: [PATCH 15/40] fix: dump/trash to respect sell_exclude items
---
scripts/eloot.lic | 1 +
1 file changed, 1 insertion(+)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 9cf42db36..f1c3c8fb7 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -5869,6 +5869,7 @@ module ELoot # Sells the loot
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
From 2244b73302b2008719f3d936bba5aa5383dbd5a2 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 16 Feb 2026 19:17:37 -0500
Subject: [PATCH 16/40] fix: add hoarding of specific valuable items, expand
sacks_full debug output
---
scripts/eloot.lic | 126 ++++++++++++++++++++++++++++++++--------------
1 file changed, 89 insertions(+), 37 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index f1c3c8fb7..f83f03bb1 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -29,6 +29,7 @@
- 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
+ - update hoard gems to support specific valuable types (shell/tooth)
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -256,7 +257,7 @@ module ELoot # Data
# inventory type
@sacks_closed = []
- @sacks_full = []
+ @sacks_full = {}
@checked_bags = []
@sell_containers = []
@ready_lines = []
@@ -2556,7 +2557,7 @@ 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 }]
+ rows << [{ value: "Sacks Full: #{ELoot.data.sacks_full}", colspan: 7 }]
rows << :separator
rows << [{ value: " *** Contents ***", colspan: 7 }]
@@ -3559,7 +3560,7 @@ module ELoot # Inventory methods
ELoot.wait_rt
raise
end
- next if ELoot.data.sacks_full.include?(bag)
+ next if ELoot.data.sacks_full.keys.include?(bag.name)
if bag.nil?
case index
@@ -3595,7 +3596,7 @@ module ELoot # Inventory methods
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!")
-
+ ELoot.msg(type: "debug", text: " Sacks Full: #{ELoot.data.sacks_full}") unless ELoot.data.sacks_full.empty?
Script.current.pause
end
end
@@ -3640,9 +3641,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)
@@ -3710,7 +3711,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, item]
end
return false
end
@@ -3812,25 +3813,47 @@ module ELoot # Gem and Reagent hoarding
def self.check_type(item)
obj_type = ELoot.data.hoard_type == 'alchemy' ? 'reagent' : ELoot.data.hoard_type
-
+
item = item.gsub(/teeth/, "tooth")
noun = item.split.last
-
- if item =~ GameObj.type_data[obj_type][:exclusion]
- return false
- elsif GameObj.type_data[obj_type][:name].to_s.match?(/\b#{item}\b/) || GameObj.type_data[obj_type][:noun].to_s.match?(/\b#{noun}\b/)
- return true
- elsif item =~ GameObj.type_data[obj_type][:name] || noun =~ GameObj.type_data[obj_type][:noun]
- return true
- elsif obj_type == 'reagent' && Room.list.any? { |r| r.tags.any? { |tag| (tag.end_with? item) || ((item.start_with? tag) && item =~ /ayana/) || (item.end_with? tag) } }
- return true
- elsif obj_type == 'reagent' && item =~ /kezmonian honey beryl|faintly glimmering dust/i
- return true
- elsif obj_type == 'gem' && item =~ /(?:deep blue sapphire|fiery ruby|glistening onyx|sparkling emerald) talon/i
- return true
- else
- return false
- end
+
+ # Cache the lookup - accessed multiple times
+ type_data = GameObj.type_data[obj_type]
+
+ # Early return on exclusion
+ return false if type_data[:exclusion]&.match?(item)
+
+ # Check standard name/noun matches
+ return true if type_data[:name]&.match?(item) || type_data[:noun]&.match?(noun)
+
+ # Reagent-specific checks
+ if obj_type == 'reagent'
+ return true if Room.list.any? { |r| r.tags.any? { |tag| tag.end_with?(item) || (item.start_with?(tag) && item.match?(/ayana/)) || item.end_with?(tag) } }
+ return true if item.match?(/kezmonian honey beryl|faintly glimmering dust/i)
+ end
+
+ # Gem-specific checks
+ if obj_type == 'gem'
+ return true if item.match?(/(?:deep blue sapphire|fiery ruby|glistening onyx|sparkling emerald) talon/i)
+
+ if %w[shell tooth].include?(noun)
+ valuable_data = GameObj.type_data["valuable"]
+ return true if valuable_data[:name]&.match?(item) || valuable_data[:noun]&.match?(noun)
+ end
+ end
+
+ false
+ end
+
+ # Helper method to check if an item is a gem or gem-like valuable (shell/tooth)
+ def self.gem_or_valuable?(item)
+ return true if item.type =~ /gem/
+ return false unless item.type =~ /valuable/
+
+ # Check if it's a shell or tooth
+ item_name = item.is_a?(GameObj) ? item.name : item.to_s
+ noun = item_name.split.last
+ %w[shell tooth].include?(noun)
end
def self.normalize_name(name)
@@ -4288,8 +4311,19 @@ module ELoot # Gem and Reagent hoarding
# Refresh the cache because lockers are special
ELoot.get_command("look in ##{ELoot.data.stash.id}", /
Date: Mon, 16 Feb 2026 19:22:52 -0500
Subject: [PATCH 17/40] fix: rubocop
---
scripts/eloot.lic | 30 +++++++++++++++---------------
1 file changed, 15 insertions(+), 15 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index f83f03bb1..c4180e35b 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -3813,35 +3813,35 @@ module ELoot # Gem and Reagent hoarding
def self.check_type(item)
obj_type = ELoot.data.hoard_type == 'alchemy' ? 'reagent' : ELoot.data.hoard_type
-
+
item = item.gsub(/teeth/, "tooth")
noun = item.split.last
-
+
# Cache the lookup - accessed multiple times
type_data = GameObj.type_data[obj_type]
-
+
# Early return on exclusion
return false if type_data[:exclusion]&.match?(item)
-
+
# Check standard name/noun matches
return true if type_data[:name]&.match?(item) || type_data[:noun]&.match?(noun)
-
+
# Reagent-specific checks
if obj_type == 'reagent'
return true if Room.list.any? { |r| r.tags.any? { |tag| tag.end_with?(item) || (item.start_with?(tag) && item.match?(/ayana/)) || item.end_with?(tag) } }
return true if item.match?(/kezmonian honey beryl|faintly glimmering dust/i)
end
-
+
# Gem-specific checks
if obj_type == 'gem'
return true if item.match?(/(?:deep blue sapphire|fiery ruby|glistening onyx|sparkling emerald) talon/i)
-
+
if %w[shell tooth].include?(noun)
valuable_data = GameObj.type_data["valuable"]
return true if valuable_data[:name]&.match?(item) || valuable_data[:noun]&.match?(noun)
end
end
-
+
false
end
@@ -3849,7 +3849,7 @@ module ELoot # Gem and Reagent hoarding
def self.gem_or_valuable?(item)
return true if item.type =~ /gem/
return false unless item.type =~ /valuable/
-
+
# Check if it's a shell or tooth
item_name = item.is_a?(GameObj) ? item.name : item.to_s
noun = item_name.split.last
@@ -4318,10 +4318,10 @@ module ELoot # Gem and Reagent hoarding
elsif name =~ /teeth$/
search_names << name.sub(/teeth$/, 'tooth')
end
-
+
jar = ELoot.data.stash.contents.find do |obj|
- obj.noun =~ /^(?:jar|bottle|beaker)$/ &&
- search_names.any? { |n| Hoard.normalize_name(obj.after_name) =~ /^#{Regexp.escape(n)}$/i }
+ obj.noun =~ /^(?:jar|bottle|beaker)$/ &&
+ search_names.any? { |n| Hoard.normalize_name(obj.after_name) =~ /^#{Regexp.escape(n)}$/i }
end
ELoot.msg(type: "debug", text: "jar: #{jar.inspect} | search_names: #{search_names}")
@@ -4503,10 +4503,10 @@ module ELoot # Gem and Reagent hoarding
elsif item_name =~ /teeth$/
search_names << item_name.sub(/teeth$/, 'tooth')
end
-
+
bottle = ELoot.data.stash.contents.find do |obj|
- obj.noun =~ /^(?:jar|bottle|beaker)$/ &&
- search_names.any? { |name| Hoard.normalize_name(obj.after_name) =~ /^#{Regexp.escape(name)}$/i }
+ obj.noun =~ /^(?:jar|bottle|beaker)$/ &&
+ search_names.any? { |name| Hoard.normalize_name(obj.after_name) =~ /^#{Regexp.escape(name)}$/i }
end
ELoot.msg(type: "debug", text: "bottle: #{bottle.inspect} | search_names: #{search_names}")
From a4cbcabdc7bb6125fa9d0618083422f4be631761 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Tue, 17 Feb 2026 08:57:58 -0500
Subject: [PATCH 18/40] revert: hoard gem/valuable changes
---
scripts/eloot.lic | 95 +++++++++++------------------------------------
1 file changed, 22 insertions(+), 73 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index c4180e35b..bfcd35cea 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -29,7 +29,6 @@
- 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
- - update hoard gems to support specific valuable types (shell/tooth)
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -3597,6 +3596,7 @@ module ELoot # Inventory methods
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!")
ELoot.msg(type: "debug", text: " Sacks Full: #{ELoot.data.sacks_full}") unless ELoot.data.sacks_full.empty?
+
Script.current.pause
end
end
@@ -3817,43 +3817,21 @@ module ELoot # Gem and Reagent hoarding
item = item.gsub(/teeth/, "tooth")
noun = item.split.last
- # Cache the lookup - accessed multiple times
- type_data = GameObj.type_data[obj_type]
-
- # Early return on exclusion
- return false if type_data[:exclusion]&.match?(item)
-
- # Check standard name/noun matches
- return true if type_data[:name]&.match?(item) || type_data[:noun]&.match?(noun)
-
- # Reagent-specific checks
- if obj_type == 'reagent'
- return true if Room.list.any? { |r| r.tags.any? { |tag| tag.end_with?(item) || (item.start_with?(tag) && item.match?(/ayana/)) || item.end_with?(tag) } }
- return true if item.match?(/kezmonian honey beryl|faintly glimmering dust/i)
- end
-
- # Gem-specific checks
- if obj_type == 'gem'
- return true if item.match?(/(?:deep blue sapphire|fiery ruby|glistening onyx|sparkling emerald) talon/i)
-
- if %w[shell tooth].include?(noun)
- valuable_data = GameObj.type_data["valuable"]
- return true if valuable_data[:name]&.match?(item) || valuable_data[:noun]&.match?(noun)
- end
+ if item =~ GameObj.type_data[obj_type][:exclusion]
+ return false
+ elsif GameObj.type_data[obj_type][:name].to_s.match?(/\b#{item}\b/) || GameObj.type_data[obj_type][:noun].to_s.match?(/\b#{noun}\b/)
+ return true
+ elsif item =~ GameObj.type_data[obj_type][:name] || noun =~ GameObj.type_data[obj_type][:noun]
+ return true
+ elsif obj_type == 'reagent' && Room.list.any? { |r| r.tags.any? { |tag| (tag.end_with? item) || ((item.start_with? tag) && item =~ /ayana/) || (item.end_with? tag) } }
+ return true
+ elsif obj_type == 'reagent' && item =~ /kezmonian honey beryl|faintly glimmering dust/i
+ return true
+ elsif obj_type == 'gem' && item =~ /(?:deep blue sapphire|fiery ruby|glistening onyx|sparkling emerald) talon/i
+ return true
+ else
+ return false
end
-
- false
- end
-
- # Helper method to check if an item is a gem or gem-like valuable (shell/tooth)
- def self.gem_or_valuable?(item)
- return true if item.type =~ /gem/
- return false unless item.type =~ /valuable/
-
- # Check if it's a shell or tooth
- item_name = item.is_a?(GameObj) ? item.name : item.to_s
- noun = item_name.split.last
- %w[shell tooth].include?(noun)
end
def self.normalize_name(name)
@@ -4311,19 +4289,8 @@ module ELoot # Gem and Reagent hoarding
# Refresh the cache because lockers are special
ELoot.get_command("look in ##{ELoot.data.stash.id}", /
Date: Tue, 17 Feb 2026 09:17:02 -0500
Subject: [PATCH 19/40] fix: expand sacks_full info output
---
scripts/eloot.lic | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index bfcd35cea..41c32fcc3 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -256,7 +256,7 @@ module ELoot # Data
# inventory type
@sacks_closed = []
- @sacks_full = {}
+ @sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
@checked_bags = []
@sell_containers = []
@ready_lines = []
@@ -2556,7 +2556,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}", 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 }]
@@ -3592,10 +3594,12 @@ 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
+ ELoot.data.sacks_full.each do |container, information|
+ ELoot.msg(type: "info", text: " Sacks Full[#{container}]: #{information}")
+ end unless ELoot.data.sacks_full.empty?
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!")
- ELoot.msg(type: "debug", text: " Sacks Full: #{ELoot.data.sacks_full}") unless ELoot.data.sacks_full.empty?
Script.current.pause
end
@@ -3711,7 +3715,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[bag.name] = [Time.now, item]
+ ELoot.data.sacks_full[bag.name] = [Time.now, Room.current.id, item]
end
return false
end
@@ -6851,7 +6855,7 @@ module ELoot # Starts the script
end
if !ELoot.data.settings[:track_full_sacks]
- ELoot.data.sacks_full = {}
+ ELoot.data.sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
ELoot.reset_disk_full
end
@@ -6929,7 +6933,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, Room.current.id, Script.current.vars[0]] }
if Script.current.vars[2] == "alchemy_mode"
ELoot.data.alchemy_mode = true
@@ -6939,7 +6943,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, Room.current.id, Script.current.vars[0]] }
ELoot.go2(ELoot.data.start_room)
ELoot::Sell.breakdown
@@ -6965,14 +6969,14 @@ module ELoot # Starts the script
type = Regexp.last_match(1)
things = Regexp.last_match(2)
- ELoot.data.sacks_full = {}
+ ELoot.data.sacks_full = { "last cleared" => [Time.now, 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 = {}
+ ELoot.data.sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
ELoot.go2(ELoot.data.start_room)
ELoot::Sell.breakdown
From 4ab1d7d4caf45f3d562f5fe52d0c9279fed699a8 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 18 Feb 2026 14:54:55 -0500
Subject: [PATCH 20/40] fix: remove silver withdraw for pool
---
scripts/eloot.lic | 24 ++----------------------
1 file changed, 2 insertions(+), 22 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 41c32fcc3..56dc25e38 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -29,6 +29,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -6369,29 +6370,10 @@ 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
- if boxes.length.positive? && ELoot.data.settings[:use_incremental_tipping]
- pool_count = Sell.locksmith_pool_count(worker)
- 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) + ELoot.data.settings[:locksmith_withdraw_amount]
- ELoot.silver_withdraw(total_tips)
- ELoot.go2(original_pool)
- worker = ELoot.find_worker
- end
- end
-
Inventory.free_hands(both: true) unless [GameObj.right_hand, GameObj.left_hand].find { |hand| hand.type =~ /box/ }
ELoot.wait_for_disk
@@ -6428,9 +6410,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 }
From 5415732fc2b32b033ab734e45be081b935d24ddf Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 20 Feb 2026 10:00:12 -0500
Subject: [PATCH 21/40] fix: rubocop
---
scripts/eloot.lic | 1 -
1 file changed, 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 56dc25e38..d5913dfee 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -6371,7 +6371,6 @@ module ELoot # Sells the loot
ELoot.reset_disk_full
ELoot.go2('locksmith pool')
- original_pool = Room.current.id
worker = ELoot.find_worker
Inventory.free_hands(both: true) unless [GameObj.right_hand, GameObj.left_hand].find { |hand| hand.type =~ /box/ }
From a60d9f9670492d9e1a2c893ab3359983ac6bd233 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 23 Feb 2026 14:58:45 -0500
Subject: [PATCH 22/40] fix: process default/overflows first for boxes
---
scripts/eloot.lic | 19 +++++++++++++------
1 file changed, 13 insertions(+), 6 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index d5913dfee..ffc189fd9 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -30,6 +30,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -2163,12 +2164,6 @@ 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
@@ -2183,6 +2178,18 @@ module ELoot # Sets Inventory
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
From 4e4e37d32ec93384105e377420837ec1aa18f169 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 23 Feb 2026 20:06:34 -0500
Subject: [PATCH 23/40] fix: add skin bounty creatures only
---
scripts/eloot.lic | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index ffc189fd9..da4bfa994 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -31,6 +31,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -762,6 +763,7 @@ module ELoot # UI Setup
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: '' },
@@ -1084,11 +1086,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)
@@ -1863,6 +1865,7 @@ module ELoot # Profile loading/saving and settings
:skin_kneel => false,
:skin_604 => false,
:skin_resolve => false,
+ :skin_bounty_only => false,
:skin_sheath => "",
:skin_weapon => "",
:skin_sheath_blunt => "",
@@ -5208,6 +5211,11 @@ 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] && 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 }
From e8c68d34c061fce74a64da4d4d3be57674e28a02 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Tue, 24 Feb 2026 09:35:36 -0500
Subject: [PATCH 24/40] fix: incremental tipping pool depth & skinning when
bounty only checked
---
scripts/eloot.lic | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index da4bfa994..19710975c 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -5211,7 +5211,8 @@ 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] && Bounty.task.skin?
+ 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
@@ -6388,6 +6389,15 @@ module ELoot # Sells the loot
ELoot.go2('locksmith pool')
worker = ELoot.find_worker
+ # if using incremental tipping, need to find out how many boxes are in the pool
+ if boxes.length.positive? && ELoot.data.settings[:use_incremental_tipping]
+ pool_count = Sell.locksmith_pool_count(worker)
+ if pool_count > 99
+ pool_count = handle_full_pool(worker) { return true if deposit }
+ return if pool_count > 99
+ end
+ end
+
Inventory.free_hands(both: true) unless [GameObj.right_hand, GameObj.left_hand].find { |hand| hand.type =~ /box/ }
ELoot.wait_for_disk
From 649a71e3d7190d0ef03a97d12e500a2d6341e388 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Tue, 24 Feb 2026 13:01:49 -0500
Subject: [PATCH 25/40] fix: clear on sacks_full on ;eloot pool
---
scripts/eloot.lic | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 19710975c..9f7ec5bad 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -259,7 +259,7 @@ module ELoot # Data
# inventory type
@sacks_closed = []
- @sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
+ @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 = []
@@ -3607,7 +3607,7 @@ module ELoot # Inventory methods
else
ELoot.data.sacks_full.each do |container, information|
ELoot.msg(type: "info", text: " Sacks Full[#{container}]: #{information}")
- end unless ELoot.data.sacks_full.empty?
+ end unless ELoot.data.sacks_full.keys.count > 1
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!")
@@ -3726,7 +3726,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[bag.name] = [Time.now, Room.current.id, item]
+ 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
@@ -6859,7 +6859,7 @@ module ELoot # Starts the script
end
if !ELoot.data.settings[:track_full_sacks]
- ELoot.data.sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
+ 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
@@ -6937,7 +6937,7 @@ module ELoot # Starts the script
ELoot.wait_rt
# Set bags as empty to avoid false full status
- ELoot.data.sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
+ 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
@@ -6947,7 +6947,7 @@ module ELoot # Starts the script
ELoot.sell
# Reset bags to empty after all the selling is done
- ELoot.data.sacks_full = { "last cleared" => [Time.now, Room.current.id, Script.current.vars[0]] }
+ 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
@@ -6956,6 +6956,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
@@ -6967,20 +6969,22 @@ 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, Room.current.id, Script.current.vars[0]] }
+ 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, Room.current.id, Script.current.vars[0]] }
+ 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
From 638babbd82a686827b35d1d5b5532edfa3a48a07 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 2 Mar 2026 09:19:32 -0500
Subject: [PATCH 26/40] Fix bug in keep scrolls option
Fixed bug in keep scrolls option to skip non-numeric entries.
---
scripts/eloot.lic | 2 ++
1 file changed, 2 insertions(+)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 9f7ec5bad..0c09986a5 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -32,6 +32,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -737,6 +738,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)
From 643507dc1bfc77667555b8faa9c1d43962f292f5 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:10:33 -0400
Subject: [PATCH 27/40] Refactor overflow settings migration and loading logic
---
scripts/eloot.lic | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 0c09986a5..9e5fe685f 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -1775,6 +1775,8 @@ 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.migrate_overflow_settings(settings)
@@ -1825,8 +1827,9 @@ module ELoot # Profile loading/saving and settings
end
end
- ELoot.save_profile() if migrated_settings
- settings
+ if migrated_settings
+ ELoot.save_profile()
+ end
end
def self.load_defaults()
@@ -1897,8 +1900,6 @@ module ELoot # Profile loading/saving and settings
filename = File.join(DATA_DIR, XMLData.game, name, "eloot.yaml")
if File.exist?(filename) && name == Char.name
settings_hash = YAML.load_file(filename)
- # Migrate old overflow settings to new format
- settings_hash = ELoot.migrate_overflow_settings(settings_hash)
elsif !File.exist?(filename) && name != Char.name
ELoot.msg(type: "error", text: " ELoot.load_profile: Attempt to load a profile that does not exist.")
elsif !File.exist?(filename) && name == Char.name
@@ -3574,7 +3575,7 @@ module ELoot # Inventory methods
ELoot.wait_rt
raise
end
- next if ELoot.data.sacks_full.keys.include?(bag.name)
+ next if bag && ELoot.data.sacks_full.keys.include?(bag.name)
if bag.nil?
case index
@@ -6854,7 +6855,7 @@ 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/
From 91f026f5a099c9c8afe4872e27185328e79b29c1 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:24:27 -0400
Subject: [PATCH 28/40] Update scripts/eloot.lic
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
---
scripts/eloot.lic | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 9e5fe685f..15c77a338 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -3608,9 +3608,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
- ELoot.data.sacks_full.each do |container, information|
- ELoot.msg(type: "info", text: " Sacks Full[#{container}]: #{information}")
- end unless ELoot.data.sacks_full.keys.count > 1
+ 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!")
From 3116df6b02118c86c991050c72bf924fdc258faa Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 14:44:14 -0400
Subject: [PATCH 29/40] Refactor migration and defaults handling in eloot.lic
---
scripts/eloot.lic | 31 +++++++++++++++++++++++++++----
1 file changed, 27 insertions(+), 4 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 15c77a338..96db8b6e7 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -1780,7 +1780,7 @@ module ELoot # Profile loading/saving and settings
end
def self.migrate_overflow_settings(settings)
- migrated_settings = false
+ 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 = []
@@ -1832,8 +1832,11 @@ module ELoot # Profile loading/saving and settings
end
end
- def self.load_defaults()
- default_hash = {
+ # 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,
@@ -1886,6 +1889,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))
@@ -2298,7 +2318,10 @@ module ELoot # Regional bounty Selling
ELoot.msg(type: "debug", text: "place: #{place}")
bounty_town = Bounty.town.eql?("Cold River") ? "Hinterwilds" : Bounty.town
- place = self.tag_for_town(bounty_town, place).id
+ 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])
From b0b81c2162536fb399d0a79061c840cfc51288bd Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 15:46:02 -0400
Subject: [PATCH 30/40] Refactor key deletion in stow list
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 96db8b6e7..ec36bd1ee 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2123,7 +2123,7 @@ 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) }
# 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 == :appraisal_container }
+ StowList.stow_list.delete_if { |k, _| [:overflow_container, :secondary_overflow, :appraisal_container].include?(k) }
# Find the stow containers we need: overflow, appraisal
# Parse comma-separated overflow containers and add them dynamically
From 905a6b433f3ee435e4f93728b4b7b1e0eed605b4 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 15:49:06 -0400
Subject: [PATCH 31/40] Refactor key deletion in stow_list
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index ec36bd1ee..b1d53fc73 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2123,7 +2123,7 @@ 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) }
# Remove old overflow container keys (they may use sequential numbering now)
- StowList.stow_list.delete_if { |k, _| [:overflow_container, :secondary_overflow, :appraisal_container].include?(k) }
+ StowList.stow_list.delete_if { |k, _| k.to_s.start_with?('overflow_container') || k == :secondary_overflow || k == :appraisal_container }
# Find the stow containers we need: overflow, appraisal
# Parse comma-separated overflow containers and add them dynamically
From 1c54f0d6c2702ea6b4790e6d966b229e21a9b27c Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 11 Mar 2026 16:19:16 -0400
Subject: [PATCH 32/40] Update tag_for_town method to use safe navigation
Use safe navigation operator to handle nil case.
---
scripts/eloot.lic | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index b1d53fc73..750a1c5c4 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2309,7 +2309,8 @@ 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
# Determine if the bounty town is within the characters region
From 91ad4310e64f6ce8a6ef7ed83f2f59e77f564340 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Mon, 16 Mar 2026 15:27:03 -0400
Subject: [PATCH 33/40] fix: update F2P withdrawal for Teras bank
---
scripts/eloot.lic | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 750a1c5c4..f1a2c2fed 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -33,6 +33,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -3165,7 +3166,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
@@ -3188,8 +3189,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/)
From 95d0f2538d50d3745e35478ad777c37217b90182 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 25 Mar 2026 16:01:45 -0400
Subject: [PATCH 34/40] fix: overflow container validation errors during
initialization
* ensure_items caller check uses include? to match 'block in set_inventory' frame label, suppressing internal temp key leak in error messages
* validate_setup passes configured container name through checks tuple instead of deriving it from label.split(' ').last (returned slot number)
* explicit StowList.stow_list.delete(:secondary_overflow) for defensive legacy key cleanup
---
scripts/eloot.lic | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index f1a2c2fed..77bca0931 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -2011,7 +2011,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
@@ -2125,6 +2125,7 @@ module ELoot # Sets Inventory
ReadyList.ready_list.delete_if { |k, _| [:skin_weapon, :skin_weapon_blunt, :skin_sheath, :skin_sheath_blunt].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
@@ -2242,17 +2243,17 @@ module ELoot # Sets Inventory
# 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]
+ checks << [:overflow_containers, StowList.stow_list[key], label, nil, container_name]
end
end
- checks.each do |setting_key, found_obj, label, conditional_key|
+ 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 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?
- container_name = setting_key == :overflow_containers ? label.split(' ').last : 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
From 766f139dc8ad47c2043d272dde3f0b3478ca64a1 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Wed, 25 Mar 2026 17:14:13 -0400
Subject: [PATCH 35/40] fix: always check pool in process boxes not working
---
scripts/eloot.lic | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 77bca0931..35e187dcf 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -15,10 +15,10 @@
game: Gemstone
tags: loot
required: Lich >= 5.12.9
- version: 2.7.1
+ version: 2.8.0
Improvements:
Major_change.feature_addition.bugfix
- v2.7.1 (2026-01-27)
+ 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
@@ -34,6 +34,7 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -6722,7 +6723,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}")
From 6d9fbbebe351bb0f735bb5d01ae7708347150dfa Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 3 Apr 2026 10:17:25 -0400
Subject: [PATCH 36/40] fix: bugs in looting and inventory handling
Fix multiple bugs related to looting and inventory management.
---
scripts/eloot.lic | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 35e187dcf..534f1e770 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -35,6 +35,8 @@
- 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
v2.7.0 (2026-01-19)
- added ground looting of boxes
- added support for group disks when looting boxes
@@ -4510,7 +4512,7 @@ module ELoot # Gem and Reagent hoarding
if bottle
3.times do
- Inventory.drag(bottle)
+ Inventory.drag(bottle, to: '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
@@ -4521,7 +4523,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, to: '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
@@ -4552,7 +4554,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, to: 'right')
result = ELoot.get_res("_drag ##{thing.id} ##{jar.id}", /You (add|put)|The.*?is full/)
@@ -5085,7 +5087,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\.|As you move to search/, 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/ } &&
@@ -5106,7 +5108,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
@@ -6848,6 +6850,7 @@ module ELoot # Sells the loot
return if lines.any?(/That's not quite my field|That's basically worthless here|Can't say I'm interested in that|This is a pawnshop, sir, not a junkshop|The company don't buy trash|as if you were a lunatic/)
+
20.times {
break if !ELoot.in_hand?(item)
sleep 0.1
From 5318ef355fac2ffb0bca75852916c6ad11c52089 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 3 Apr 2026 10:22:40 -0400
Subject: [PATCH 37/40] fix: remove unnecessary blank lines in eloot.lic
---
scripts/eloot.lic | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 534f1e770..8b8d9a970 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -6849,8 +6849,7 @@ module ELoot # Sells the loot
lines = ELoot.get_command("sell ##{item.id}", /You (offer to sell|ask)/)
return if lines.any?(/That's not quite my field|That's basically worthless here|Can't say I'm interested in that|This is a pawnshop, sir, not a junkshop|The company don't buy trash|as if you were a lunatic/)
-
-
+
20.times {
break if !ELoot.in_hand?(item)
sleep 0.1
From a4ea55293e49976c8620af1e07ed4c3f258c9155 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 3 Apr 2026 10:25:09 -0400
Subject: [PATCH 38/40] fix: additional rubocop blank space removal
---
scripts/eloot.lic | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 8b8d9a970..00cd7aa64 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -6849,7 +6849,7 @@ module ELoot # Sells the loot
lines = ELoot.get_command("sell ##{item.id}", /You (offer to sell|ask)/)
return if lines.any?(/That's not quite my field|That's basically worthless here|Can't say I'm interested in that|This is a pawnshop, sir, not a junkshop|The company don't buy trash|as if you were a lunatic/)
-
+
20.times {
break if !ELoot.in_hand?(item)
sleep 0.1
From 75904563ecab2ed69f72f4b0a00a67dee3808ee4 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 3 Apr 2026 12:12:59 -0400
Subject: [PATCH 39/40] fix: CR recommendations drag method calls in eloot.lic
---
scripts/eloot.lic | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index 00cd7aa64..a030f0159 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -4512,7 +4512,7 @@ module ELoot # Gem and Reagent hoarding
if bottle
3.times do
- Inventory.drag(bottle, to: 'left')
+ 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
@@ -4523,7 +4523,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, to: 'left')
+ 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
@@ -4554,7 +4554,7 @@ module ELoot # Gem and Reagent hoarding
items_to_hoard.each do |thing|
thing_name = Hoard.normalize_name(thing.name)
- Inventory.drag(thing, to: 'right')
+ Inventory.drag(thing, 'right')
result = ELoot.get_res("_drag ##{thing.id} ##{jar.id}", /You (add|put)|The.*?is full/)
From 3fcb94b1d9dd678b74cdb4516f8cf49b22f48f12 Mon Sep 17 00:00:00 2001
From: "Ryan P. McKinnon" <15917743+mrhoribu@users.noreply.github.com>
Date: Fri, 3 Apr 2026 15:53:20 -0400
Subject: [PATCH 40/40] fix: hoarding_list single respect type on select
prevents situation when you have both `pink sapphire` gem and `sparkling pink sapphire band` jewelry in your inventory causing it to select both on single select to jar.
---
scripts/eloot.lic | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/scripts/eloot.lic b/scripts/eloot.lic
index a030f0159..1fc55cfa2 100644
--- a/scripts/eloot.lic
+++ b/scripts/eloot.lic
@@ -37,6 +37,7 @@
- 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
@@ -4432,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}/ }