-
Notifications
You must be signed in to change notification settings - Fork 157
/
flow.lua
432 lines (385 loc) · 18.8 KB
/
flow.lua
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
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
--Copyright (c) 2013~2016, Byrthnoth
--All rights reserved.
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are met:
-- * Redistributions of source code must retain the above copyright
-- notice, this list of conditions and the following disclaimer.
-- * Redistributions in binary form must reproduce the above copyright
-- notice, this list of conditions and the following disclaimer in the
-- documentation and/or other materials provided with the distribution.
-- * Neither the name of <addon name> nor the
-- names of its contributors may be used to endorse or promote products
-- derived from this software without specific prior written permission.
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
--ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
--WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
--DISCLAIMED. IN NO EVENT SHALL <your name> BE LIABLE FOR ANY
--DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
--(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
--LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
--ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
--(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----------------------------------------------------------------------------------
--Name: equip_sets(swap_type,ts,val1,val2)
--Desc: General purpose equipment pipeline / user function caller.
--Args:
---- swap_type - Determines equip_sets' behavior in terms of which user function it
-- attempts to call
---- ts - index of command_registry or nil for pretarget/commands
---- val1 - First argument to be passed to the user function
---- val2 - Second argument to be passed to the user function
-----------------------------------------------------------------------------------
--Return (varies by swap type):
---- pretarget : empty string to blank packet or full string
---- Everything else : nil
-----------------------------------------------------------------------------------
function equip_sets(swap_type,ts,...)
local results
local var_inps = {...}
local val1 = var_inps[1]
local val2 = var_inps[2]
table.reassign(_global,command_registry[ts] or {pretarget_cast_delay = 0,precast_cast_delay=0,cancel_spell = false, new_target=false,target_arrow={x=0,y=0,z=0}})
_global.current_event = tostring(swap_type)
if _global.current_event == 'precast' and val1 and val1.english and val1.english:find('Geo-') then
_global.target_arrow = initialize_arrow_offset(val1.target)
end
windower.debug(tostring(swap_type)..' enter')
if showphase or debugging.general then msg.debugging(8,windower.to_shift_jis(tostring(swap_type))..' enter') end
local cur_equip = table.reassign({},update_equipment())
table.reassign(equip_list,{})
table.reassign(player.equipment,to_names_set(cur_equip))
for i,v in pairs(slot_map) do
if not player.equipment[i] then
player.equipment[i] = player.equipment[toslotname(v)]
end
end
logit('\n\n'..tostring(os.clock)..'(15) equip_sets: '..tostring(swap_type))
if val1 then
if type(val1) == 'table' and val1.english then
logit(' : '..val1.english)
else
logit(' : Unknown type val1- '..tostring(val1))
end
else
logit(' : nil-or-false')
end
if val2 then
if type(val2) == 'table' and val2.type then logit(' : '..val2.type)
else
logit(' : Unknown type val2- '..tostring(val2))
end
else
logit(' : nil-or-false')
end
if type(swap_type) == 'string' then
msg.debugging("Entering "..swap_type)
else
msg.debugging("Entering User Event "..tostring(swap_type))
end
if not val1 then val1 = {}
if debugging.general then
msg.debugging(8,'val1 error')
end
end
if type(swap_type) == 'function' then
results = { pcall(swap_type,...) }
if not table.remove(results,1) then error('\nUser Event Error: '..results[1]) end
elseif swap_type == 'equip_command' then
equip(val1)
else
user_pcall(swap_type,...)
end
--[[ local c
if type(swap_type) == 'function' then
c = coroutine.create(swap_type)
elseif swap_type == 'equip_command' then
equip(val1)
elseif type(swap_type) == 'string' and user_env[swap_type] and type(user_env[swap_type]) == 'function' then
c = coroutine.create(user_env[swap_type])
elseif type(swap_type) == 'string' and user_env[swap_type] then
msg.addon_msg(123,windower.to_shift_jis(tostring(str))..'() exists but is not a function')
end
if c then
while coroutine.status(c) == 'suspended' do
local err, typ, val = coroutine.resume(c,unpack(var_inputs))
if not err then
error('\nGearSwap has detected an error in the user function '..tostring(swap_type)..':\n'..typ)
elseif typ then
if typ == 'sleep' and type(val) == 'number' and val >= 0 then
-- coroutine slept
err, typ, val = coroutine.schedule(c,val)
else
-- Someone yielded or slept with a nonsensical argument.
err, typ, val = coroutine.resume(c)
end
else
-- coroutine finished
end
end
end]]
if type(swap_type) == 'string' and (swap_type == 'pretarget' or swap_type == 'filtered_action') then -- Target may just have been changed, so make the ind now.
ts = command_registry:new_entry(val1)
-- elseif type(swap_type) == 'string' and swap_type == 'precast' and not command_registry[ts] and debugging.command_registry then
-- print_set(spell,'precast nil error') -- spell's scope changed to local
end
if player.race ~= 'Precomposed NPC' then
-- Short circuits the routine and gets out before equip processing
-- if there's no swapping to be done because the user is a monster.
for v,i in pairs(default_slot_map) do
if equip_list[i] and encumbrance_table[v] then
not_sent_out_equip[i] = equip_list[i]
equip_list[i] = nil
msg.debugging(i..' slot was not equipped because you are encumbered.')
end
end
table.update(equip_list_history,equip_list)
-- Attempts to identify the player-specified item in inventory
-- Starts with (i=slot name, v=item name)
-- Ends with (i=slot id and v={bag_id=bag_id, slot=inventory slot}).
local equip_next,priorities = unpack_equip_list(equip_list,cur_equip)
if (_settings.show_swaps and table.length(equip_next) > 0) or _settings.demo_mode then --and table.length(equip_next)>0 then
local tempset = to_names_set(equip_next)
print_set(tempset,tostring(swap_type))
end
if (buffactive.charm or player.charmed) or (player.status == 2 or player.status == 3) then -- dead or engaged dead statuses
local failure_reason
if (buffactive.charm or player.charmed) then
failure_reason = 'Charmed'
elseif player.status == 2 or player.status == 3 then
failure_reason = 'KOed'
end
msg.debugging("Cannot change gear right now: "..tostring(failure_reason))
logit('\n\n'..tostring(os.clock)..'(69) failure_reason: '..tostring(failure_reason))
else
local chunk_table = L{}
for eq_slot_id,priority in priorities:it() do
if equip_next[eq_slot_id] and not encumbrance_table[eq_slot_id] and not _settings.demo_mode then
local minichunk = equip_piece(eq_slot_id,equip_next[eq_slot_id].bag_id,equip_next[eq_slot_id].slot)
chunk_table:append(minichunk)
end
end
if chunk_table.n >= 3 then
local big_chunk = string.char(0x51,0x24,0,0,chunk_table.n,0,0,0)
for i=1,chunk_table.n do
big_chunk = big_chunk..chunk_table[i]
end
while string.len(big_chunk) < 0x48 do big_chunk = big_chunk..string.char(0) end
windower.packets.inject_outgoing(0x51,big_chunk)
elseif chunk_table.n > 0 then
for i=1,chunk_table.n do
local chunk = string.char(0x50,4,0,0)..chunk_table[i]
windower.packets.inject_outgoing(0x50,chunk)
end
end
end
end
windower.debug(tostring(swap_type)..' exit')
if type(swap_type) == 'function' then
return unpack(results)
end
return equip_sets_exit(swap_type,ts,val1)
end
-----------------------------------------------------------------------------------
--Name: equip_sets_exit(swap_type,ind,val1)
--Desc: Cleans up the global table and leaves equip_sets properly.
--Args:
---- swap_type - Current swap type for equip_sets
---- ts - Current index of command_registry
---- val1 - First argument of equip_sets
-----------------------------------------------------------------------------------
--Returns:
---- none
-----------------------------------------------------------------------------------
function equip_sets_exit(swap_type,ts,val1)
if command_registry[ts] then
table.update(command_registry[ts],_global)
end
if type(swap_type) == 'string' then
if swap_type == 'pretarget' then
if command_registry[ts].cancel_spell then
msg.debugging("Action canceled ("..storedcommand..' '..val1.target.raw..")")
storedcommand = nil
command_registry:delete_entry(ts)
return true
elseif not ts or not command_registry[ts] or not storedcommand then
msg.debugging('This case should not be hittable - 1')
return true
end
if command_registry[ts].new_target then
val1.target = command_registry[ts].new_target -- Switch target, if it is requested.
end
-- Compose a proposed packet for the given action (this should be possible after pretarget)
command_registry[ts].spell = val1
if val1.target and val1.target.id and val1.target.index and val1.prefix and unify_prefix[val1.prefix] then
if val1.prefix == '/item' then
-- Item use packet handling here
if find_usable_item(val1.id,true) then --val1.target.id == player.id then
--0x37 packet
command_registry[ts].proposed_packet = assemble_use_item_packet(val1.target.id,val1.target.index,val1.id)
else
--0x36 packet
command_registry[ts].proposed_packet = assemble_menu_item_packet(val1.target.id,val1.target.index,val1.id)
end
if not command_registry[ts].proposed_packet then
command_registry:delete_entry(ts)
end
elseif outgoing_action_category_table[unify_prefix[val1.prefix]] then
if filter_precast(val1) then
command_registry[ts].proposed_packet = assemble_action_packet(val1.target.id,val1.target.index,outgoing_action_category_table[unify_prefix[val1.prefix]],val1.id,command_registry[ts].target_arrow)
if not command_registry[ts].proposed_packet then
command_registry:delete_entry(ts)
msg.debugging("Unable to create a packet for this command because the target is still invalid after pretarget ("..storedcommand..' '..val1.target.raw..")")
storedcommand = nil
return storedcommand..' '..val1.target.raw
end
end
else
msg.debugging(8,"Hark, what weird prefix through yonder window breaks? "..tostring(val1.prefix))
end
end
if ts and command_registry[ts] and val1.target then
if st_targs[val1.target.raw] then
-- st targets
st_flag = true
elseif not val1.target.name then
-- Spells with invalid pass_through_targs, like using <t> without a target
command_registry:delete_entry(ts)
msg.debugging("Change target was used to pick an invalid target ("..storedcommand..' '..val1.target.raw..")")
local ret = storedcommand..' '..val1.target.raw
storedcommand = nil
return ret
else
-- Spells with complete target information
-- command_registry[ts] is deleted for cancelled spells
if command_registry[ts].pretarget_cast_delay == 0 then
equip_sets('precast',ts,val1)
else
windower.send_command('@wait '..command_registry[ts].pretarget_cast_delay..';lua i '.._addon.name..' pretarget_delayed_cast '..ts)
end
return true
end
elseif not ts or not command_registry[ts] then
msg.debugging('This case should not be hittable - 2')
return true
end
elseif swap_type == 'precast' then
-- Update the target_arrow
if val1.prefix ~= '/item' then
command_registry[ts].proposed_packet = assemble_action_packet(val1.target.id,val1.target.index,outgoing_action_category_table[unify_prefix[val1.prefix]],val1.id,command_registry[ts].target_arrow)
end
return precast_send_check(ts)
elseif swap_type == 'filtered_action' and command_registry[ts] and command_registry[ts].cancel_spell then
storedcommand = nil
command_registry:delete_entry(ts)
return true
elseif swap_type == 'midcast' and _settings.demo_mode then
command_registry[ts].midaction = false
equip_sets('aftercast',ts,val1)
elseif swap_type == 'aftercast' then
if ts then
command_registry:delete_entry(ts)
end
elseif swap_type == 'pet_aftercast' then
if ts then
command_registry:delete_entry(ts)
end
end
end
end
-----------------------------------------------------------------------------------
--Name: user_pcall(str,val1,val2,exit_funct)
--Desc: Calls a user function, if it exists. If not, throws an error.
--Args:
---- str - Function's key in user_env.
-----------------------------------------------------------------------------------
--Returns:
---- none
-----------------------------------------------------------------------------------
function user_pcall(str,...)
if user_env then
if type(user_env[str]) == 'function' then
bool,err = pcall(user_env[str],...)
if not bool then error('\nGearSwap has detected an error in the user function '..str..':\n'..err) end
elseif user_env[str] then
msg.addon_msg(123,windower.to_shift_jis(tostring(str))..'() exists but is not a function')
end
end
end
-----------------------------------------------------------------------------------
--Name: pretarget_delayed_cast(ts)
--Desc: Triggers an outgoing action packet (if the passed key is valid).
--Args:
---- ts - Timestamp argument to precast_delayed_cast
-----------------------------------------------------------------------------------
--Returns:
---- none
-----------------------------------------------------------------------------------
function pretarget_delayed_cast(ts)
ts = tonumber(ts)
if ts then
equip_sets('precast',ts,command_registry[ts].spell)
else
msg.debugging("Bad index passed to pretarget_delayed_cast")
end
end
-----------------------------------------------------------------------------------
--Name: precast_send_check(ts)
--Desc: Determines whether or not to send the current packet.
-- Cancels if _global.cancel_spell is true
-- If command_registry[ts].precast_cast_delay is not 0, cues precast_delayed_cast with the proper
-- delay instead of sending immediately.
--Args:
---- ts - key of command_registry
-----------------------------------------------------------------------------------
--Returns:
---- true (to block) or the outgoing packet
-----------------------------------------------------------------------------------
function precast_send_check(ts)
if ts and command_registry[ts] then
if command_registry[ts].cancel_spell then
command_registry:delete_entry(ts)
else
if command_registry[ts].precast_cast_delay == 0 then
send_action(ts)
return
else
windower.send_command('@wait '..command_registry[ts].precast_cast_delay..';lua i '.._addon.name..' precast_delayed_cast '..ts)
end
end
end
return true
end
-----------------------------------------------------------------------------------
--Name: precast_delayed_cast(ts)
--Desc: Triggers an outgoing action packet (if the passed key is valid).
--Args:
---- ts - Timestamp argument to precast_delayed_cast
-----------------------------------------------------------------------------------
--Returns:
---- none
-----------------------------------------------------------------------------------
function precast_delayed_cast(ts)
ts = tonumber(ts)
if ts then
send_action(ts)
else
msg.debugging("Bad index passed to precast_delayed_cast")
end
end
-----------------------------------------------------------------------------------
--Name: send_action(ts)
--Desc: Sends the cued action packet, if it exists.
--Args:
---- ts - index for a command_registry entry that includes an action packet (hopefully)
-----------------------------------------------------------------------------------
--Returns:
---- none
-----------------------------------------------------------------------------------
function send_action(ts)
if command_registry[ts].proposed_packet then
if not _settings.demo_mode then windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet) end
command_registry[ts].midaction = true
equip_sets('midcast',ts,command_registry[ts].spell)
end
end