Merge remote-tracking branches 'warmist/advfort', 'Putnam3145/patch-8', 'AndreasPK/master' and 'PeridexisErrant/fix-exportlegends'

develop
lethosor 2015-01-05 16:19:52 -05:00
5 changed files with 518 additions and 324 deletions

@ -51,7 +51,7 @@ end
function wait_for_export_maps_vs() function wait_for_export_maps_vs()
local vs = dfhack.gui.getCurViewscreen() local vs = dfhack.gui.getCurViewscreen()
if dfhack.gui.getCurFocus() == "export_graphical_map" then if dfhack.gui.getCurFocus() == "export_graphical_map" then
vs.sel_idx = i vs.sel_idx = i-1
print(' Exporting: '..MAPS[i]..' map') print(' Exporting: '..MAPS[i]..' map')
gui.simulateInput(vs, 'SELECT') gui.simulateInput(vs, 'SELECT')
i = i + 1 i = i + 1
@ -81,13 +81,16 @@ if dfhack.gui.getCurFocus() == "legends" then
export_site_maps() export_site_maps()
wait_for_legends_vs() wait_for_legends_vs()
elseif args[1] == "info" then elseif args[1] == "info" then
wait_for_legends_vs() export_legends_info()
elseif args[1] == "maps" then elseif args[1] == "maps" then
wait_for_legends_vs() wait_for_legends_vs()
elseif args[1] == "sites" then elseif args[1] == "sites" then
export_site_maps() export_site_maps()
else dfhack.printerr('Valid arguments are "all", "info", "maps" or "sites"') else dfhack.printerr('Valid arguments are "all", "info", "maps" or "sites"')
end end
elseif args[1] == "maps" and
dfhack.gui.getCurFocus() == "export_graphical_map" then
wait_for_export_maps_vs()
else else
dfhack.printerr('Not in main legends view') dfhack.printerr('Exportlegends must be run from the main legends view')
end end

@ -29,7 +29,11 @@ if args.help then
return return
end end
unit = df.unit.find(args.unit) or dfhack.gui.getSelectedUnit() if(args.unit) then
unit = df.unit.find(args.unit)
else
unit = dfhack.gui.getSelectedUnit()
end
if not unit then if not unit then
qerror('Error: please select a unit or pass its id as an argument.') qerror('Error: please select a unit or pass its id as an argument.')

