Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions scripts/eloot.lic
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@
wiki: https://gswiki.play.net/Lich:Script_Eloot
game: Gemstone
tags: loot
required: Lich >= 5.12.9
version: 2.8.2
required: Lich >= 5.15.0
version: 2.9.0
Improvements:
Major_change.feature_addition.bugfix
v2.9.0 (2026-05-05)
- add new feature to keep transmogs
v2.8.2 (2026-05-01)
- bugfix: validate_hoarding_settings no longer errors when container_settings
is empty but use_overflow is enabled with resolved overflow containers
Expand Down Expand Up @@ -257,7 +259,8 @@ module ELoot # Data
:only_list, :only, :inventory, :gem_inventory, :alchemy_inventory, :hoard_type, :cache, :locker_city, :use_hoarding, :stash,
:items_to_hoard, :hoard_deposit, :inv_save, :deposit_regex, :withdraw_regex, :disk_nouns_regex, :sigil_determination_on_fail, :start_room, :last_called,
:urchin_msg, :gemshop_first, :reject_loot_names, :reject_loot_nouns, :version, :debug_logger, :details_check, :coin_bag_full,
:use_house_locker, :che_rooms, :che_entry, :che_exit, :towns, :gambling_kit, :gambling_kit_full, :ready_lines, :weapon_inv, :original_readylist, :blood_band
:use_house_locker, :che_rooms, :che_entry, :che_exit, :towns, :gambling_kit, :gambling_kit_full, :ready_lines, :weapon_inv, :original_readylist, :blood_band,
:transmog_cache

def initialize(settings)
@settings = settings
Expand Down Expand Up @@ -338,6 +341,9 @@ module ELoot # Data
$sell_ignore = []
@gemshop_first = false

# session-scoped cache of ANALYZE results for transmog detection: { [id, name] => true/false }
@transmog_cache = {}

