2015-11-09 19:52:20 -07:00
-- trigger commands based on attacks with certain items
2014-06-30 06:16:10 -06:00
--author expwnent
--based on itemsyndrome by Putnam
2014-07-09 04:21:52 -06:00
--triggers scripts when a unit attacks another with a weapon type, a weapon of a particular material, or a weapon contaminated with a particular material, or when a unit equips/unequips a particular item type, an item of a particular material, or an item contaminated with a particular material
2015-10-23 17:57:04 -06:00
--[[=begin
2014-06-30 06:16:10 -06:00
2015-10-23 17:57:04 -06:00
modtools / item - trigger
=====================
This powerful tool triggers DFHack commands when a unit equips , unequips , or
attacks another unit with specified item types , specified item materials , or
specified item contaminants .
= end ] ]
2014-06-30 06:16:10 -06:00
local eventful = require ' plugins.eventful '
local utils = require ' utils '
itemTriggers = itemTriggers or { }
materialTriggers = materialTriggers or { }
contaminantTriggers = contaminantTriggers or { }
2014-07-03 14:57:56 -06:00
eventful.enableEvent ( eventful.eventType . UNIT_ATTACK , 1 ) -- this event type is cheap, so checking every tick is fine
2014-07-07 03:52:54 -06:00
eventful.enableEvent ( eventful.eventType . INVENTORY_CHANGE , 5 ) --this is expensive, but you might still want to set it lower
2014-07-03 14:57:56 -06:00
eventful.enableEvent ( eventful.eventType . UNLOAD , 1 )
eventful.onUnload . itemTrigger = function ( )
itemTriggers = { }
materialTriggers = { }
contaminantTriggers = { }
end
2014-06-30 06:16:10 -06:00
function processTrigger ( command )
local command2 = { }
for i , arg in ipairs ( command.command ) do
if arg == ' \\ ATTACKER_ID ' then
command2 [ i ] = ' ' .. command.attacker . id
elseif arg == ' \\ DEFENDER_ID ' then
command2 [ i ] = ' ' .. command.defender . id
elseif arg == ' \\ ITEM_MATERIAL ' then
command2 [ i ] = command.itemMat : getToken ( )
elseif arg == ' \\ ITEM_MATERIAL_TYPE ' then
command2 [ i ] = command.itemMat [ ' type ' ]
elseif arg == ' \\ ITEM_MATERIAL_INDEX ' then
command2 [ i ] = command.itemMat . index
elseif arg == ' \\ ITEM_ID ' then
command2 [ i ] = ' ' .. command.item . id
elseif arg == ' \\ ITEM_TYPE ' then
command2 [ i ] = command.itemType
elseif arg == ' \\ CONTAMINANT_MATERIAL ' then
command2 [ i ] = command.contaminantMat : getToken ( )
elseif arg == ' \\ CONTAMINANT_MATERIAL_TYPE ' then
command2 [ i ] = command.contaminantMat [ ' type ' ]
elseif arg == ' \\ CONTAMINANT_MATERIAL_INDEX ' then
command2 [ i ] = command.contaminantMat . index
elseif arg == ' \\ MODE ' then
command2 [ i ] = command.mode
elseif arg == ' \\ UNIT_ID ' then
command2 [ i ] = command.unit . id
elseif string.sub ( arg , 1 , 1 ) == ' \\ ' then
2014-07-03 16:28:05 -06:00
command2 [ i ] = string.sub ( arg , 2 )
2014-06-30 06:16:10 -06:00
else
command2 [ i ] = arg
end
end
2014-07-01 00:15:38 -06:00
dfhack.run_command ( table.unpack ( command2 ) )
2014-06-30 06:16:10 -06:00
end
2016-04-19 07:47:05 -06:00
function getitemType ( item )
2016-04-20 04:05:48 -06:00
if item : getSubtype ( ) ~= - 1 then
2016-04-20 03:08:49 -06:00
itemType = dfhack.items . getSubtypeDef ( item : getType ( ) , item : getSubtype ( ) ) . id
2016-04-20 04:05:48 -06:00
else
itemType = df.item_type [ item : getType ( ) ]
2016-04-20 03:08:49 -06:00
end
return itemType
2016-04-19 07:47:05 -06:00
end
2014-06-30 06:16:10 -06:00
function handler ( table )
local itemMat = dfhack.matinfo . decode ( table.item )
local itemMatStr = itemMat : getToken ( )
2016-04-19 07:47:05 -06:00
local itemType = getitemType ( table.item )
2014-06-30 06:16:10 -06:00
table.itemMat = itemMat
table.itemType = itemType
2015-02-14 20:53:06 -07:00
2014-06-30 06:16:10 -06:00
for _ , command in ipairs ( itemTriggers [ itemType ] or { } ) do
if command [ table.mode ] then
2014-07-03 04:01:58 -06:00
utils.fillTable ( command , table )
2014-06-30 06:16:10 -06:00
processTrigger ( command )
2014-07-03 04:01:58 -06:00
utils.unfillTable ( command , table )
2014-06-30 06:16:10 -06:00
end
end
for _ , command in ipairs ( materialTriggers [ itemMatStr ] or { } ) do
if command [ table.mode ] then
2014-07-03 04:01:58 -06:00
utils.fillTable ( command , table )
2014-06-30 06:16:10 -06:00
processTrigger ( command )
2014-07-03 04:01:58 -06:00
utils.unfillTable ( command , table )
2014-06-30 06:16:10 -06:00
end
end
2015-02-14 20:53:06 -07:00
2014-07-03 06:10:55 -06:00
for _ , contaminant in ipairs ( table.item . contaminants or { } ) do
2014-06-30 06:16:10 -06:00
local contaminantMat = dfhack.matinfo . decode ( contaminant.mat_type , contaminant.mat_index )
local contaminantStr = contaminantMat : getToken ( )
table.contaminantMat = contaminantMat
for _ , command in ipairs ( contaminantTriggers [ contaminantStr ] or { } ) do
2014-07-03 04:01:58 -06:00
utils.fillTable ( command , table )
2014-06-30 06:16:10 -06:00
processTrigger ( command )
2014-07-03 04:01:58 -06:00
utils.unfillTable ( command , table )
2014-06-30 06:16:10 -06:00
end
table.contaminantMat = nil
end
end
2014-07-03 06:10:55 -06:00
function equipHandler ( unit , item , isEquip )
2014-06-30 06:16:10 -06:00
local mode = ( isEquip and ' onEquip ' ) or ( not isEquip and ' onUnequip ' )
2014-07-03 06:10:55 -06:00
2014-06-30 06:16:10 -06:00
local table = { }
table.mode = mode
table.item = df.item . find ( item )
2014-11-06 21:46:10 -07:00
table.unit = df.unit . find ( unit )
2014-06-30 06:16:10 -06:00
handler ( table )
end
2014-07-03 06:10:55 -06:00
eventful.onInventoryChange . equipmentTrigger = function ( unit , item , item_old , item_new )
if item_old and item_new then
return
end
2015-02-14 20:53:06 -07:00
2014-07-03 06:10:55 -06:00
local isEquip = item_new and not item_old
equipHandler ( unit , item , isEquip )
end
2014-06-30 06:16:10 -06:00
eventful.onUnitAttack . attackTrigger = function ( attacker , defender , wound )
attacker = df.unit . find ( attacker )
defender = df.unit . find ( defender )
2015-02-14 20:53:06 -07:00
2014-06-30 06:16:10 -06:00
if not attacker then
return
end
2015-02-14 20:53:06 -07:00
2014-06-30 06:16:10 -06:00
local attackerWeapon
for _ , item in ipairs ( attacker.inventory ) do
if item.mode == df.unit_inventory_item . T_mode.Weapon then
attackerWeapon = item.item
break
end
end
2015-02-14 20:53:06 -07:00
2014-06-30 06:16:10 -06:00
if not attackerWeapon then
return
end
local table = { }
table.attacker = attacker
table.defender = defender
table.item = attackerWeapon
table.mode = ' onStrike '
handler ( table )
end
2014-06-30 22:55:52 -06:00
validArgs = validArgs or utils.invert ( {
' clear ' ,
2014-07-03 14:57:56 -06:00
' help ' ,
2014-06-30 22:55:52 -06:00
' checkAttackEvery ' ,
' checkInventoryEvery ' ,
' command ' ,
' itemType ' ,
' onStrike ' ,
' onEquip ' ,
' onUnequip ' ,
' material ' ,
' contaminant ' ,
} )
local args = utils.processArgs ( { ... } , validArgs )
2014-06-30 06:16:10 -06:00
2014-07-03 14:57:56 -06:00
if args.help then
print ( [ [ scripts / modtools / item - trigger.lua usage
arguments :
- help
print this help message
- clear
clear all registered triggers
2015-02-14 20:53:06 -07:00
- checkAttackEvery n
2014-07-03 14:57:56 -06:00
check the attack event at least every n ticks
- checkInventoryEvery n
check inventory event at least every n ticks
- itemType type
trigger the command for items of this type
examples :
ITEM_WEAPON_PICK
2016-04-19 07:47:05 -06:00
RING
2014-07-03 14:57:56 -06:00
- onStrike
trigger the command when someone strikes someone with an appropriate weapon
- onEquip
trigger the command when someone equips an appropriate item
- onUnequip
trigger the command when someone unequips an appropriate item
- material mat
trigger the commmand on items with the given material
examples
INORGANIC : IRON
CREATURE_MAT : DWARF : BRAIN
PLANT_MAT : MUSHROOM_HELMET_PLUMP : DRINK
- contaminant mat
trigger the command on items with a given material contaminant
examples
INORGANIC : IRON
CREATURE_MAT : DWARF : BRAIN
PLANT_MAT : MUSHROOM_HELMET_PLUMP : DRINK
- command [ commandStrs ]
specify the command to be executed
commandStrs
\ \ ATTACKER_ID
\ \ DEFENDER_ID
\ \ ITEM_MATERIAL
\ \ ITEM_MATERIAL_TYPE
\ \ ITEM_ID
\ \ ITEM_TYPE
\ \ CONTAMINANT_MATERIAL
\ \ CONTAMINANT_MATERIAL_TYPE
\ \ CONTAMINANT_MATERIAL_INDEX
\ \ MODE
\ \ UNIT_ID
2014-11-06 21:46:10 -07:00
\ \ anything -> \ anything
2014-07-03 14:57:56 -06:00
anything -> anything
] ] )
return
end
2014-06-30 06:16:10 -06:00
if args.clear then
itemTriggers = { }
materialTriggers = { }
contaminantTriggers = { }
end
2014-06-30 22:02:19 -06:00
if args.checkAttackEvery then
if not tonumber ( args.checkAttackEvery ) then
2014-06-30 22:55:52 -06:00
error ( ' checkAttackEvery must be a number ' )
2014-06-30 06:16:10 -06:00
end
2014-06-30 22:02:19 -06:00
eventful.enableEvent ( eventful.eventType . UNIT_ATTACK , tonumber ( args.checkAttackEvery ) )
end
if args.checkInventoryEvery then
if not tonumber ( args.checkInventoryEvery ) then
2014-06-30 22:55:52 -06:00
error ( ' checkInventoryEvery must be a number ' )
2014-06-30 22:02:19 -06:00
end
eventful.enableEvent ( eventful.eventType . INVENTORY_CHANGE , tonumber ( args.checkInventoryEvery ) )
2014-06-30 06:16:10 -06:00
end
if not args.command then
if not args.clear then
error ' specify a command '
end
return
end
2014-07-03 12:38:29 -06:00
if args.itemType then
2016-04-19 07:47:05 -06:00
if dfhack.items . findType ( args.itemType ) == - 1 then
2014-06-30 06:16:10 -06:00
local temp
2014-07-03 12:38:29 -06:00
for _ , itemdef in ipairs ( df.global . world.raws . itemdefs.all ) do
if itemdef.id == args.itemType then
2014-11-28 21:03:27 -07:00
temp = args.itemType --itemdef.subtype
2014-06-30 06:16:10 -06:00
break
end
end
if not temp then
2014-07-03 12:38:29 -06:00
error ' Could not find item type. '
2014-06-30 06:16:10 -06:00
end
2014-07-03 12:38:29 -06:00
args.itemType = temp
2016-04-19 07:47:05 -06:00
end
2014-06-30 06:16:10 -06:00
end
2014-07-03 12:38:29 -06:00
local numConditions = ( args.material and 1 or 0 ) + ( args.itemType and 1 or 0 ) + ( args.contaminant and 1 or 0 )
2014-06-30 22:55:52 -06:00
if numConditions > 1 then
2014-06-30 06:16:10 -06:00
error ' too many conditions defined: not (yet) supported (pester expwnent if you want it) '
2014-06-30 22:55:52 -06:00
elseif numConditions == 0 then
error ' specify a material, weaponType, or contaminant '
2014-06-30 06:16:10 -06:00
end
if args.material then
if not materialTriggers [ args.material ] then
materialTriggers [ args.material ] = { }
end
table.insert ( materialTriggers [ args.material ] , args )
elseif args.itemType then
if not itemTriggers [ args.itemType ] then
itemTriggers [ args.itemType ] = { }
end
table.insert ( itemTriggers [ args.itemType ] , args )
elseif args.contaminant then
if not contaminantTriggers [ args.contaminant ] then
contaminantTriggers [ args.contaminant ] = { }
end
table.insert ( contaminantTriggers [ args.contaminant ] , args )
end