dfhack/scripts/modtools/reaction-trigger.lua

180 lines
4.7 KiB
Lua

-- reaction-trigger.lua
-- author expwnent
-- replaces autoSyndrome: trigger commands when custom reactions are completed
local eventful = require 'plugins.eventful'
local syndromeUtil = require 'syndromeUtil'
local utils = require 'utils'
reactionHooks = reactionHooks or {}
local function getWorkerAndBuilding(job)
local workerId = -1
local buildingId = -1
for _,generalRef in ipairs(job.general_refs) do
if generalRef:getType() == df.general_ref_type.UNIT_WORKER then
if workerId ~= -1 then
print(job)
printall(job)
error('reaction-trigger: two workers on same job: ' .. workerId .. ', ' .. generalRef.unit_id)
else
workerId = generalRef.unit_id
if workerId == -1 then
print(job)
printall(job)
error('reaction-trigger: invalid worker')
end
end
elseif generalRef:getType() == df.general_ref_type.BUILDING_HOLDER then
if buildingId ~= -1 then
print(job)
printall(job)
error('reaction-trigger: two buildings same job: ' .. buildingId .. ', ' .. generalRef.building_id)
else
buildingId = generalRef.building_id
if buildingId == -1 then
print(job)
printall(job)
error('reaction-trigger: invalid building')
end
end
end
end
return workerId,buildingId
end
local function processCommand(job, worker, target, building, command)
local result = {}
for _,arg in ipairs(command) do
if arg == '\\WORKER_ID' then
table.insert(result,''..worker.id)
elseif arg == '\\TARGET_ID' then
table.insert(restul,''..target.id)
elseif arg == '\\BUILDING_ID' then
table.insert(result,''..building.id)
elseif arg == '\\LOCATION' then
table.insert(result,''..job.pos.x)
table.insert(result,''..job.pos.y)
table.insert(result,''..job.pos.z)
elseif arg == '\\REACTION_NAME' then
table.insert(result,''..job.reaction_name)
else
table.insert(result,arg)
end
end
return result
end
eventful.onJobCompleted.reactionTrigger = function(job)
if job.completion_timer > 0 then
return
end
-- if job.job_type ~= df.job_type.CustomReaction then
-- --TODO: support builtin reaction triggers if someone asks
-- return
-- end
if not job.reaction_name or job.reaction_name == '' then
return
end
-- print('reaction name: ' .. job.reaction_name)
if not job.reaction_name or not reactionHooks[job.reaction_name] then
return
end
local worker,building = getWorkerAndBuilding(job)
worker = df.unit.find(worker)
building = df.building.find(building)
if not worker or not building then
--this probably means that it finished before EventManager could get a copy of the job while the job was running
--TODO: consider printing a warning once
return
end
local function doAction(action)
local didSomething
if action.command then
local processed = processCommand(job, worker, worker, building, action.command)
print(dfhack.run_command(table.unpack(processed)))
end
if action.syndrome then
didSomething = syndromeUtil.infectWithSyndromeIfValidTarget(worker, action.syndrome, action.resetPolicy) or didSomething
end
if action.workerOnly then
return
end
if didSomething and not action.allowMultipleTargets then
return
end
local function foreach(unit)
if unit == worker then
return false
elseif unit.pos.z ~= building.z then
return false
elseif unit.pos.x < building.x1 or unit.pos.x > building.x2 then
return false
elseif unit.pos.y < building.y1 or unit.pos.y > building.y2 then
return false
else
if action.command then
processCommand(job, worker, unit, building, action.command)
end
if action.syndrome then
didSomething = syndrome.infectWithSyndromeIfValidTarget(unit,action.syndrome,action.resetPolicy) or didSomething
end
if didSomething and not action.allowMultipleTargets then
return true
end
return false
end
end
for _,unit in ipairs(df.global.world.units.all) do
if foreach(unit) then
break
end
end
end
for _,action in ipairs(reactionHooks[job.reaction_name]) do
doAction(action)
end
end
eventful.enableEvent(eventful.eventType.JOB_COMPLETED,0)
validArgs = utils.invert({
'help',
'clear',
'reactionName',
'syndrome',
'command'
})
local args = utils.processArgs({...}, validArgs)
if args.clear then
reactionHooks = {}
end
if not args.reactionName then
return
end
if not reactionHooks[args.reactionName] then
reactionHooks[args.reactionName] = {}
end
if args.syndrome then
local foundIt
for _,syndrome in ipairs(df.global.world.raws.syndromes.all) do
if syndrome.syn_name == args.syndrome then
args.syndrome = syndrome
foundIt = true
break
end
end
if not foundIt then
error('Could not find syndrome ' .. args.syndrome)
end
end
table.insert(reactionHooks[args.reactionName], args)