default_crumbly = [
# Kraken Fall
"gnarled dark wooden crook",
Expand Down Expand Up @@ -768,6 +774,7 @@ module ELoot # UI Setup
sell_aspect: { default: false },
sell_keep_silver: { default: 0 },
sell_deposit_coinhand: { default: false },
keep_transmogs: { default: false },
trash_dump_types: { default: ["herb", "junk", "food"] },
},
skin: {
Expand Down Expand Up @@ -1087,7 +1094,7 @@ module ELoot # UI Setup
</packing></child><child><object class="GtkCheckButton" id="sell_deposit_coinhand"><property name="label" translatable="yes">Deposit coinhand/gambling kit</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="margin-top">5</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">2</property><property name="top-attach">1</property>
</packing></child><child><object class="GtkCheckButton" id="sell_share_silvers"><property name="label" translatable="yes">Share silvers</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="margin-top">5</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">2</property><property name="top-attach">0</property>
</packing></child><child><object class="GtkSpinButton" id="sell_keep_silver"><property name="visible">True</property><property name="can-focus">True</property><property name="halign">start</property><property name="margin-start">30</property><property name="margin-top">5</property><property name="margin-bottom">30</property><property name="text" translatable="yes">0</property><property name="adjustment">sell_keep_silver_adjustment</property><property name="numeric">True</property></object><packing><property name="left-attach">3</property><property name="top-attach">1</property><property name="height">2</property>
</packing></child><child><placeholder/></child><child><placeholder/></child></object></child><child type="label"><object class="GtkLabel"><property name="visible">True</property><property name="can-focus">False</property><property name="label" translatable="yes">Other Settings</property></object></child></object><packing><property name="left-attach">0</property><property name="top-attach">0</property><property name="width">2</property></packing></child></object><packing><property name="expand">False</property><property name="fill">True</property><property name="position">3</property>
</packing></child><child><object class="GtkCheckButton" id="keep_transmogs"><property name="label" translatable="yes">Keep Transmogs</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="margin-top">5</property><property name="draw-indicator">True</property><property name="tooltip-text" translatable="yes">Will analyze jewelry and clothing types for transmog capability and keep instead of sell</property></object><packing><property name="left-attach">1</property><property name="top-attach">2</property></packing></child><child><placeholder/></child><child><placeholder/></child></object></child><child type="label"><object class="GtkLabel"><property name="visible">True</property><property name="can-focus">False</property><property name="label" translatable="yes">Other Settings</property></object></child></object><packing><property name="left-attach">0</property><property name="top-attach">0</property><property name="width">2</property></packing></child></object><packing><property name="expand">False</property><property name="fill">True</property><property name="position">3</property>
</packing></child><child><object class="GtkFrame"><property name="visible">True</property><property name="can-focus">False</property><property name="border-width">10</property><property name="label-xalign">0</property><child><!-- n-columns=4 n-rows=3 --><object class="GtkGrid"><property name="visible">True</property><property name="can-focus">False</property><property name="margin-top">5</property><property name="margin-bottom">5</property><property name="row-spacing">2</property><property name="column-spacing">5</property><property name="column-homogeneous">True</property><child><object class="GtkCheckButton" id="trash_dump_types:alchemy"><property name="label" translatable="yes">Alchemy</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">0</property><property name="top-attach">0</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:food"><property name="label" translatable="yes">Food</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">1</property><property name="top-attach">0</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:lm trap"><property name="label" translatable="yes">Locksmith Traps</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">2</property><property name="top-attach">0</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:box"><property name="label" translatable="yes">Box</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">3</property><property name="top-attach">0</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:herb"><property name="label" translatable="yes">Herb</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">0</property><property name="top-attach">1</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:reagent"><property name="label" translatable="yes">Reagent</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">1</property><property name="top-attach">1</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:wand"><property name="label" translatable="yes">Wand</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">2</property><property name="top-attach">1</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:breakable"><property name="label" translatable="yes">Breakable</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">3</property><property name="top-attach">1</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:clothing"><property name="label" translatable="yes">Clothing</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="margin-start">5</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">0</property><property name="top-attach">2</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:junk"><property name="label" translatable="yes">Junk</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">1</property><property name="top-attach">2</property></packing></child><child><object class="GtkCheckButton" id="trash_dump_types:lockpick"><property name="label" translatable="yes">Lockpick</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">False</property><property name="halign">start</property><property name="draw-indicator">True</property></object><packing><property name="left-attach">2</property><property name="top-attach">2</property></packing></child></object></child><child type="label"><object class="GtkLabel"><property name="visible">True</property><property name="can-focus">False</property><property name="label" translatable="yes">Trash to Dump (?)</property><property name="tooltip-text" translatable="yes">Will attempt to TRASH type after selling is done, requires type to be enabled for selling to dump</property></object></child></object><packing><property name="expand">False</property><property name="fill">True</property><property name="position">4</property></packing></child></object></child></object></child></object><packing><property name="position">3</property></packing></child><child type="tab"><object class="GtkLabel"><property name="visible">True</property><property name="can-focus">False</property><property name="label" translatable="yes">Selling</property></object><packing><property name="position">3</property><property name="tab-fill">False</property></packing></child><child><object class="GtkScrolledWindow"><property name="visible">True</property><property name="can-focus">True</property><property name="shadow-type">in</property><child><object class="GtkViewport"><property name="visible">True</property><property name="can-focus">False</property><child><!-- n-columns=2 n-rows=3 --><object class="GtkGrid"><property name="visible">True</property><property name="can-focus">False</property><property name="border-width">10</property><child><object class="GtkFrame"><property name="width-request">150</property><property name="height-request">150</property><property name="visible">True</property><property name="can-focus">False</property><property name="border-width">5</property><property name="label-xalign">0</property><child><!-- n-columns=3 n-rows=2 --><object class="GtkGrid"><property name="visible">True</property><property name="can-focus">False</property><property name="valign">center</property><property name="margin-top">5</property><property name="margin-bottom">5</property><property name="row-spacing">2</property><property name="column-spacing">5</property><child><object class="GtkButton" id="sell_exclude_add"><property name="label" translatable="yes">Add</property><property name="width-request">80</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">True</property><property name="halign">start</property><property name="margin-start">5</property>
</object><packing><property name="left-attach">0</property><property name="top-attach">0</property></packing></child><child><object class="GtkButton" id="sell_exclude_delete"><property name="label" translatable="yes">Delete</property><property name="width-request">80</property><property name="visible">True</property><property name="can-focus">True</property><property name="receives-default">True</property><property name="halign">end</property><property name="margin-end">5</property></object><packing><property name="left-attach">2</property><property name="top-attach">0</property>
</packing></child><child><object class="GtkEntry" id="sell_exclude_entry"><property name="visible">True</property><property name="can-focus">True</property><property name="hexpand">True</property><property name="placeholder-text" translatable="yes">Enter exclusion (e.g. uncut diamond)</property></object><packing><property name="left-attach">1</property><property name="top-attach">0</property></packing></child><child><object class="GtkScrolledWindow"><property name="height-request">200</property><property name="visible">True</property><property name="can-focus">True</property><property name="margin-start">5</property><property name="margin-end">5</property><property name="margin-top">5</property><property name="margin-bottom">5</property><property name="hexpand">True</property><property name="shadow-type">in</property><child><object class="GtkViewport"><property name="visible">True</property><property name="can-focus">False</property><child><object class="GtkTreeView" id="sell_exclude"><property name="visible">True</property><property name="can-focus">True</property><property name="model">sell_exclude_store</property><property name="headers-visible">False</property><property name="search-column">0</property><property name="fixed-height-mode">True</property><child internal-child="selection"><object class="GtkTreeSelection"/>
Expand Down Expand Up @@ -1878,6 +1885,7 @@ module ELoot # Profile loading/saving and settings
:sell_shroud => false,
:sell_aspect => false,
:sell_keep_silver => 0,
:keep_transmogs => false,
:trash_dump_types => ["herb", "junk", "food"],
:skin_enable => false,
:skin_kneel => false,
Expand Down Expand Up @@ -3337,6 +3345,30 @@ module ELoot # Inventory methods
return false
end

# Determines if an item is a transmog (allows transferring its appearance onto another worn item).
# Only jewelry/clothing items with an after_name are candidates; for those we look at ANALYZE
# output for the transmog descriptor line. Callers that already have ANALYZE output for the
# item should pass it via `analyze_lines:` to avoid issuing a redundant ANALYZE command.
# Results are cached by a composite key of [item.id, item.name] for the
# lifetime of the script process. The composite key defends against game-id reuse over long
# sessions: if the item at a given id changes name, the prior result is ignored.
# @param item [GameObj] item to check
# @param analyze_lines [Array<String>, nil] pre-fetched ANALYZE output, or nil to fetch
# @return [Boolean] true if ANALYZE output confirms this is a transmog
def self.is_transmog?(item, analyze_lines: nil)
return false unless item.type =~ /jewelry|clothing/
return false if item.after_name.nil? || item.after_name.empty?
Comment thread
mrhoribu marked this conversation as resolved.

cache = ELoot.data.transmog_cache
key = [item.id, item.name]
return cache[key] if cache.key?(key)

lines = analyze_lines || ELoot.get_command("analyze ##{item.id}", /You analyze/, silent: true, quiet: true)
result = lines.any?(/This item allows you to transfer its appearance onto another compatible worn item/)
cache[key] = result
result
end

def self.check_auto_closer
return if ELoot.data.settings[:auto_close].empty?

Expand Down Expand Up @@ -5801,6 +5833,11 @@ module ELoot # Sells the loot
items_to_sell.each do |item|
Inventory.drag(item)

if ELoot.data.settings[:keep_transmogs] && Inventory.is_transmog?(item)
Inventory.single_drag(item)
next
end

if item.type =~ /#{ELoot.data.settings[:sell_appraise_types].join('|')}/ && !ELoot.data.settings[:sell_appraise_types].empty?
Sell.appraise(item, place.capitalize, ELoot.data.silver_breakdown)
else
Expand Down Expand Up @@ -5936,6 +5973,7 @@ module ELoot # Sells the loot
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('|')}/
next false if ELoot.data.settings[:keep_transmogs] && Inventory.is_transmog?(item)
true
end

Expand Down Expand Up @@ -6131,6 +6169,11 @@ module ELoot # Sells the loot

Inventory.drag(item)

if ELoot.data.settings[:keep_transmogs] && Inventory.is_transmog?(item)
Inventory.single_drag(item)
next
end

if item.type =~ /#{ELoot.data.settings[:sell_appraise_types].join('|')}/ && !ELoot.data.settings[:sell_appraise_types].empty?
Sell.appraise(item, "Gemshop", ELoot.data.silver_breakdown)
else
Expand Down Expand Up @@ -6652,6 +6695,12 @@ module ELoot # Sells the loot
Inventory.drag(thing)

lines = ELoot.get_command("analyze ##{thing.id}", /You analyze/, silent: true, quiet: true)

if ELoot.data.settings[:keep_transmogs] && Inventory.is_transmog?(thing, analyze_lines: lines)
Inventory.single_drag(thing)
next
end

if lines.any?(/ALTER 41/)
ELoot.msg(type: "info", text: "** This analyzes as Alter 41. Keeping it **", space: true)
Inventory.single_drag(thing)
Expand Down
Loading