@ -1,5 +1,26 @@
-- allows to do jobs in adv. mode. -- allows to do jobs in adv. mode.
--[==[
version: 0.011
changelog:
*0.011
- fixed crash with building jobs (other jobs might have been crashing too!)
- fixed bug with building asking twice to input items
*0.01
- instant job startation
- item selection screen (!)
- BUG:custom jobs need stuff on ground to work
*0.003
- fixed farms (i think...)
- added faster time pasing (yay for random deaths from local wildlife)
- still hasn't fixed gather plants. but you can visit local market, buy a few local fruits/vegetables eat them and use seeds
- other stuff
*0.002
- kind-of fixed the item problem... now they get teleported (if teleport_items=true which should be default for adventurer)
- gather plants still not working... Other jobs seem to work.
- added new-and-improved waiting. Interestingly it could be improved to be interuptable.
--]==]
--keybinding, change to your hearts content. Only the key part. --keybinding, change to your hearts content. Only the key part.
keybinds={ keybinds={
nextJob={key="CUSTOM_SHIFT_T",desc="Next job in the list"}, nextJob={key="CUSTOM_SHIFT_T",desc="Next job in the list"},
@ -14,16 +35,19 @@ workshop={key="CHANGETAB",desc="Show building menu"},
} }
-- building filters -- building filters
build_filter={ build_filter={
forbid_all=true, --this forbits all except the "allow" forbid_all=false, --this forbits all except the "allow"
allow={"MetalSmithsForge"}, --ignored if forbit_all=false allow={"MetalSmithsForge"}, --ignored if forbit_all=false
forbid={"Custom"} --ignored if forbit_all==true forbid={} --ignored if forbit_all==true
} }
build_filter.HUMANish={ build_filter.HUMANish={
forbid_all=true, forbid_all=true,
allow={"Masons"}, allow={"Masons"},
forbid={} forbid={}
} }
--[[ FIXME: maybe let player select which to disable?]]
for k,v in ipairs(df.global.ui.economic_stone) do df.global.ui.economic_stone[k]=0 end
local gui = require 'gui' local gui = require 'gui'
local wid=require 'gui.widgets' local wid=require 'gui.widgets'
local dialog=require 'gui.dialogs' local dialog=require 'gui.dialogs'
@ -31,10 +55,11 @@ local buildings=require 'dfhack.buildings'
local bdialog=require 'gui.buildings' local bdialog=require 'gui.buildings'
local workshopJobs=require 'dfhack.workshops' local workshopJobs=require 'dfhack.workshops'
local utils=require 'utils' local utils=require 'utils'
local gscript=require 'gui.script'
local tile_attrs = df.tiletype.attrs local tile_attrs = df.tiletype.attrs
settings={build_by_items=false,check_inv=false,df_assign=true} settings={build_by_items=false,use_worn=false,check_inv=true,teleport_items=true,df_assign=false,gui_item_select=true,only_in_sites=false}
function hasValue(tbl,val) function hasValue(tbl,val)
for k,v in pairs(tbl) do for k,v in pairs(tbl) do
@ -48,7 +73,7 @@ function reverseRaceLookup(id)
return df.global.world.raws.creatures.all[id].creature_id return df.global.world.raws.creatures.all[id].creature_id
end end
function deon_filter(name,type_id,subtype_id,custom_id, parent) function deon_filter(name,type_id,subtype_id,custom_id, parent)
print(name) --print(name)
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
local race_filter=build_filter[reverseRaceLookup(adv.race)] local race_filter=build_filter[reverseRaceLookup(adv.race)]
if race_filter then if race_filter then
@ -138,60 +163,99 @@ function inSite()
end end
end end
--[[ low level job management ]]-- --[[ low level job management ]]--
function getLastJobLink() function findAction(unit,ltype)
local st=df.global.world.job_list ltype=ltype or df.unit_action_type.None
while st.next~=nil do for i,v in ipairs(unit.actions) do
st=st.next if v.type==ltype then
return v
end
end end
return st
end end
function addNewJob(job) function add_action(unit,action_data)
local lastLink=getLastJobLink() local action=findAction(unit) --find empty action
local newLink=df.job_list_link:new() if action then
newLink.prev=lastLink action:assign(action_data)
lastLink.next=newLink action.id=unit.next_action_id
newLink.item=job unit.next_action_id=unit.next_action_id+1
job.list_link=newLink else
local tbl=copyall(action_data)
tbl.new=true
tbl.id=unit.next_action_id
unit.actions:insert("#",tbl)
unit.next_action_id=unit.next_action_id+1
end
end
function addJobAction(job,unit) --what about job2?
if job==nil then
error("invalid job")
end
if findAction(unit,df.unit_action_type.Job) or findAction(unit,df.unit_action_type.Job2) then
print("Already has job action")
return
end
local action=findAction(unit)
local pos=copyall(unit.pos)
--local pos=copyall(job.pos)
unit.path.dest:assign(pos)
--job
local data={type=df.unit_action_type.Job,data={job={x=pos.x,y=pos.y,z=pos.z,timer=10}}}
--job2:
--local data={type=df.unit_action_type.Job2,data={job2={timer=10}}}
add_action(unit,data)
--add_action(unit,{type=df.unit_action_type.Unsteady,data={unsteady={timer=5}}})
end end
function makeJob(args)
local newJob=df.job:new()
newJob.id=df.global.job_next_id
df.global.job_next_id=df.global.job_next_id+1
--newJob.flags.special=true
newJob.job_type=args.job_type
newJob.completion_timer=-1
newJob.pos:assign(args.pos) function make_native_job(args)
args.job=newJob if args.job == nil then
local failed local newJob=df.job:new()
for k,v in ipairs(args.pre_actions or {}) do newJob.id=df.global.job_next_id
local ok,msg=v(args) df.global.job_next_id=df.global.job_next_id+1
if not ok then newJob.flags.special=true
failed=msg newJob.job_type=args.job_type
break newJob.completion_timer=-1
end
newJob.pos:assign(args.pos)
--newJob.pos:assign(args.unit.pos)
args.job=newJob
args.unlinked=true
end end
if failed==nil then end
AssignUnitToJob(newJob,args.unit,args.from_pos) function makeJob(args)
for k,v in ipairs(args.post_actions or {}) do gscript.start(function ()
make_native_job(args)
local failed
for k,v in ipairs(args.pre_actions or {}) do
local ok,msg=v(args) local ok,msg=v(args)
if not ok then if not ok then
failed=msg failed=msg
break break
end end
end end
if failed then if failed==nil then
UnassignJob(newJob,args.unit) AssignUnitToJob(args.job,args.unit,args.from_pos)
for k,v in ipairs(args.post_actions or {}) do
local ok,msg=v(args)
if not ok then
failed=msg
break
end
end
if failed then
UnassignJob(args.job,args.unit)
end
end end
end if failed==nil then
if failed==nil then if args.unlinked then
addNewJob(newJob) dfhack.job.linkIntoWorld(args.job,true)
return newJob args.unlinked=false
else end
newJob:delete() addJobAction(args.job,args.unit)
return false,failed args.screen:wait_tick()
end else
args.job:delete()
dfhack.gui.showAnnouncement(msg,5,1)
end
end)
end end
function UnassignJob(job,unit,unit_pos) function UnassignJob(job,unit,unit_pos)
@ -345,7 +409,7 @@ function IsWall(args)
end end
function IsTree(args) function IsTree(args)
local tt=dfhack.maps.getTileType(args.pos) local tt=dfhack.maps.getTileType(args.pos)
if tile_attrs[tt].shape==df.tiletype_shape.TREE then if tile_attrs[tt].material==df.tiletype_material.TREE then
return true return true
else else
return false, "Can only do it on trees" return false, "Can only do it on trees"
@ -382,9 +446,10 @@ function itemsAtPos(pos,tbl)
return ret return ret
end end
function AssignBuildingRef(args) function AssignBuildingRef(args)
local bld=dfhack.buildings.findAtTile(args.pos) local bld=args.building or dfhack.buildings.findAtTile(args.pos)
args.job.general_refs:insert("#",{new=df.general_ref_building_holderst,building_id=bld.id}) args.job.general_refs:insert("#",{new=df.general_ref_building_holderst,building_id=bld.id})
bld.jobs:insert("#",args.job) bld.jobs:insert("#",args.job)
args.building=args.building or bld
return true return true
end end
function chooseBuildingWidthHeightDir(args) --TODO nicer selection dialog function chooseBuildingWidthHeightDir(args) --TODO nicer selection dialog
@ -417,7 +482,7 @@ function chooseBuildingWidthHeightDir(args) --TODO nicer selection dialog
return false return false
--width = ..., height = ..., direction = ... --width = ..., height = ..., direction = ...
end end
CheckAndFinishBuilding=nil
function BuildingChosen(inp_args,type_id,subtype_id,custom_id) function BuildingChosen(inp_args,type_id,subtype_id,custom_id)
local args=inp_args or {} local args=inp_args or {}
@ -438,7 +503,8 @@ function BuildingChosen(inp_args,type_id,subtype_id,custom_id)
--if settings.build_by_items then --if settings.build_by_items then
-- args.items=itemsAtPos(inp_args.from_pos) -- args.items=itemsAtPos(inp_args.from_pos)
--end --end
buildings.constructBuilding(args) args.building=buildings.constructBuilding(args)
CheckAndFinishBuilding(args,args.building)
end end
@ -489,7 +555,30 @@ function isSuitableItem(job_item,item)
local matinfo=dfhack.matinfo.decode(item) local matinfo=dfhack.matinfo.decode(item)
--print(matinfo:getCraftClass()) --print(matinfo:getCraftClass())
--print("Matching ",item," vs ",job_item) --print("Matching ",item," vs ",job_item)
if not matinfo:matches(job_item) then if not matinfo:matches(job_item) then
--[[
local true_flags={}
for k,v in pairs(job_item.flags1) do
if v then
table.insert(true_flags,k)
end
end
for k,v in pairs(job_item.flags2) do
if v then
table.insert(true_flags,k)
end
end
for k,v in pairs(job_item.flags3) do
if v then
table.insert(true_flags,k)
end
end
for k,v in pairs(true_flags) do
print(v)
end
--]]
return false,"matinfo" return false,"matinfo"
end end
-- some bonus checks: -- some bonus checks:
@ -586,225 +675,138 @@ function EnumItems(args)
end end
return ret return ret
end end
jobitemEditor=defclass(jobitemEditor,gui.FramedScreen) function putItemsInBuilding(building,job_item_refs)
jobitemEditor.ATTRS{ for k,v in ipairs(job_item_refs) do
frame_style = gui.GREY_LINE_FRAME, --local pos=dfhack.items.getPosition(v)
frame_inset = 1, if not dfhack.items.moveToBuilding(v.item,building,0) then
allow_add=false, print("Could not put item:",k,v.item)
allow_remove=false,
allow_any_item=false,
job=DEFAULT_NIL,
items=DEFAULT_NIL,
}
function jobitemEditor:init(args)
--self.job=args.job
if self.job==nil then qerror("This screen must have job target") end
if self.items==nil then qerror("This screen must have item list") end
local itemChoices={}
table.insert(itemChoices,{text="<nothing>"})
for k,v in pairs(self.items) do
table.insert(itemChoices,{item=v,text=dfhack.items.getDescription(v, 0)})
end
self.itemChoices=itemChoices
self:addviews{
wid.Label{
view_id = 'label',
text = args.prompt,
text_pen = args.text_pen,
frame = { l = 0, t = 0 },
},
wid.List{
view_id = 'itemList',
frame = { l = 0, t = 2 ,b=2},
on_submit = self:callback("selectJobItem")
},
wid.Label{
frame = { b=1,l=1},
text ={{text= ": cancel",
key = "LEAVESCREEN",
on_activate= self:callback("dismiss")
},
{
gap=3,
text= ": accept",
key = "SEC_SELECT",
on_activate= self:callback("commit"),
enabled=self:callback("jobValid")
},
{
gap=3,
text= ": add",
key = "CUSTOM_A",
enabled=false,
--on_activate= self:callback("commit")
},
{
gap=3,
text= ": remove",
key = "CUSTOM_R",
enabled=false,
--on_activate= self:callback("commit")
},}
},
}
self.assigned={}
self:fill(self.job)
end
function jobitemEditor:fill(job)
local choices={}
for item_id, trg_job_item in ipairs(job.job_items) do
local str="<nothing>"
if self.assigned[item_id] ~=nil then
str=dfhack.items.getDescription(self.assigned[item_id],0)
end
local text={string.format("%3d:",item_id)}
if self.assigned[item_id]~=nil then
for subid,assigned_item in ipairs(self.assigned[item_id]) do
table.insert(text," "..dfhack.items.getDescription(assigned_item,0))
table.insert(text,"\n")
end
else
table.insert(text,"<nothing>")
end
table.insert(choices,{text=text,
job_item=trg_job_item,job_item_idx=item_id})
end
self.choices=choices
self.subviews.itemList:setChoices(choices)
end
function jobitemEditor:countMatched(job_item_idx,job_item)
local sum=0
if self.assigned[job_item_idx]==nil then return false end
for k,v in pairs(self.assigned[job_item_idx]) do
sum=sum+v:getTotalDimension()
end
return job_item.quantity<=sum
end
function jobitemEditor:jobValid()
for k,v in pairs(self.job.job_items) do
if not self:countMatched(k,v) then
return false
end
end
return true
end
function jobitemEditor:itemChosen(job_choice,index,choice)
if choice.item==nil then
self.assigned[job_choice.job_item_idx]=nil
else
self.assigned[job_choice.job_item_idx]=self.assigned[job_choice.job_item_idx] or {}
table.insert(self.assigned[job_choice.job_item_idx],choice.item)
if not self:countMatched(job_choice.job_item_idx,job_choice.job_item) then
self:selectJobItem(nil,job_choice)
end
end
self:fill(self.job)
end
function jobitemEditor:selectJobItem(index,choice)
local filtered_items={}
for k,v in pairs(self.itemChoices) do
if (v.text=="<nothing>" or isSuitableItem(choice.job_item,v.item)) and (v.item==nil or not self:isAssigned(v.item)) then
table.insert(filtered_items,v)
end end
v.is_fetching=0
end end
dialog.showListPrompt("Item choice", "Choose item:", nil, filtered_items, self:callback("itemChosen",choice), nil,nil,true) --custom item choice dialog req
end end
function jobitemEditor:isAssigned(item) function putItemsInHauling(unit,job_item_refs)
for k,v in pairs(self.assigned) do for k,v in ipairs(job_item_refs) do
for subid, aitem in pairs(v) do --local pos=dfhack.items.getPosition(v)
if aitem.id==item.id then print("moving:",tostring(v),tostring(v.item))
return true printall(v)
end if not dfhack.items.moveToInventory(v.item,unit,0,0) then
print("Could not put item:",k,v.item)
end end
v.is_fetching=0
end end
end end
function jobitemEditor:commit() function finish_item_assign(args)
local job=args.job
for job_item_id,v in pairs(self.assigned) do local item_modes={
for sub_id,cur_item in pairs(v) do [df.job_type.PlantSeeds]="haul",
self.job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=job_item_id}) [df.job_type.Eat]="haul",
end }
local item_mode=item_modes[job.job_type] or "teleport"
if settings.teleport_items and item_mode=="teleport" then
putItemsInBuilding(args.building,job.items)
end end
local uncollected = getItemsUncollected(job) local uncollected = getItemsUncollected(job)
if #uncollected == 0 then if #uncollected == 0 then
self.job.flags.working=true job.flags.working=true
if item_mode=="haul" then
putItemsInHauling(args.unit,job.items)
end
else else
job.flags.fetching=true
uncollected[1].is_fetching=1 uncollected[1].is_fetching=1
self.job.flags.fetching=true
end end
self:dismiss()
end end
function AssignJobItems(args) function AssignJobItems(args)
print("----")
if settings.df_assign then --use df default logic and hope that it would work if settings.df_assign then --use df default logic and hope that it would work
return true return true
end end
-- first find items that you want to use for the job -- first find items that you want to use for the job
local job=args.job local job=args.job
local its=EnumItems{pos=args.from_pos,unit=args.unit, local its
inv={[df.unit_inventory_item.T_mode.Hauled]=settings.check_inv,[df.unit_inventory_item.T_mode.Worn]=settings.check_inv, if settings.check_inv then
[df.unit_inventory_item.T_mode.Weapon]=settings.check_inv,},deep=true} its=EnumItems{pos=args.from_pos,unit=args.unit,
--[[ job item editor... inv={[df.unit_inventory_item.T_mode.Hauled]=settings.use_worn,[df.unit_inventory_item.T_mode.Worn]=settings.use_worn,
jobitemEditor{job=args.job,items=its}:show() [df.unit_inventory_item.T_mode.Weapon]=settings.use_worn,},deep=true}
local ok=job.flags.working or job.flags.fetching
if not ok then
return ok, "Stuff"
else else
return ok its=EnumItems{pos=args.from_pos}
end end
--]]
-- [=[
--[[while(#job.items>0) do --clear old job items --[[while(#job.items>0) do --clear old job items
job.items[#job.items-1]:delete() job.items[#job.items-1]:delete()
job.items:erase(#job.items-1) job.items:erase(#job.items-1)
end]] end]]
local item_counts={} local item_counts={}
for job_id, trg_job_item in ipairs(job.job_items) do for job_id, trg_job_item in ipairs(job.job_items) do
item_counts[job_id]=trg_job_item.quantity item_counts[job_id]=trg_job_item.quantity
end end
local item_suitability={}
local used_item_id={} local used_item_id={}
for job_id, trg_job_item in ipairs(job.job_items) do for job_id, trg_job_item in ipairs(job.job_items) do
item_suitability[job_id]={}
for _,cur_item in pairs(its) do for _,cur_item in pairs(its) do
if not used_item_id[cur_item.id] then if not used_item_id[cur_item.id] then
local item_suitable,msg=isSuitableItem(trg_job_item,cur_item) local item_suitable,msg=isSuitableItem(trg_job_item,cur_item)
--if msg then if item_suitable or settings.build_by_items then
-- print(cur_item,msg) table.insert(item_suitability[job_id],cur_item)
--end end
--[[
if (item_counts[job_id]>0 and item_suitable) or settings.build_by_items then if msg then
--cur_item.flags.in_job=true print(cur_item,msg)
job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=job_id}) end
item_counts[job_id]=item_counts[job_id]-cur_item:getTotalDimension() --]]
--print(string.format("item added, job_item_id=%d, item %s, quantity left=%d",job_id,tostring(cur_item),item_counts[job_id])) if not settings.gui_item_select then
used_item_id[cur_item.id]=true if (item_counts[job_id]>0 and item_suitable) or settings.build_by_items then
--cur_item.flags.in_job=true
job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=job_id})
item_counts[job_id]=item_counts[job_id]-cur_item:getTotalDimension()
--print(string.format("item added, job_item_id=%d, item %s, quantity left=%d",job_id,tostring(cur_item),item_counts[job_id]))
used_item_id[cur_item.id]=true
end
end end
end end
end end
end end
print("before block")
if not settings.build_by_items then if settings.gui_item_select and #job.job_items>0 then
for job_id, trg_job_item in ipairs(job.job_items) do local item_dialog=require('hack.scripts.gui.advfort_items')
if item_counts[job_id]>0 then --local rr=require('gui.script').start(function()
return false, "Not enough items for this job" print("before dialog")
local ret=item_dialog.showItemEditor(job,item_suitability)
print("post dialog",ret)
--showItemEditor(job,item_suitability)
if ret then
finish_item_assign(args)
return true
else
print("Failed job, i'm confused...")
end end
end
end --end)
local uncollected = getItemsUncollected(job) return false,"Selecting items"
if #uncollected == 0 then
job.flags.working=true
else else
job.flags.fetching=true if not settings.build_by_items then
uncollected[1].is_fetching=1 for job_id, trg_job_item in ipairs(job.job_items) do
if item_counts[job_id]>0 then
print("Not enough items for this job")
return false, "Not enough items for this job"
end
end
end
finish_item_assign(args)
return true
end end
--todo set working for workshops if items are present, else set fetching (and at least one item to is_fetching=1)
--job.flags.working=true
return true
--]=]
end end
function CheckAndFinishBuilding(args,bld)
CheckAndFinishBuilding=function (args,bld)
args.building=args.building or bld
for idx,job in pairs(bld.jobs) do for idx,job in pairs(bld.jobs) do
if job.job_type==df.job_type.ConstructBuilding then if job.job_type==df.job_type.ConstructBuilding then
args.job=job args.job=job
@ -813,21 +815,16 @@ function CheckAndFinishBuilding(args,bld)
end end
if args.job~=nil then if args.job~=nil then
local ok,msg=AssignJobItems(args) args.pre_actions={AssignJobItems}
if not ok then
return false,msg
else
AssignUnitToJob(args.job,args.unit,args.from_pos)
end
else else
local t={items=buildings.getFiltersByType({},bld:getType(),bld:getSubtype(),bld:getCustomType())} local t={items=buildings.getFiltersByType({},bld:getType(),bld:getSubtype(),bld:getCustomType())}
args.pre_actions={dfhack.curry(setFiltersUp,t),AssignJobItems,AssignBuildingRef} args.pre_actions={dfhack.curry(setFiltersUp,t),AssignBuildingRef}--,AssignJobItems
local ok,msg=makeJob(args)
return ok,msg
end end
makeJob(args)
end end
function AssignJobToBuild(args) function AssignJobToBuild(args)
local bld=dfhack.buildings.findAtTile(args.pos) local bld=args.building or dfhack.buildings.findAtTile(args.pos)
args.building=bld
args.job_type=df.job_type.ConstructBuilding args.job_type=df.job_type.ConstructBuilding
if bld~=nil then if bld~=nil then
CheckAndFinishBuilding(args,bld) CheckAndFinishBuilding(args,bld)
@ -864,23 +861,26 @@ function CancelJob(unit)
end end
function ContinueJob(unit) function ContinueJob(unit)
local c_job=unit.job.current_job local c_job=unit.job.current_job
if c_job then --no job to continue
c_job.flags.suspend=false if not c_job then return end
for k,v in pairs(c_job.items) do --reset suspends...
if v.is_fetching==1 then c_job.flags.suspend=false
unit.path.dest:assign(v.item.pos) for k,v in pairs(c_job.items) do --try fetching missing items
return if v.is_fetching==1 then
end unit.path.dest:assign(v.item.pos)
return
end end
unit.path.dest:assign(c_job.pos)
end end
--unit.path.dest:assign(c_job.pos) -- FIXME: job pos is not always the target pos!!
addJobAction(c_job,unit)
end end
actions={ actions={
{"CarveFortification" ,df.job_type.CarveFortification,{IsWall,IsHardMaterial}}, {"CarveFortification" ,df.job_type.CarveFortification,{IsWall,IsHardMaterial}},
{"DetailWall" ,df.job_type.DetailWall,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall,IsHardMaterial}}, {"DetailWall" ,df.job_type.DetailWall,{IsWall,IsHardMaterial}},
{"DetailFloor" ,df.job_type.DetailFloor,{MakePredicateWieldsItem(df.job_skill.MINING),IsFloor,IsHardMaterial,SameSquare}}, {"DetailFloor" ,df.job_type.DetailFloor,{IsFloor,IsHardMaterial,SameSquare}},
{"CarveTrack" ,df.job_type.CarveTrack,{MakePredicateWieldsItem(df.job_skill.MINING),IsFloor,IsHardMaterial} {"CarveTrack" ,df.job_type.CarveTrack,{IsFloor,IsHardMaterial}
,{SetCarveDir}}, ,{SetCarveDir}},
{"Dig" ,df.job_type.Dig,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}}, {"Dig" ,df.job_type.Dig,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}},
{"CarveUpwardStaircase" ,df.job_type.CarveUpwardStaircase,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}}, {"CarveUpwardStaircase" ,df.job_type.CarveUpwardStaircase,{MakePredicateWieldsItem(df.job_skill.MINING),IsWall}},
@ -950,11 +950,10 @@ function usetool:init(args)
} }
} }
} }
end local labors=df.global.world.units.active[0].status.labors
for i,v in ipairs(labors) do
function usetool:onIdle() labors[i]=true
end
self._native.parent:logic()
end end
MOVEMENT_KEYS = { MOVEMENT_KEYS = {
A_CARE_MOVE_N = { 0, -1, 0 }, A_CARE_MOVE_S = { 0, 1, 0 }, A_CARE_MOVE_N = { 0, -1, 0 }, A_CARE_MOVE_S = { 0, 1, 0 },
@ -1000,24 +999,11 @@ function setFiltersUp(specific,args)
end end
function onWorkShopJobChosen(args,idx,choice) function onWorkShopJobChosen(args,idx,choice)
args.pos=args.from_pos args.pos=args.from_pos
args.building=args.building or dfhack.buildings.findAtTile(args.pos)
args.job_type=choice.job_id args.job_type=choice.job_id
args.post_actions={AssignBuildingRef} args.post_actions={AssignBuildingRef}
args.pre_actions={dfhack.curry(setFiltersUp,choice.filter),AssignJobItems} args.pre_actions={dfhack.curry(setFiltersUp,choice.filter),AssignJobItems}
local job,msg=makeJob(args) makeJob(args)
if not job then
dfhack.gui.showAnnouncement(msg,5,1)
end
args.job=job
--[[for _,v in ipairs(choice.filter) do
local filter=require("utils").clone(args.common)
filter.new=true
require("utils").assign(filter,v)
--printall(filter)
job.job_items:insert("#",filter)
end--]]
--local ok,msg=AssignJobItems(args)
--print(ok,msg)
end end
function siegeWeaponActionChosen(building,actionid) function siegeWeaponActionChosen(building,actionid)
local args local args
@ -1051,10 +1037,7 @@ function siegeWeaponActionChosen(building,actionid)
end end
if args~=nil then if args~=nil then
args.post_actions={AssignBuildingRef} args.post_actions={AssignBuildingRef}
local ok,msg=makeJob(args) makeJob(args)
if not ok then
dfhack.gui.showAnnouncement(msg,5,1)
end
end end
end end
function putItemToBuilding(building,item) function putItemToBuilding(building,item)
@ -1083,12 +1066,19 @@ function usetool:openSiegeWindow(building)
end end
function usetool:onWorkShopButtonClicked(building,index,choice) function usetool:onWorkShopButtonClicked(building,index,choice)
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
local args={unit=adv,building=building}
if df.interface_button_building_new_jobst:is_instance(choice.button) then if df.interface_button_building_new_jobst:is_instance(choice.button) then
print("pre-click")
choice.button:click() choice.button:click()
print("post-click",#building.jobs)
if #building.jobs>0 then if #building.jobs>0 then
local job=building.jobs[#building.jobs-1] local job=building.jobs[#building.jobs-1]
AssignUnitToJob(job,adv,adv.pos) args.job=job
AssignJobItems{job=job,from_pos=adv.pos,pos=adv.pos,unit=adv} args.pos=adv.pos
args.from_pos=adv.pos
args.pre_actions={AssignJobItems}
args.screen=self
makeJob(args)
end end
elseif df.interface_button_building_category_selectorst:is_instance(choice.button) or elseif df.interface_button_building_category_selectorst:is_instance(choice.button) or
df.interface_button_building_material_selectorst:is_instance(choice.button) then df.interface_button_building_material_selectorst:is_instance(choice.button) then
@ -1133,7 +1123,7 @@ function usetool:openShopWindow(building)
local filter_pile=workshopJobs.getJobs(building:getType(),building:getSubtype(),building:getCustomType()) local filter_pile=workshopJobs.getJobs(building:getType(),building:getSubtype(),building:getCustomType())
if filter_pile then if filter_pile then
local state={unit=adv,from_pos={x=adv.pos.x,y=adv.pos.y, z=adv.pos.z} local state={unit=adv,from_pos={x=adv.pos.x,y=adv.pos.y, z=adv.pos.z,building=building}
,screen=self,bld=building,common=filter_pile.common} ,screen=self,bld=building,common=filter_pile.common}
choices={} choices={}
for k,v in pairs(filter_pile) do for k,v in pairs(filter_pile) do
@ -1167,7 +1157,8 @@ function usetool:armCleanTrap(building)
end end
--building.trap_type==df.trap_type.PressurePlate then --building.trap_type==df.trap_type.PressurePlate then
--settings/link --settings/link
local args={unit=adv,post_actions={AssignBuildingRef,AssignJobItems},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.CleanTrap} local args={unit=adv,post_actions={AssignBuildingRef,AssignJobItems},pos=adv.pos,from_pos=adv.pos,
building=building,job_type=df.job_type.CleanTrap}
if building.trap_type==df.trap_type.CageTrap then if building.trap_type==df.trap_type.CageTrap then
args.job_type=df.job_type.LoadCageTrap args.job_type=df.job_type.LoadCageTrap
local job_filter={items={{quantity=1,item_type=df.item_type.CAGE}} } local job_filter={items={{quantity=1,item_type=df.item_type.CAGE}} }
@ -1182,28 +1173,24 @@ function usetool:armCleanTrap(building)
else else
return return
end end
local job,msg=makeJob(args) args.screen=self
if not job then makeJob(args)
print(msg)
end
end end
end end
function usetool:hiveActions(building) function usetool:hiveActions(building)
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
local args={unit=adv,post_actions={AssignBuildingRef,AssignJobItems},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.InstallColonyInHive} local args={unit=adv,post_actions={AssignBuildingRef,AssignJobItems},pos=adv.pos,
from_pos=adv.pos,job_type=df.job_type.InstallColonyInHive,building=building,screen=self}
local job_filter={items={{quantity=1,item_type=df.item_type.VERMIN}} } local job_filter={items={{quantity=1,item_type=df.item_type.VERMIN}} }
args.pre_actions={dfhack.curry(setFiltersUp,job_filter)} args.pre_actions={dfhack.curry(setFiltersUp,job_filter)}
local job,msg=makeJob(args) makeJob(args)
if not job then
print(msg)
end
--InstallColonyInHive, --InstallColonyInHive,
--CollectHiveProducts, --CollectHiveProducts,
end end
function usetool:operatePump(building) function usetool:operatePump(building)
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
makeJob{unit=adv,post_actions={AssignBuildingRef},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.OperatePump} makeJob{unit=adv,post_actions={AssignBuildingRef},pos=adv.pos,from_pos=adv.pos,job_type=df.job_type.OperatePump,screen=self}
end end
function usetool:farmPlot(building) function usetool:farmPlot(building)
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
@ -1217,25 +1204,31 @@ function usetool:farmPlot(building)
end end
--check if there tile is without plantseeds,add job --check if there tile is without plantseeds,add job
local args={unit=adv,pos=adv.pos,from_pos=adv.pos, local args={unit=adv,pos=adv.pos,from_pos=adv.pos,screen=self}
} if do_harvest then
if not do_harvest then
local seedjob={items={{quantity=1,item_type=df.item_type.SEEDS}}}
args.job_type=df.job_type.PlantSeeds
args.pre_actions={dfhack.curry(setFiltersUp,seedjob)}
args.post_actions={AssignBuildingRef}
else
args.job_type=df.job_type.HarvestPlants args.job_type=df.job_type.HarvestPlants
args.post_actions={AssignBuildingRef} args.post_actions={AssignBuildingRef}
end
local job,msg=makeJob(args)
if not job then
print(msg)
else else
--print(AssignJobItems(args)) --WHY U NO WORK? local seedjob={items={{quantity=1,item_type=df.item_type.SEEDS}}}
args.job_type=df.job_type.PlantSeeds
args.pre_actions={dfhack.curry(setFiltersUp,seedjob)}
args.post_actions={AssignBuildingRef,AssignJobItems}
end end
makeJob(args)
end
function usetool:bedActions(building)
local adv=df.global.world.units.active[0]
local args={unit=adv,pos=adv.pos,from_pos=adv.pos,screen=self,building=building,
job_type=df.job_type.Sleep,post_actions={AssignBuildingRef}}
makeJob(args)
end
function usetool:chairActions(building)
local adv=df.global.world.units.active[0]
local eatjob={items={{quantity=1,item_type=df.item_type.FOOD}}}
local args={unit=adv,pos=adv.pos,from_pos=adv.pos,screen=self,job_type=df.job_type.Eat,building=building,
pre_actions={dfhack.curry(setFiltersUp,eatjob),AssignJobItems},post_actions={AssignBuildingRef}}
makeJob(args)
end end
MODES={ MODES={
[df.building_type.Table]={ --todo filters... [df.building_type.Table]={ --todo filters...
@ -1289,7 +1282,15 @@ MODES={
[df.building_type.Hive]={ [df.building_type.Hive]={
name="Hive actions", name="Hive actions",
input=usetool.hiveActions, input=usetool.hiveActions,
} },
[df.building_type.Bed]={
name="Rest",
input=usetool.bedActions,
},
[df.building_type.Chair]={
name="Eat",
input=usetool.chairActions,
},
} }
function usetool:shopMode(enable,mode,building) function usetool:shopMode(enable,mode,building)
self.subviews.shopLabel.visible=enable self.subviews.shopLabel.visible=enable
@ -1304,7 +1305,9 @@ function usetool:shopInput(keys)
self:openShopWindowButtoned(self.in_shop) self:openShopWindowButtoned(self.in_shop)
end end
end end
function usetool:wait_tick()
self:sendInputToParent("A_SHORT_WAIT")
end
function usetool:setupFields() function usetool:setupFields()
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
local civ_id=df.global.world.units.active[0].civ_id local civ_id=df.global.world.units.active[0].civ_id
@ -1358,7 +1361,7 @@ function usetool:fieldInput(keys)
if type(cur_mode[2])=="function" then if type(cur_mode[2])=="function" then
ok,msg=cur_mode[2](state) ok,msg=cur_mode[2](state)
else else
ok,msg=makeJob(state) makeJob(state)
--(adv,moddedpos(adv.pos,MOVEMENT_KEYS[code]),cur_mode[2],adv.pos,cur_mode[4]) --(adv,moddedpos(adv.pos,MOVEMENT_KEYS[code]),cur_mode[2],adv.pos,cur_mode[4])
end end
@ -1366,11 +1369,7 @@ function usetool:fieldInput(keys)
if code=="SELECT" then if code=="SELECT" then
self:sendInputToParent("LEAVESCREEN") self:sendInputToParent("LEAVESCREEN")
end end
if ok then self.long_wait=true
self:sendInputToParent("A_WAIT")
else
dfhack.gui.showAnnouncement(msg,5,1)
end
end end
return code return code
end end
@ -1399,9 +1398,13 @@ function usetool:onInput(keys)
if mode<0 then mode=#actions-1 end if mode<0 then mode=#actions-1 end
--elseif keys.A_LOOK then --elseif keys.A_LOOK then
-- self:sendInputToParent("A_LOOK") -- self:sendInputToParent("A_LOOK")
elseif keys["A_SHORT_WAIT"] then
--ContinueJob(adv)
self:sendInputToParent("A_SHORT_WAIT")
elseif keys[keybinds.continue.key] then elseif keys[keybinds.continue.key] then
ContinueJob(adv) --ContinueJob(adv)
self:sendInputToParent("A_WAIT") --self:sendInputToParent("A_SHORT_WAIT")
self.long_wait=true
else else
if self.mode~=nil then if self.mode~=nil then
if keys[keybinds.workshop.key] then if keys[keybinds.workshop.key] then
@ -1421,6 +1424,21 @@ function usetool:onInput(keys)
self.subviews.siteLabel.visible=false self.subviews.siteLabel.visible=false
end end
end end
function usetool:onIdle()
local adv=df.global.world.units.active[0]
local job_ptr=adv.job.current_job
local job_action=findAction(adv,df.unit_action_type.Job)
if job_ptr and self.long_wait and not job_action then
if adv.job.current_job.completion_timer==-1 then
self.long_wait=false
end
ContinueJob(adv)
self:sendInputToParent("A_SHORT_WAIT") --todo continue till finished
end
self._native.parent:logic()
end
function usetool:isOnBuilding() function usetool:isOnBuilding()
local adv=df.global.world.units.active[0] local adv=df.global.world.units.active[0]
local bld=dfhack.buildings.findAtTile(adv.pos) local bld=dfhack.buildings.findAtTile(adv.pos)

@ -0,0 +1,163 @@
local _ENV = mkmodule('hack.scripts.gui.advfort_items')
local gui=require('gui')
local wid=require('gui.widgets')
local gscript=require('gui.script')
jobitemEditor=defclass(jobitemEditor,gui.FramedScreen)
jobitemEditor.ATTRS{
frame_style = gui.GREY_LINE_FRAME,
frame_inset = 1,
allow_add=false,
allow_remove=false,
allow_any_item=false,
job=DEFAULT_NIL,
items=DEFAULT_NIL,
on_okay=DEFAULT_NIL,
}
function update_slot_text(slot)
local items=""
for i,v in ipairs(slot.items) do
items=items.." "..dfhack.items.getDescription(v,0)
if i~=#slot.items then
items=items..","
end
end
slot.text=string.format("%02d. Filled(%d/%d):%s",slot.id+1,slot.filled_amount,slot.job_item.quantity,items)
end
--items-> table => key-> id of job.job_items, value-> table => key (num), value => item(ref)
function jobitemEditor:init(args)
--self.job=args.job
if self.job==nil then qerror("This screen must have job target") end
if self.items==nil then qerror("This screen must have item list") end
self:addviews{
wid.Label{
view_id = 'label',
text = args.prompt,
text_pen = args.text_pen,
frame = { l = 0, t = 0 },
},
wid.List{
view_id = 'itemList',
frame = { l = 0, t = 2 ,b=2},
},
wid.Label{
frame = { b=1,l=1},
text ={{text= ": cancel",
key = "LEAVESCREEN",
on_activate= self:callback("dismiss")
},
{
gap=3,
text= ": accept",
key = "SEC_SELECT",
on_activate= self:callback("commit"),
enabled=self:callback("jobValid")
},
{
gap=3,
text= ": add",
key = "CUSTOM_A",
enabled=self:callback("can_add"),
on_activate= self:callback("add_item")
},
{
gap=3,
text= ": remove",
key = "CUSTOM_R",
enabled=self:callback("can_remove"),
on_activate= self:callback("remove_item")
},}
},
}
self.assigned={}
self:fill()
end
function jobitemEditor:get_slot()
local idx,choice=self.subviews.itemList:getSelected()
return choice
end
function jobitemEditor:can_add()
local slot=self:get_slot()
return slot.filled_amount<slot.job_item.quantity
end
function jobitemEditor:can_remove()
local slot=self:get_slot()
return #slot.items>0
end
function jobitemEditor:add_item()
local cur_slot=self:get_slot()
local choices={}
table.insert(choices,{text="<no item>"})
for k,v in pairs(cur_slot.choices) do
if not self.assigned[v.id] then
table.insert(choices,{text=dfhack.items.getDescription(v,0),item=v})
end
end
gscript.start(function ()
local _,_2,choice=gscript.showListPrompt("which item?", "Select item", COLOR_WHITE, choices)
if choice ~= nil and choice.item~=nil then
self:add_item_to_slot(cur_slot,choice.item)
end
end
)
end
function jobitemEditor:add_item_to_slot(slot,item)
table.insert(slot.items,item)
slot.filled_amount=slot.filled_amount+item:getTotalDimension()
self.assigned[item.id]=true
update_slot_text(slot)
self.subviews.itemList:setChoices(self.slots)
end
function jobitemEditor:remove_item()
local slot=self:get_slot()
for k,v in pairs(slot.items) do
self.assigned[v.id]=nil
end
slot.items={}
slot.filled_amount=0
update_slot_text(slot)
self.subviews.itemList:setChoices(self.slots)
end
function jobitemEditor:fill()
self.slots={}
for k,v in pairs(self.items) do
table.insert(self.slots,{job_item=self.job.job_items[k], id=k, items={},choices=v,filled_amount=0,slot_id=#self.slots})
update_slot_text(self.slots[#self.slots])
end
self.subviews.itemList:setChoices(self.slots)
end
function jobitemEditor:jobValid()
for k,v in pairs(self.slots) do
if v.filled_amount<v.job_item.quantity then
return false
end
end
return true
end
function jobitemEditor:commit()
for _,slot in pairs(self.slots) do
for _1,cur_item in pairs(slot.items) do
self.job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=slot.id})
end
end
self:dismiss()
if self.on_okay then self:on_okay() end
end
function showItemEditor(job,item_selections)
jobitemEditor{
job = job,
items = item_selections,
on_close = gscript.qresume(nil),
on_okay = gscript.mkresume(true)
--on_cancel=gscript.mkresume(false)
}:show()
return gscript.wait()
end
return _ENV

@ -71,7 +71,7 @@ function getMatFilter(itemtype)
end end
function getRestrictiveMatFilter(itemType) function getRestrictiveMatFilter(itemType)
if not args.veryRestrictive then return nil else if not args.restrictive then return nil end
local itemTypes={ local itemTypes={
WEAPON=function(mat,parent,typ,idx) WEAPON=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_WEAPON or mat.flags.ITEMS_WEAPON_RANGED) return (mat.flags.ITEMS_WEAPON or mat.flags.ITEMS_WEAPON_RANGED)
@ -82,15 +82,12 @@ function getRestrictiveMatFilter(itemType)
ARMOR=function(mat,parent,typ,idx) ARMOR=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_ARMOR) return (mat.flags.ITEMS_ARMOR)
end, end,
SHOES,SHIELD,HELM,GLOVES=ARMOR,ARMOR,ARMOR,ARMOR,
INSTRUMENT=function(mat,parent,typ,idx) INSTRUMENT=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_HARD) return (mat.flags.ITEMS_HARD)
end, end,
GOBLET,FLASK,TOY,RING,CROWN,SCEPTER,FIGURINE,TOOL=INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,INSTRUMENT,
AMULET=function(mat,parent,typ,idx) AMULET=function(mat,parent,typ,idx)
return (mat.flags.ITEMS_SOFT or mat.flags.ITEMS_HARD) return (mat.flags.ITEMS_SOFT or mat.flags.ITEMS_HARD)
end, end,
EARRING,BRACELET=AMULET,AMULET,
ROCK=function(mat,parent,typ,idx) ROCK=function(mat,parent,typ,idx)
return (mat.flags.IS_STONE) return (mat.flags.IS_STONE)
end, end,
@ -100,8 +97,17 @@ function getRestrictiveMatFilter(itemType)
end end
} }
return itemTypes[df.item_type[itemType]] for k,v in ipairs({'GOBLET','FLASK','TOY','RING','CROWN','SCEPTER','FIGURINE','TOOL'}) do
itemTypes[v]=itemTypes.INSTRUMENT
end
for k,v in ipairs({'SHOES','SHIELD','HELM','GLOVES'}) do
itemTypes[v]=itemTypes.ARMOR
end end
for k,v in ipairs({'EARRING','BRACELET'}) do
itemTypes[v]=itemTypes.AMULET
end
itemTypes.BOULDER=itemTypes.ROCK
return itemTypes[df.item_type[itemType]]
end end
function createItem(mat,itemType,quality,creator,description) function createItem(mat,itemType,quality,creator,description)