summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua442
1 files changed, 442 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua
new file mode 100644
index 0000000..ef5a1ee
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/flow.lua
@@ -0,0 +1,442 @@
+--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 swap_type == 'midcast' and command_registry[ts] and command_registry[ts].proposed_packet and not _settings.demo_mode then
+ windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet)
+ 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
+ else
+ if swap_type == 'midcast' and command_registry[ts] and command_registry[ts].proposed_packet and not _settings.demo_mode then
+ windower.packets.inject_outgoing(command_registry[ts].proposed_packet:byte(1),command_registry[ts].proposed_packet)
+ 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 bit.band(val1.target.spawn_type, 2) == 2 and find_inventory_item(val1.id) then
+ -- 0x36 packet
+ if val1.target.distance <= 6 then
+ command_registry[ts].proposed_packet = assemble_menu_item_packet(val1.target.id,val1.target.index,val1.id)
+ else
+ windower.add_to_chat(67, "Target out of range.")
+ end
+ elseif find_usable_item(val1.id) then
+ -- 0x37 packet
+ command_registry[ts].proposed_packet = assemble_use_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)
+ command_registry[ts].midaction = true
+ equip_sets('midcast',ts,command_registry[ts].spell)
+end \ No newline at end of file