Skip to content

Instantly share code, notes, and snippets.

@ab9rf
Last active December 21, 2022 08:42
Show Gist options
  • Save ab9rf/4740564 to your computer and use it in GitHub Desktop.
Save ab9rf/4740564 to your computer and use it in GitHub Desktop.
DFHack Ruby script to mark items for purchase in trade screen
def is_tree_seed? (item)
if (!item.instance_of? DFHack::ItemSeedsst)
return false
end
if (item.mat_type < 419 || item.mat_type > 618)
return false
end
mat = df.world.raws.plants.all[item.mat_index]
if (! mat.flags[:TREE])
return false
end
seed_mat_idx = mat.material_defs.type_seed
if (seed_mat_idx == -1)
return false
end
seed_mat = mat.material[seed_mat_idx - 419]
return !(seed_mat.flags[:EDIBLE_RAW] || seed_mat.flags[:EDIBLE_COOKED])
end
def is_scroll? (item)
if (!item.instance_of? DFHack::ItemToolst)
return false
end
return item.subtype.tool_use.any?{|u|u==:CONTAIN_WRITING}
end
def desirable_boulder_mat? (matindex)
mat = df.world.raws.inorganics[matindex]
(mat.economic_uses.count > 0 || mat.metal_ore.mat_index.count > 0)
end
def is_metal? (item)
return (item.mat_type == 0 && df.world.raws.inorganics[item.mat_index].material.flags[:IS_METAL])
end
def is_useful_metal? (item)
if (!is_metal? (item))
return false
end
mat = df.world.raws.inorganics[item.mat_index].material
return (mat.flags[:ITEMS_METAL] ||
mat.flags[:ITEMS_WEAPON] ||
mat.flags[:ITEMS_WEAPON_RANGED] ||
mat.flags[:ITEMS_AMMO] ||
mat.flags[:ITEMS_ARMOR])
end
def is_wood? (item)
if (item.mat_type < 419 || item.mat_type > 618)
return false
end
mat = df.world.raws.plants.all[item.mat_index].material[item.mat_type-419]
mat.flags[:WOOD]
end
def is_booze? (item)
item.instance_of? DFHack::ItemDrinkst
end
def is_seeds? (item)
item.instance_of? DFHack::ItemSeedsst
end
def is_plantgrowth? (item)
item.instance_of? DFHack::ItemPlantGrowthst
end
def is_milk? (item)
if not item.instance_of? DFHack::ItemLiquidMiscst
return false
end
if (item.mat_type < 19 || item.mat_type > 218)
return false
end
mat = df.world.raws.creatures.all[item.mat_index].material[item.mat_type-19]
mat.reaction_class.any? {|i|i == "MILK"}
end
def is_flour? (item)
if not item.instance_of? DFHack::ItemPowderMiscst
return false
end
if (item.mat_type < 419 || item.mat_type > 618)
return false
end
mat = df.world.raws.plants.all[item.mat_index].material[item.mat_type-419]
mat.flags[:POWDER_MISC_PLANT]
end
def is_salve? (item)
if not item.instance_of? DFHack::ItemLiquidMiscst
return false
end
if (item.mat_type < 419 || item.mat_type > 618)
return false
end
mat = df.world.raws.plants.all[item.mat_index].material[item.mat_type-419]
mat.flags[:LIQUID_MISC_PLANT]
end
def is_syrup? (item)
if not item.instance_of? DFHack::ItemLiquidMiscst
return false
end
if (item.mat_type < 419 || item.mat_type > 618)
return false
end
mat = df.world.raws.plants.all[item.mat_index].material[item.mat_type-419]
mat.flags[:LIQUID_MISC_PLANT] &&
(mat.flags[:EDIBLE_COOKED] || mat.flags[:EDIBLE_RAW])
end
def is_lye? (item)
if not item.instance_of? DFHack::ItemLiquidMiscst
return false
end
item.mat_type == 11
end
def is_sand? (item)
if not item.instance_of? DFHack::ItemPowderMiscst
return false
end
if (item.mat_type != 0)
return false
end
mat = df.world.raws.inorganics[item.mat_index]
mat.flags[:SOIL_SAND]
end
def is_plaster? (item)
if not item.instance_of? DFHack::ItemPowderMiscst
return false
end
if (item.mat_type != 0)
return false
end
mat = df.world.raws.inorganics[item.mat_index]
mat.material.hardens_with_water.mat_type != -1
end
def cage_nonempty? (item)
item.general_refs.any? {|r| r.instance_of? DFHack::GeneralRefContainsUnitst}
end
def container_empty? (item)
not (item.general_refs.any? {|r| r.instance_of? DFHack::GeneralRefContainsItemst})
end
def contents (item)
result = item.general_refs.find {|r| (r.instance_of? DFHack::GeneralRefContainsItemst)}
result = result && result.item_tg
end
def contents_list (item)
result = item.general_refs.find_all {|r| (r.instance_of? DFHack::GeneralRefContainsItemst)}
result = result && result.map {|r|r.item_tg}
end
def trader_desirable? (item)
if (((item.instance_of? DFHack::ItemFlaskst) &&
(contents_list(item).any?{|c|is_salve?(c)})) ||
(item.instance_of? DFHack::ItemFoodst))
return false
end
(is_booze?(item)) or
(is_milk?(item)) or
(is_syrup?(item)) or
(is_lye?(item)) or
(is_flour?(item)) or
(is_sand?(item)) or
(is_seeds?(item) && !is_tree_seed?(item)) or
(is_scroll?(item)) or
(is_plaster?(item)) or
(item.instance_of? DFHack::ItemCoinst) or
(item.instance_of? DFHack::ItemInstrumentst) or
(item.instance_of? DFHack::ItemCheesest) or
(item.instance_of? DFHack::ItemMeatst) or
(item.instance_of? DFHack::ItemEggst) or
(item.instance_of? DFHack::ItemFishst) or
(item.instance_of? DFHack::ItemBarst) or
(item.instance_of? DFHack::ItemSmallgemst) or
(item.instance_of? DFHack::ItemRoughst) or
(item.instance_of? DFHack::ItemBookst) or
((item.instance_of? DFHack::ItemBoulderst) && desirable_boulder_mat?(item.mat_index)) or
(item.instance_of? DFHack::ItemWoodst) or
(((((item.instance_of? DFHack::ItemBinst) ||
(item.instance_of? DFHack::ItemBoxst) ||
(item.instance_of? DFHack::ItemBarrelst) ||
(item.instance_of? DFHack::ItemBackpackst) ||
(item.instance_of? DFHack::ItemCabinetst)) && container_empty?(item)) ||
(item.instance_of? DFHack::ItemArmorstandst) ||
(item.instance_of? DFHack::ItemWeaponrackst) ||
(item.instance_of? DFHack::ItemGratest) ||
(item.instance_of? DFHack::ItemFlaskst) ||
(item.instance_of? DFHack::ItemBucketst) ||
(item.instance_of? DFHack::ItemBedst) ||
(item.instance_of? DFHack::ItemDoorst) ||
(item.instance_of? DFHack::ItemChairst) ||
(item.instance_of? DFHack::ItemTablest) ||
(item.instance_of? DFHack::ItemSlabst) ||
(item.instance_of? DFHack::ItemCoffinst) ||
(item.instance_of? DFHack::ItemStatuest) ||
(item.instance_of? DFHack::ItemTrappartsst) ||
(item.instance_of? DFHack::ItemQuiverst) ||
(item.instance_of? DFHack::ItemWeaponst) ||
(item.instance_of? DFHack::ItemArmorst) ||
(item.instance_of? DFHack::ItemShoesst) ||
(item.instance_of? DFHack::ItemShieldst) ||
(item.instance_of? DFHack::ItemHelmst) ||
(item.instance_of? DFHack::ItemGlovesst) ||
(item.instance_of? DFHack::ItemAmmost) ||
(item.instance_of? DFHack::ItemAnvilst) ||
(item.instance_of? DFHack::ItemPantsst) ||
(item.instance_of? DFHack::ItemTrapcompst) ||
(item.instance_of? DFHack::ItemChainst) ||
(item.instance_of? DFHack::ItemSplintst) ||
(item.instance_of? DFHack::ItemToolst) ||
(item.instance_of? DFHack::ItemCrutchst) ||
(item.instance_of? DFHack::ItemSheetst) ||
(item.instance_of? DFHack::ItemGobletst)) &&
((is_useful_metal?(item)) ||
((item.wear == 0) && (item.quality == :Masterful || item.quality == :Artifact)))) or
(((item.instance_of? DFHack::ItemToyst) ||
(item.instance_of? DFHack::ItemBraceletst) ||
(item.instance_of? DFHack::ItemCrownst) ||
(item.instance_of? DFHack::ItemFigurinest) ||
(item.instance_of? DFHack::ItemAmuletst) ||
(item.instance_of? DFHack::ItemScepterst) ||
(item.instance_of? DFHack::ItemRingst) ||
(item.instance_of? DFHack::ItemEarringst) ||
(item.instance_of? DFHack::ItemGemst)) &&
(is_useful_metal?(item) &&
!(item.quality == :Masterful || item.quality == :Artifact))) or
((item.instance_of? DFHack::ItemCagest)) or
(((item.instance_of? DFHack::ItemBarrelst) ||
(item.instance_of? DFHack::ItemToolst) ||
(item.instance_of? DFHack::ItemBoxst)) &&
(contents_list(item).any?{|c|trader_desirable?(c)})) or
((item.instance_of? DFHack::ItemClothst)) or
((item.instance_of? DFHack::ItemSkinTannedst)) or
((item.instance_of? DFHack::ItemPlantst)) or
((item.instance_of? DFHack::ItemPlantGrowthst)) or
((item.instance_of? DFHack::ItemThreadst)) or
false
end
def is_wood_based? (typ, idx)
if (typ == 11) # lye
return true
end
if (typ == 4 || typ == 5) # clear & crystal glass
return true
end
mat = DFHack::decode_mat(typ, idx)
return mat && mat.material && (mat.material.flags[:WOOD] || mat.material.flags[:SOAP])
end
def contains_wood?(item)
mat_type = item.getMaterial()
mat_index = item.getMaterialIndex()
if is_wood_based?(mat_type, mat_index)
# puts "wood: #{item.inspect}"
return true
end
if ((item.kind_of? DFHack::ItemConstructed) &&
item.improvements.any? {|imp|
res=is_wood_based?(imp.mat_type, imp.mat_index)
res
})
# puts "wood in improvements: #{item.inspect}"
return true
end
if (item.flags.container && contents_list(item).any? {|c|contains_wood?(c)})
# puts "wood in contents: #{item.inspect}"
return true
end
false
end
def broker_desirable? (item, nowood=false)
if item.flags.artifact then
return false
end
if df.world.mandates.any? {|m|
m.mode == 0 && m.item_type == item.getType() &&
(m.item_subtype == -1 || m.item_subtype == item.getSubtype()) &&
(m.mat_type == -1 || m.mat_type == item.getMaterial()) &&
(m.mat_index == -1 || m.mat_type == item.getMaterialIndex()) }
return false
end
if ((item.instance_of? DFHack::ItemBoulderst) ||
(item.instance_of? DFHack::ItemMeatst) ||
(item.instance_of? DFHack::ItemCheesest) ||
(item.instance_of? DFHack::ItemFishst) ||
(item.instance_of? DFHack::ItemFishRawst) ||
(item.instance_of? DFHack::ItemEggst) ||
(item.instance_of? DFHack::ItemGlobst) ||
(item.instance_of? DFHack::ItemBinst) ||
(item.instance_of? DFHack::ItemCagest) ||
(item.instance_of? DFHack::ItemBlocksst) ||
(item.instance_of? DFHack::ItemCorpsepiecest)) ||
(item.instance_of? DFHack::ItemTrappartsst) ||
(item.instance_of? DFHack::ItemDoorst) ||
(item.instance_of? DFHack::ItemCabinetst) ||
(item.instance_of? DFHack::ItemBoxst) ||
(item.instance_of? DFHack::ItemCoffinst) ||
(item.instance_of? DFHack::ItemBedst)
return false
end
if (((item.instance_of? DFHack::ItemBarrelst) ||
# (item.instance_of? DFHack::ItemBucketst) ||
(item.instance_of? DFHack::ItemToolst) ||
(item.instance_of? DFHack::ItemBoxst)) &&
contents_list(item).empty?)
return false
end
if (nowood && contains_wood?(item))
return false
end
if (nowood && item.weight >= 50 )
return false
end
des = ! trader_desirable?(item)
if (des)
return true
end
return false
end
def find_broker ()
broker = df.unit_citizens.find{|u|
ep = df.unit_entitypositions(u)
ep.find{|r|r.responsibilities[:TRADE]}
}
end
nowood = false
case $script_args[0]
when 'test'
item = DFHack::item_find
if (item)
td = trader_desirable?(item)
bd = broker_desirable?(item)
bdc = (! (contents_list(item).empty?) &&
(contents_list(item).any? {|c| broker_desirable?(c)}))
puts "TD: #{td} BD: #{bd} BDC: #{bdc}"
end
runmode = :Nothing
when 'clear'
runmode = :Clear
when 'clearpend'
runmode = :Clearpend
when 'cpnb'
runmode = :CPNB
when 'clearbroker'
runmode = :ClearBroker
when 'cleartrader'
runmode = :ClearTrader
when 'nowood'
runmode = :Set
nowood = true
when 'wt'
runmode = :WT
when 'unmark'
runmode = :Unmark
arg = $script_args[1]
else
runmode = :Set
end
if runmode != :Nothing then
broker = find_broker
civ = broker.civ_tg
vs = df.gview.view.child.child
if (vs.instance_of? DFHack::ViewscreenLayerAssigntradest)
vs.info.each {|i|
case runmode
when :Clear
des = false
when :Set
item = i.item
td = trader_desirable?(item)
bd = ((broker_desirable?(item,nowood)))
bd = bd || (!(item.instance_of? DFHack::ItemBarrelst) &&
contents_list(item).any? {|c| broker_desirable?(c,nowood)})
des = !td && (bd)
when :Clearpend
des = (i.status == :Trading) ||
((i.status == :Pending || i.status == :AddPending) && i.distance == 0)
when :CPNB
des = (i.status == :Trading) ||
((i.status == :Pending || i.status == :AddPending) && ((i.distance == 0) || (i.item.instance_of? DFHack::ItemBinst)))
else
des = (i.status == :AddPending || i.status == :Pending || i.status == :Trading)
end
stat = i.status
if (des)
if i.status == :None
i.status = :AddPending
elsif i.status == 255
i.status = :Pending
elsif i.status == 254
i.status = :Trading
end
else
if i.status == :AddPending
i.status = :None
elsif i.status == :Pending
i.status = :RemovePending
elsif i.status == :Trading
i.status = :RemoveTrading
end
end
}
elsif (vs.instance_of? DFHack::ViewscreenTradelistst)
vs = vs.child
wood_ethic = vs.entity.entity_raw.ethic[:KILL_PLANT]
nowood = nowood ||
wood_ethic == :MISGUIDED ||
wood_ethic == :SHUN ||
wood_ethic == :APPALLING ||
wood_ethic == :PUNISH_REPRIMAND ||
wood_ethic == :PUNISH_SERIOUS ||
wood_ethic == :PUNISH_EXILE ||
wood_ethic == :PUNISH_CAPITAL ||
wood_ethic == :UNTHINKABLE
case runmode
when :Clear
(0...vs.trader_items.count).each {|i|
item = vs.trader_items[i]
vs.trader_selected[i] = false
}
(0...vs.broker_items.count).each {|i|
item = vs.broker_items[i]
vs.broker_selected[i] = false
}
when :ClearBroker
(0...vs.broker_items.count).each {|i|
item = vs.broker_items[i]
vs.broker_selected[i] = false
}
when :ClearTrader
(0...vs.trader_items.count).each {|i|
item = vs.trader_items[i]
vs.trader_selected[i] = false
}
when :Set
(0...vs.trader_items.count).each {|i|
item = vs.trader_items[i]
vs.trader_selected[i] = trader_desirable? (item)
}
(0...vs.broker_items.count).each {|i|
item = vs.broker_items[i]
vs.broker_selected[i] = broker_desirable?(item, nowood)
}
when :Unmark
(0...vs.trader_items.count).each {|i|
item = vs.trader_items[i]
if (vs.trader_selected[i])
str = DFHack::StlString.cpp_new
vs.trader_items[i].getItemDescription(str, 0)
if (str.str.include?(arg))
vs.trader_selected[i] = false
end
end
}
(0...vs.broker_items.count).each {|i|
item = vs.broker_items[i]
if (vs.broker_selected[i])
str = DFHack::StlString.cpp_new
vs.broker_items[i].getItemDescription(str, 0)
if (str.str.include?(arg))
vs.broker_selected[i] = false
end
end
}
when :WT
while (vs.broker_cursor < vs.broker_items.count)
vs.broker_cursor = vs.broker_cursor + 1
item = vs.broker_items[vs.broker_cursor]
break if (contains_wood?(item))
end
end
else
puts "Invalid invocation context!"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment