--scripts/modtools/interaction-trigger.lua
--author expwnent
--triggers scripts when a unit does a unit interaction on another

local eventful = require 'plugins.eventful'
local utils = require 'utils'

attackTriggers = attackTriggers or {}
defendTriggers = defendTriggers or {}
commands = commands or {}
commandCount = commandCount or 0

eventful.enableEvent(eventful.eventType.INTERACTION,1) --cheap, so every tick is fine
eventful.enableEvent(eventful.eventType.UNLOAD,1)

eventful.onUnload.interactionTrigger = function()
 attackTriggers = {}
 defendTriggers = {}
 commands = {}
 commandCount = 0
end

local function processTrigger(args)
 local command = {}
 for _,arg in ipairs(args.command) do
  if arg == '\\ATTACK_VERB' then
   table.insert(command,args.attackVerb)
  elseif arg == '\\DEFEND_VERB' then
   table.insert(command,args.defendVerb)
  elseif arg == '\\ATTACKER_ID' then
   table.insert(command,args.attackerId)
  elseif arg == '\\DEFENDER_ID' then
   table.insert(command,args.defenderId)
  elseif arg == '\\ATTACK_REPORT' then
   table.insert(command,args.attackReport)
  elseif arg == '\\DEFEND_REPORT' then
   table.insert(command,args.defendReport)
  elseif string.sub(arg,1,1) == '\\' then
   table.insert(command,string.sub(arg,2))
  else
   table.insert(command,arg)
  end
 end
 dfhack.run_command(table.unpack(command))
end

eventful.onInteraction.interactionTrigger = function(attackVerb, defendVerb, attacker, defender, attackReport, defendReport)
 local extras = {}
 extras.attackVerb = attackVerb
 extras.defendVerb = defendVerb
 extras.attackReport = attackReport
 extras.defendReport = defendReport
 extras.attackerId = attacker
 extras.defenderId = defender
 local suppressAttack = false
 local suppressDefend = false
 local todo = {}
 for _,trigger in ipairs(attackTriggers[attackVerb] or {}) do
  todo[trigger] = true
 end
 for _,trigger in ipairs(defendTriggers[defendVerb] or {}) do
  todo[trigger] = true
 end
 for k,v in pairs(todo) do
  command = commands[k]
  suppressAttack = suppressAttack or command.suppressAttack
  suppressDefend = suppressDefend or command.suppressDefend
  utils.fillTable(command,extras)
  processTrigger(command)
  utils.unfillTable(command,extras)
 end
 
 local eraseReport = function(unit,report)
  for i,v in ipairs(unit.reports.log.Combat) do
   if v == report then
    unit.reports.log.Combat:erase(i)
    break
   end
  end
 end
 if suppressAttack or suppressDefend then
  attacker = df.unit.find(tonumber(attacker))
  defender = df.unit.find(tonumber(defender))
 end
 if suppressAttack then
  eraseReport(attacker,attackReport)
  eraseReport(defender,attackReport)
 end
 if suppressDefend then
  eraseReport(attacker,defendReport)
  eraseReport(defender,defendReport)
 end
  --TODO: get rid of combat report on LHS of screen
end

----------------------------------------------------
--argument processing

validArgs = validArgs or utils.invert({
 'clear',
 'help',
 'onAttackStr',
 'onDefendStr',
 'command',
 'suppressAttack',
 'suppressDefend',
})

local args = utils.processArgs({...}, validArgs)

if args.help then
 print([[scripts/modtools/interaction-trigger.lua
arguments:
    -help
        print this help message
    -clear
        unregisters all triggers
    -onAttackStr str
        trigger the command when the attack verb is "str". both onAttackStr and onDefendStr MUST be specified
    -onDefendStr str
        trigger the command when the defend verb is "str". both onAttackStr and onDefendStr MUST be specified
    -suppressAttack
        delete the attack announcement from the combat logs
    -suppressDefend
        delete the defend announcement from the combat logs
    -command [ commandStrs ]
        specify the command to be executed
        commandStrs
            \\ATTACK_VERB
            \\DEFEND_VERB
            \\ATTACKER_ID
            \\DEFENDER_ID
            \\ATTACK_REPORT
            \\DEFEND_REPORT
            \\anything -> \anything
            anything -> anything
You must specify both an attack string and a defend string to guarantee correct performance. Either will trigger the script when it happens, but it will not be triggered twice in a row if both happen.
]])
 return
end

if args.clear then
 triggers = {}
 commands = {}
 commandCount = 0
end

if not args.command then
 return
end

commands[commandCount] = args

if args.onAttackStr then
 if not attackTriggers[args.onAttackStr] then
  attackTriggers[args.onAttackStr] = {}
 end
 table.insert(attackTriggers[args.onAttackStr],commandCount)
end

if args.onDefendStr then
 if not defendTriggers[args.onDefendStr] then
  defendTriggers[args.onDefendStr] = {}
 end
 table.insert(defendTriggers[args.onDefendStr],commandCount)
end

commandCount = commandCount+1