forked from DFHack/dfhack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathitem-trigger.lua
More file actions
288 lines (256 loc) · 8.08 KB
/
Copy pathitem-trigger.lua
File metadata and controls
288 lines (256 loc) · 8.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
--scripts/modtools/attack-trigger.lua
--author expwnent
--based on itemsyndrome by Putnam
--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
--[[
BEGIN_DOCS
.. _scripts/modtools/item-trigger:
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_DOCS
]]
local eventful = require 'plugins.eventful'
local utils = require 'utils'
itemTriggers = itemTriggers or {}
materialTriggers = materialTriggers or {}
contaminantTriggers = contaminantTriggers or {}
eventful.enableEvent(eventful.eventType.UNIT_ATTACK,1) -- this event type is cheap, so checking every tick is fine
eventful.enableEvent(eventful.eventType.INVENTORY_CHANGE,5) --this is expensive, but you might still want to set it lower
eventful.enableEvent(eventful.eventType.UNLOAD,1)
eventful.onUnload.itemTrigger = function()
itemTriggers = {}
materialTriggers = {}
contaminantTriggers = {}
end
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
command2[i] = string.sub(arg,2)
else
command2[i] = arg
end
end
dfhack.run_command(table.unpack(command2))
end
function handler(table)
local itemMat = dfhack.matinfo.decode(table.item)
local itemMatStr = itemMat:getToken()
local itemType = dfhack.items.getSubtypeDef(table.item:getType(),table.item:getSubtype()).id
table.itemMat = itemMat
table.itemType = itemType
for _,command in ipairs(itemTriggers[itemType] or {}) do
if command[table.mode] then
utils.fillTable(command,table)
processTrigger(command)
utils.unfillTable(command,table)
end
end
for _,command in ipairs(materialTriggers[itemMatStr] or {}) do
if command[table.mode] then
utils.fillTable(command,table)
processTrigger(command)
utils.unfillTable(command,table)
end
end
for _,contaminant in ipairs(table.item.contaminants or {}) do
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
utils.fillTable(command,table)
processTrigger(command)
utils.unfillTable(command,table)
end
table.contaminantMat = nil
end
end
function equipHandler(unit, item, isEquip)
local mode = (isEquip and 'onEquip') or (not isEquip and 'onUnequip')
local table = {}
table.mode = mode
table.item = df.item.find(item)
table.unit = df.unit.find(unit)
handler(table)
end
eventful.onInventoryChange.equipmentTrigger = function(unit, item, item_old, item_new)
if item_old and item_new then
return
end
local isEquip = item_new and not item_old
equipHandler(unit,item,isEquip)
end
eventful.onUnitAttack.attackTrigger = function(attacker,defender,wound)
attacker = df.unit.find(attacker)
defender = df.unit.find(defender)
if not attacker then
return
end
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
if not attackerWeapon then
return
end
local table = {}
table.attacker = attacker
table.defender = defender
table.item = attackerWeapon
table.mode = 'onStrike'
handler(table)
end
validArgs = validArgs or utils.invert({
'clear',
'help',
'checkAttackEvery',
'checkInventoryEvery',
'command',
'itemType',
'onStrike',
'onEquip',
'onUnequip',
'material',
'contaminant',
})
local args = utils.processArgs({...}, validArgs)
if args.help then
print([[scripts/modtools/item-trigger.lua usage
arguments:
-help
print this help message
-clear
clear all registered triggers
-checkAttackEvery n
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
-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
\\anything -> \anything
anything -> anything
]])
return
end
if args.clear then
itemTriggers = {}
materialTriggers = {}
contaminantTriggers = {}
end
if args.checkAttackEvery then
if not tonumber(args.checkAttackEvery) then
error('checkAttackEvery must be a number')
end
eventful.enableEvent(eventful.eventType.UNIT_ATTACK,tonumber(args.checkAttackEvery))
end
if args.checkInventoryEvery then
if not tonumber(args.checkInventoryEvery) then
error('checkInventoryEvery must be a number')
end
eventful.enableEvent(eventful.eventType.INVENTORY_CHANGE,tonumber(args.checkInventoryEvery))
end
if not args.command then
if not args.clear then
error 'specify a command'
end
return
end
if args.itemType then
local temp
for _,itemdef in ipairs(df.global.world.raws.itemdefs.all) do
if itemdef.id == args.itemType then
temp = args.itemType --itemdef.subtype
break
end
end
if not temp then
error 'Could not find item type.'
end
args.itemType = temp
end
local numConditions = (args.material and 1 or 0) + (args.itemType and 1 or 0) + (args.contaminant and 1 or 0)
if numConditions > 1 then
error 'too many conditions defined: not (yet) supported (pester expwnent if you want it)'
elseif numConditions == 0 then
error 'specify a material, weaponType, or contaminant'
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