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,31 +163,66 @@ 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 end
function makeJob(args) 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
function make_native_job(args)
if args.job == nil then
local newJob=df.job:new() local newJob=df.job:new()
newJob.id=df.global.job_next_id newJob.id=df.global.job_next_id
df.global.job_next_id=df.global.job_next_id+1 df.global.job_next_id=df.global.job_next_id+1
--newJob.flags.special=true newJob.flags.special=true
newJob.job_type=args.job_type newJob.job_type=args.job_type
newJob.completion_timer=-1 newJob.completion_timer=-1
newJob.pos:assign(args.pos) newJob.pos:assign(args.pos)
--newJob.pos:assign(args.unit.pos)
args.job=newJob args.job=newJob
args.unlinked=true
end
end
function makeJob(args)
gscript.start(function ()
make_native_job(args)
local failed local failed
for k,v in ipairs(args.pre_actions or {}) do for k,v in ipairs(args.pre_actions or {}) do
local ok,msg=v(args) local ok,msg=v(args)
@ -172,7 +232,7 @@ function makeJob(args)
end end
end end
if failed==nil then if failed==nil then
AssignUnitToJob(newJob,args.unit,args.from_pos) AssignUnitToJob(args.job,args.unit,args.from_pos)
for k,v in ipairs(args.post_actions or {}) do for k,v in ipairs(args.post_actions or {}) do
local ok,msg=v(args) local ok,msg=v(args)
if not ok then if not ok then
@ -181,17 +241,21 @@ function makeJob(args)
end end
end end
if failed then if failed then
UnassignJob(newJob,args.unit) UnassignJob(args.job,args.unit)
end end
end end
if failed==nil then if failed==nil then
addNewJob(newJob) if args.unlinked then
return newJob dfhack.job.linkIntoWorld(args.job,true)
args.unlinked=false
end
addJobAction(args.job,args.unit)
args.screen:wait_tick()
else else
newJob:delete() args.job:delete()
return false,failed dfhack.gui.showAnnouncement(msg,5,1)
end 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,193 +675,91 @@ 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 end
return true v.is_fetching=0
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
end
self:fill(self.job)
end end
function jobitemEditor:selectJobItem(index,choice) function putItemsInHauling(unit,job_item_refs)
local filtered_items={} for k,v in ipairs(job_item_refs) do
for k,v in pairs(self.itemChoices) do --local pos=dfhack.items.getPosition(v)
if (v.text=="<nothing>" or isSuitableItem(choice.job_item,v.item)) and (v.item==nil or not self:isAssigned(v.item)) then print("moving:",tostring(v),tostring(v.item))
table.insert(filtered_items,v) printall(v)
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
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 finish_item_assign(args)
for k,v in pairs(self.assigned) do local job=args.job
for subid, aitem in pairs(v) do local item_modes={
if aitem.id==item.id then [df.job_type.PlantSeeds]="haul",
return true [df.job_type.Eat]="haul",
end }
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
end
function jobitemEditor:commit()
for job_item_id,v in pairs(self.assigned) do
for sub_id,cur_item in pairs(v) do
self.job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=job_item_id})
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 msg then
print(cur_item,msg)
end
--]]
if not settings.gui_item_select then
if (item_counts[job_id]>0 and item_suitable) or settings.build_by_items then if (item_counts[job_id]>0 and item_suitable) or settings.build_by_items then
--cur_item.flags.in_job=true --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}) job.items:insert("#",{new=true,item=cur_item,role=df.job_item_ref.T_role.Reagent,job_item_idx=job_id})
@ -783,28 +770,43 @@ function AssignJobItems(args)
end end
end end
end end
end
print("before block")
if settings.gui_item_select and #job.job_items>0 then
local item_dialog=require('hack.scripts.gui.advfort_items')
--local rr=require('gui.script').start(function()
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)
return false,"Selecting items"
else
if not settings.build_by_items then if not settings.build_by_items then
for job_id, trg_job_item in ipairs(job.job_items) do for job_id, trg_job_item in ipairs(job.job_items) do
if item_counts[job_id]>0 then if item_counts[job_id]>0 then
print("Not enough items for this job")
return false, "Not enough items for this job" return false, "Not enough items for this job"
end end
end end
end end
local uncollected = getItemsUncollected(job) finish_item_assign(args)
if #uncollected == 0 then
job.flags.working=true
else
job.flags.fetching=true
uncollected[1].is_fetching=1
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 return true
--]=] end
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
if not c_job then return end
--reset suspends...
c_job.flags.suspend=false c_job.flags.suspend=false
for k,v in pairs(c_job.items) do for k,v in pairs(c_job.items) do --try fetching missing items
if v.is_fetching==1 then if v.is_fetching==1 then
unit.path.dest:assign(v.item.pos) unit.path.dest:assign(v.item.pos)
return return
end end
end end
unit.path.dest:assign(c_job.pos)
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 args.job_type=df.job_type.HarvestPlants
args.post_actions={AssignBuildingRef}
else
local seedjob={items={{quantity=1,item_type=df.item_type.SEEDS}}} local seedjob={items={{quantity=1,item_type=df.item_type.SEEDS}}}
args.job_type=df.job_type.PlantSeeds args.job_type=df.job_type.PlantSeeds
args.pre_actions={dfhack.curry(setFiltersUp,seedjob)} args.pre_actions={dfhack.curry(setFiltersUp,seedjob)}
args.post_actions={AssignBuildingRef} args.post_actions={AssignBuildingRef,AssignJobItems}
else
args.job_type=df.job_type.HarvestPlants
args.post_actions={AssignBuildingRef}
end end
local job,msg=makeJob(args)
if not job then
print(msg)
else
--print(AssignJobItems(args)) --WHY U NO WORK?
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)