I'm currently in the process of updating hackwish to (optionally) only allow stockpilable items to be made and (again, optionally) have even stricter requirements so that only items that can technically be made in-game can be made (say, only allowing weapons to be made of ITEMS_WEAPON materials).
I may also integrate it with spawnUnit if you try to make a pet, but that would be far more complex and would also kinda require spawnunit to be a lua library.
WIP:
-- Allows for script-based wishing.
function getCreatureID(creatureRaw)
return df.global.world.creatures.list_creature[creatureRaw.caste[0].index]
end
function createItem(mat,itemType,quality,pos)
local item=df[df.item_type.attrs[itemType[1]].classname]:new() --incredible
item.id=df.global.item_next_id
df.global.world.items.all:insert('#',item)
df.global.item_next_id=df.global.item_next_id+1
item:setSubtype(itemType[2])
item:setMaterial(mat[1])
item:setMaterialIndex(mat[2])
item:categorize(true)
item.flags.removed=true
item:setSharpness(1,0)
item:setQuality(quality-1)
dfhack.items.moveToGround(item,{x=pos.x,y=pos.y,z=pos.z})
end
function qualityTable()
return {{'None'},
{'-Well-crafted-'},
{'+Finely-crafted+'},
{'*Superior*'},
{string.char(240)..'Exceptional'..string.char(240)},
{string.char(15)..'Masterwork'..string.char(15)}
}
end
local script=require('gui/script')
function showItemPrompt(text,item_filter,hide_none)
require('gui.materials').ItemTypeDialog{
prompt=text,
item_filter=item_filter,
hide_none=hide_none,
on_select=script.mkresume(true),
on_cancel=script.mkresume(false),
on_close=script.qresume(nil)
}:show()
return script.wait()
end
function showMaterialPrompt(title, prompt, filter, inorganic, creature, plant) --the one included with DFHack doesn't have a filter or the inorganic, creature, plant things available
require('gui.materials').MaterialDialog{
frame_title = title,
prompt = prompt,
mat_filter = filter,
use_inorganic = inorganic,
use_creature = creature,
use_plant = plant,
on_select = script.mkresume(true),
on_cancel = script.mkresume(false),
on_close = script.qresume(nil)
}:show()
return script.wait()
end
function getMatFilter(itemtype)
local itemTypes={
SEEDS=function(mat,parent,typ,idx)
return mat.flags.SEED_MAT
end,
PLANT=function(mat,parent,typ,idx)
return mat.flags.STRUCTURAL_PLANT_MAT
end,
LEAVES=function(mat,parent,typ,idx)
return mat.flags.LEAF_MAT
end,
MEAT=function(mat,parent,typ,idx)
return mat.flags.MEAT
end,
CHEESE=function(mat,parent,typ,idx)
return (mat.flags.CHEESE_PLANT or mat.flags.CHEESE_CREATURE)
end,
LIQUID_MISC=function(mat,parent,typ,idx)
return (mat.flags.LIQUID_MISC_PLANT or mat.flags.LIQUID_MISC_CREATURE or mat.flags.LIQUID_MISC_OTHER)
end,
POWDER_MISC=function(mat,parent,typ,idx)
return (mat.flags.POWDER_MISC_PLANT or mat.flags.POWDER_MISC_CREATURE)
end,
DRINK=function(mat,parent,typ,idx)
return (mat.flags.ALCOHOL_PLANT or mat.flags.ALCOHOL_CREATURE)
end,
GLOB=function(mat,parent,typ,idx)
return (mat.flags.STOCKPILE_GLOB)
end,
WOOD=function(mat,parent,typ,idx)
return (mat.flags.WOOD)
end,
THREAD=function(mat,parent,typ,idx)
return (mat.flags.THREAD_PLANT)
end,
LEATHER=function(mat,parent,typ,idx)
return (mat.flags.LEATHER)
end
}
return itemTypes[df.item_type[itemtype]] or getRestrictiveMatFilter(itemtype)
end
function getRestrictiveMatFilter(itemType)
if not args.veryRestrictive then return nil else
local itemTypes={
WEAPON=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_WEAPON or mat.flags.ITEMS_WEAPON_RANGED)
end,
AMMO=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_AMMO)
end,
ARMOR=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_ARMOR)
end,
SHOES,SHIELD,HELM,GLOVES=ARMOR,ARMOR,ARMOR,ARMOR,
INSTRUMENT=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_HARD)
end,
GOBLET,FLASK,TOY,RING,CROWN,SCEPTER,FIGURINE=INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,
AMULET=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_SOFT or mat.flags.ITEMS_HARD)
end,
EARRING,BRACELET=AMULET,AMULET,
ROCK=function(mat,parent,typ,idx)
return (mat.flags.IS_STONE)
end,
BOULDER=ROCK,
BAR=function(mat,parent,typ,idx)
return (mat.flags.IS_METAL or mat.flags.SOAP or mat.id==COAL)
end
}
return itemTypes[df.item_type[itemtype]]
end
end
function hackWish(posOrUnit)
local pos = df.unit:is_instance(posOrUnit) and posOrUnit.pos or posOrUnit
script.start(function()
-- local amountok, amount
local matFilter
local itemok,itemtype,itemsubtype=showItemPrompt('What item do you want?',nil,true)
if not args.noMatRestriction then
matFilter=getMatFilter(itemtype)
end --for stockpiling reasons
local matok,mattype,matindex=showMaterialPrompt('Wish','And what material should it be made of?',matFilter)
local qualityok,quality=script.showListPrompt('Wish','What quality should it be?',COLOR_LIGHTGREEN,qualityTable())
-- repeat amountok,amount=script.showInputPrompt('Wish','How many do you want? (numbers only!)',COLOR_LIGHTGREEN) until tonumber(amount)
if mattype and itemtype then
-- for i=1,tonumber(amount) do
createItem({mattype,matindex},{itemtype,itemsubtype},quality,pos)
-- end
end
end)
end
args={...}
for k,v in ipairs(args) do
if v=='all' then args.noMatRestriction=true end
if v=='startup' then args.startup=true end
if v=='restrict' then args.veryRestrictive=true end
if v=='unit' then unitNum=args[k+1] end
end
eventful=require('plugins.eventful')
print(args.veryRestrictive)
if not args.startup then
local posOrUnit=#args<1 and dfhack.gui.getSelectedUnit(true) and dfhack.gui.getSelectedUnit(true) or not unitNum and df.global.cursor or unitNum and df.unit.find(unitNum) or {x=args[1],y=args[2],z=args[3]}
hackWish(posOrUnit)
else
eventful.onReactionComplete.hackWishP=function(reaction,unit,input_items,input_reagents,output_items,call_native)
if not reaction.code:find('DFHACK_WISH') then return nil end
hackWish(unit)
end
end