dfhack/scripts/stripcaged.rb

228 lines
6.2 KiB
Ruby

# mark stuff inside of cages for dumping.
=begin
stripcaged
==========
For dumping items inside cages. Will mark selected items for dumping, then
a dwarf may come and actually dump them (or you can use `autodump`).
Arguments:
:list: display the list of all cages and their item content on the console
:items: dump items in the cage, excluding stuff worn by caged creatures
:weapons: dump equipped weapons
:armor: dump everything worn by caged creatures (including armor and clothing)
:all: dump everything in the cage, on a creature or not
Without further arguments, all commands work on all cages and animal traps on
the map. With the ``here`` argument, considers only the in-game selected cage
(or the cage under the game cursor). To target only specific cages, you can
alternatively pass cage IDs as arguments::
stripcaged weapons 25321 34228
=end
def plural(nr, name)
# '1 cage' / '4 cages'
"#{nr} #{name}#{'s' if nr > 1}"
end
def cage_dump_items(list)
count = 0
count_cage = 0
list.each { |cage|
pre_count = count
cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsItemst)
next if ref.item_tg.flags.dump
count += 1
ref.item_tg.flags.dump = true
}
count_cage += 1 if pre_count != count
}
puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}"
end
def cage_dump_armor(list)
count = 0
count_cage = 0
list.each { |cage|
pre_count = count
cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst)
ref.unit_tg.inventory.each { |it|
next if it.mode != :Worn
next if it.item.flags.dump
count += 1
it.item.flags.dump = true
}
}
count_cage += 1 if pre_count != count
}
puts "Dumped #{plural(count, 'armor piece')} in #{plural(count_cage, 'cage')}"
end
def cage_dump_weapons(list)
count = 0
count_cage = 0
list.each { |cage|
pre_count = count
cage.general_refs.each { |ref|
next unless ref.kind_of?(DFHack::GeneralRefContainsUnitst)
ref.unit_tg.inventory.each { |it|
next if it.mode != :Weapon
next if it.item.flags.dump
count += 1
it.item.flags.dump = true
}
}
count_cage += 1 if pre_count != count
}
puts "Dumped #{plural(count, 'weapon')} in #{plural(count_cage, 'cage')}"
end
def cage_dump_all(list)
count = 0
count_cage = 0
list.each { |cage|
pre_count = count
cage.general_refs.each { |ref|
case ref
when DFHack::GeneralRefContainsItemst
next if ref.item_tg.flags.dump
count += 1
ref.item_tg.flags.dump = true
when DFHack::GeneralRefContainsUnitst
ref.unit_tg.inventory.each { |it|
next if it.item.flags.dump
count += 1
it.item.flags.dump = true
}
end
}
count_cage += 1 if pre_count != count
}
puts "Dumped #{plural(count, 'item')} in #{plural(count_cage, 'cage')}"
end
def cage_dump_list(list)
count_total = Hash.new(0)
empty_cages = 0
list.each { |cage|
count = Hash.new(0)
cage.general_refs.each { |ref|
case ref
when DFHack::GeneralRefContainsItemst
count[ref.item_tg._rtti_classname] += 1
when DFHack::GeneralRefContainsUnitst
ref.unit_tg.inventory.each { |it|
count[it.item._rtti_classname] += 1
}
# TODO vermin ?
else
puts "unhandled ref #{ref.inspect}" if $DEBUG
end
}
type = case cage
when DFHack::ItemCagest; 'Cage'
when DFHack::ItemAnimaltrapst; 'Animal trap'
else cage._rtti_classname
end
if count.empty?
empty_cages += 1
else
puts "#{type} ##{cage.id}: ", count.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" }
end
count.each { |k, v| count_total[k] += v }
}
if list.length > 2
puts '', "Total: ", count_total.sort_by { |k, v| v }.map { |k, v| " #{v} #{k}" }
puts "with #{plural(empty_cages, 'empty cage')}"
end
end
# handle magic script arguments
here_only = $script_args.delete 'here'
if here_only
it = df.item_find
list = [it]
if not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst)
list = df.world.items.other[:ANY_CAGE_OR_TRAP].find_all { |i| df.at_cursor?(i) }
end
if list.empty?
puts 'Please select a cage'
throw :script_finished
end
elsif ids = $script_args.find_all { |arg| arg =~ /^\d+$/ } and ids.first
list = []
ids.each { |id|
$script_args.delete id
if not it = df.item_find(id.to_i)
puts "Invalid item id #{id}"
elsif not it.kind_of?(DFHack::ItemCagest) and not it.kind_of?(DFHack::ItemAnimaltrapst)
puts "Item ##{id} is not a cage"
list << it
else
list << it
end
}
if list.empty?
puts 'Please use a valid cage id'
throw :script_finished
end
else
list = df.world.items.other[:ANY_CAGE_OR_TRAP]
end
# act
case $script_args[0]
when /^it/i
cage_dump_items(list)
when /^arm/i
cage_dump_armor(list)
when /^wea/i
cage_dump_weapons(list)
when 'all'
cage_dump_all(list)
when 'list'
cage_dump_list(list)
else
puts <<EOS
Marks items inside all cages for dumping.
Add 'here' to dump stuff only for selected cage.
Add a cage id to dump stuff for this cage only.
See 'autodump' to actually dump stuff.
Usage:
stripcaged items
dump items directly in cages (eg seeds after training)
stripcaged [armor|weapons] here
dump armor or weapons of caged creatures in selected cage
stripcaged all 28 29
dump every item in cage id 28 and 29, along with every item worn by creatures in there too
stripcaged list
show content of the cages
EOS
end