summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua343
1 files changed, 343 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua
new file mode 100644
index 0000000..8df14f1
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua
@@ -0,0 +1,343 @@
+--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: outgoing_text(original,modified,blocked,ffxi)
+--Desc: Searches the client's outgoing text for GearSwap handled commands and
+-- returns '' if it finds one. Otherwise returns the command unaltered.
+--Args:
+---- original - String entered by the user
+---- modified - String after being modified by upstream addons/plugins
+---- blocked - Boolean indicating whether the outgoing text is blocked upstream
+---- ffxi - Boolean indicating whether the outgoing text is generated by FFXI
+-----------------------------------------------------------------------------------
+--Returns:
+---- none or ''
+-----------------------------------------------------------------------------------
+windower.register_event('outgoing text',function(original,modified,blocked,ffxi,extra_stuff,extra2)
+ windower.debug('outgoing text')
+ if gearswap_disabled then return modified end
+
+ local splitline = windower.from_shift_jis(windower.convert_auto_trans(modified)):gsub(' <wait %d+>',''):gsub('"(.-)"',function(str)
+ return str:gsub(' ',string.char(7))
+ end):split(' '):filter(-'')
+
+ if splitline.n == 0 then return end
+
+ local command = splitline[1]
+ local bstpet = command == '/bstpet'
+ local unified_prefix = unify_prefix[command]
+ local abil, temptarg, temp_mob_arr
+ if splitline[2] and not bstpet then
+ abil = splitline[2]:gsub(string.char(7),' '):lower() -- Why am I removing \x7?
+ elseif splitline[2] and bstpet and tonumber(splitline[2]) then
+ local pet_abilities = {}
+ for _,v in ipairs(windower.ffxi.get_abilities().job_abilities) do
+ if v >= bstpet_range.min and v <= bstpet_range.max then
+ pet_abilities[#pet_abilities+1] = v
+ end
+ end
+ if pet_abilities[tonumber(splitline[2])] then
+ abil = res.job_abilities[pet_abilities[tonumber(splitline[2])]].name:gsub(string.char(7),' '):lower() -- .name, or .english?
+ end
+ end
+
+ if validabils[language][unified_prefix] and validabils[language][unified_prefix][abil] then
+ temptarg, temp_mob_arr = valid_target(splitline[3])
+ elseif validabils[language][unified_prefix] then
+ temptarg, temp_mob_arr = valid_target(splitline[2])
+ end
+
+ if unified_prefix and temptarg and (validabils[language][unified_prefix][abil] or unified_prefix=='/ra') then
+ if st_flag then
+ st_flag = nil
+ return modified
+ elseif temp_mob_arr then
+ refresh_globals()
+
+ local r_line, find_monster_skill
+
+ function find_monster_skill(abil)
+ local line = false
+ if player.species and player.species.tp_moves then
+ -- Iterates over currently available monster TP moves instead of using validabils
+ for i,v in pairs(player.species.tp_moves) do
+ if res.monster_skills[i][language]:lower() == abil then
+ line = copy_entry(res.monster_skills[i])
+ break
+ end
+ end
+ end
+ return line
+ end
+
+ if unified_prefix == '/ma' then
+ r_line = copy_entry(res.spells[validabils[language][unified_prefix][abil]])
+ storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" '
+ elseif unified_prefix == '/ms' and find_monster_skill(abil) then
+ r_line = find_monster_skill(abil)
+ storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" '
+ elseif unified_prefix == '/ws' then
+ r_line = copy_entry(res.weapon_skills[validabils[language][unified_prefix][abil]])
+ storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" '
+ elseif unified_prefix == '/ja' then
+ r_line = copy_entry(res.job_abilities[validabils[language][unified_prefix][abil]])
+ if bstpet then
+ storedcommand = command..' '..splitline[2]
+ else
+ storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" '
+ end
+ elseif unified_prefix == '/item' then
+ r_line = copy_entry(res.items[validabils[language][unified_prefix][abil]])
+ r_line.prefix = '/item'
+ r_line.type = 'Item'
+ storedcommand = command..' "'..windower.to_shift_jis(r_line[language])..'" '
+ elseif unified_prefix == '/ra' then
+ r_line = copy_entry(resources_ranged_attack)
+ storedcommand = command..' '
+ end
+
+ r_line.name = r_line[language]
+ local spell = spell_complete(r_line)
+ spell.target = temp_mob_arr
+ spell.action_type = action_type_map[command]
+
+ if filter_pretarget(spell) then
+ if tonumber(splitline[splitline.n]) then
+ -- If the target is a number
+ local ts = command_registry:new_entry(spell)
+
+ if spell.prefix == '/item' then
+ -- Item use packet handling here
+ if bit.band(spell.target.spawn_type, 2) == 2 and find_inventory_item(spell.id) then
+ --0x36 packet
+ if spell.target.distance <= 6 then
+ command_registry[ts].proposed_packet = assemble_menu_item_packet(spell.target.id,spell.target.index,spell.id)
+ else
+ windower.add_to_chat(67, "Target out of range.")
+ return true
+ end
+ elseif find_usable_item(spell.id) then
+ --0x37 packet
+ command_registry[ts].proposed_packet = assemble_use_item_packet(spell.target.id,spell.target.index,spell.id)
+ end
+ else
+ command_registry[ts].proposed_packet = assemble_action_packet(spell.target.id,spell.target.index,outgoing_action_category_table[unify_prefix[spell.prefix]],spell.id,initialize_arrow_offset(spell.target))
+ end
+ -- The packets created above should not be used.
+ if command_registry[ts].proposed_packet then
+ equip_sets('precast',ts,spell)
+ return true
+ end
+ else
+ return equip_sets('pretarget',-1,spell)
+ end
+ else
+ return equip_sets('filtered_action',-1,spell)
+ end
+ end
+ end
+ return modified
+end)
+
+
+
+-----------------------------------------------------------------------------------
+--Name: parse.i[0x028](act)
+--Desc: Calls midcast or aftercast functions as appropriate in response to incoming
+-- action packets.
+--Args:
+---- act - Action packet array (described on the dev wiki)
+-----------------------------------------------------------------------------------
+--Returns:
+---- none
+-----------------------------------------------------------------------------------
+parse.i[0x028] = function (data)
+ local act = windower.packets.parse_action(data)
+ if gearswap_disabled or act.category == 1 then return end
+
+-- local spell_res = ActionPacket.new(act):get_spell()
+
+ --print(((res[unpackedaction.resource] or {})[unpackedaction.spell_id] or {}).english,unpackedaction.type,unpackedaction.value,unpackedaction.interruption)
+ local temp_player_mob_table,temp_pet,pet_id = windower.ffxi.get_mob_by_index(player.index)
+ if temp_player_mob_table and temp_player_mob_table.pet_index then
+ temp_pet = windower.ffxi.get_mob_by_index(temp_player_mob_table.pet_index)
+ if temp_pet then
+ pet_id = temp_pet.id
+ end
+ end
+
+ if act.actor_id ~= player.id and act.actor_id ~= pet_id then
+ return -- If the action is not being used by the player, the pet, or is a melee attack then abort processing.
+ end
+
+ local prefix = ''
+
+ if act.actor_id == pet_id then
+ prefix = 'pet_'
+ end
+
+ local spell = get_spell(act)
+-- if not spell_res or (spell.english ~= spell_res.english) then print('Did not match.',spell.english,spell_res) end
+
+ if spell then logit('\n\n'..tostring(os.clock)..'(178) Event Action: '..tostring(spell[language])..' '..tostring(act.category))
+ else logit('\n\nNil spell detected') end
+
+ if spell and spell[language] then
+ spell.target = target_complete(windower.ffxi.get_mob_by_id(act.targets[1].id))
+ spell.action_type = action_type_map[unify_prefix[spell.prefix or 'Monster']]
+ elseif S{84,78}:contains(act.targets[1].actions[1].message) then -- "Paralyzed" and "too far away" respectively
+ local ts,tab = command_registry:delete_by_id(act.targets[1].id)
+ if tab and tab.spell and tab.spell.prefix == '/pet' then
+ tab.spell.interrupted = true
+ equip_sets('pet_aftercast',nil,tab.spell)
+ elseif tab and tab.spell then
+ tab.spell.interrupted = true
+ equip_sets('aftercast',nil,tab.spell)
+ end
+ return
+ else
+ if debugging.general then windower.send_command('input /echo Incoming Action packet did not generate a spell/aftercast.')end
+ return
+ end
+
+ --[[4 (action message) = "out of range" when attempting to melee something that's too far away
+ 78 (action message) = "too far away" when attempting to engage or cast magic on something that's too far away
+ 78 (action) = "too far away" when attempting to WS something that's too far away
+ 154 (action message) - "out of range" when attempting to use a JA on something that's too far away. param_1 is the JA ID]]
+
+ -- Paralysis of JAs/spells/etc. and Out of Range messages for avatars both send two action packets when they occur.
+ -- The first packet is a paralysis packet that contains the message and spell-appropriate information.
+ -- The second packet contains the interruption code and no useful information as far as I can see.
+ -- The same occurs for items, except that they are both category 9 messages.
+
+ -- For some reason avatar Out of Range messages send two packets (Category 4 and Category 7)
+ -- Category 4 contains real information, while Category 7 does not.
+ -- I do not know if this will affect automatons being interrupted.
+ local ts = command_registry:find_by_spell(spell)
+ if (jas[act.category] or uses[act.category]) then
+ if uses[act.category] and act.param == 28787 then
+ spell.action_type = 'Interruption'
+ spell.interrupted = true
+ else
+ spell.value = act.targets[1].actions[1].param
+ end
+ if ts then --or spell.prefix == '/item' then
+ -- Only aftercast things that were precasted.
+ -- Also, there are some actions (like being paralyzed while casting Ninjutsu) that sends two result action packets. Block the second packet.
+ refresh_globals()
+ command_registry[ts].midaction = false
+ equip_sets(prefix..'aftercast',ts,spell)
+ elseif debugging.command_registry then
+ msg.debugging('Hitting Aftercast without detecting an entry in command_registry')
+ end
+ elseif (readies[act.category] and act.param == 28787) then -- and not (act.category == 9 or (act.category == 7 and prefix == 'pet_'))) then
+ spell.action_type = 'Interruption'
+ spell.interrupted = true
+ if ts or spell.prefix == '/item' then
+ -- Only aftercast things that were precasted.
+ -- Also, there are some actions (like being paralyzed while casting Ninjutsu) that sends two result action packets. Block the second packet.
+ refresh_globals()
+ if command_registry[ts] then command_registry[ts].midaction = false end
+ equip_sets(prefix..'aftercast',ts,spell)
+ elseif debugging.command_registry then
+ msg.debugging('Hitting Aftercast without detecting an entry in command_registry')
+ end
+ elseif readies[act.category] and prefix == 'pet_' and act.targets[1].actions[1].message ~= 0 then
+ -- Entry for pet midcast. Excludes the second packet of "Out of range" BPs.
+ ts = command_registry:new_entry(spell)
+ refresh_globals()
+ command_registry[ts].pet_midaction = true
+ equip_sets('pet_midcast',ts,spell)
+ end
+end
+
+
+
+-----------------------------------------------------------------------------------
+--Name: parse.i[0x029](data)
+--Desc: Responds to incoming action message packets.
+--Args:
+---- arr - Action message packet arguments (described on the dev wiki):
+ -- actor_id,target_id,param_1,param_2,param_3,actor_index,target_index,message_id)
+-----------------------------------------------------------------------------------
+--Returns:
+---- none
+-----------------------------------------------------------------------------------
+parse.i[0x029] = function (data)
+ if gearswap_disabled then return end
+ local arr = {}
+ arr.actor_id = data:unpack('I',0x05)
+ arr.target_id = data:unpack('I',0x09)
+ arr.param_1 = data:unpack('I',0x0D)
+ arr.param_2 = data:unpack('I',0x11)%64 -- First 6 bits
+ arr.param_3 = math.floor(data:unpack('I',0x11)/64) -- Rest
+ arr.actor_index = data:unpack('H',0x15)
+ arr.target_index = data:unpack('H',0x17)
+ arr.message_id = data:unpack('H',0x19)%32768
+
+
+ windower.debug('action message')
+ if T{6,20,113,406,605,646}:contains(arr.message_id) then -- death messages
+ local ts,tab = command_registry:delete_by_id(arr.target_id)
+ if tab and tab.spell and tab.spell.prefix == '/pet' then
+ equip_sets('pet_aftercast',nil,tab.spell)
+ elseif tab and tab.spell then
+ equip_sets('aftercast',nil,tab.spell)
+ end
+ return
+ end
+
+ local tempplay = windower.ffxi.get_player()
+ local prefix = ''
+ if arr.actor_id ~= tempplay.id then
+ if tempplay.pet_index then
+ if arr.actor_id ~= windower.ffxi.get_mob_by_index(tempplay.pet_index).id then
+ return
+ else
+ prefix = 'pet_'
+ end
+ else
+ return
+ end
+ end
+
+ if unable_to_use:contains(arr.message_id) then
+ logit('\n\n'..tostring(os.clock)..'(195) Event Action Message: '..tostring(message_id)..' Interrupt')
+ local ts,tab = command_registry:find_by_time()
+
+ if tab and tab.spell then
+ tab.spell.interrupted = true
+ tab.spell.action_type = 'Interruption'
+ command_registry[ts].midaction = false
+ refresh_globals()
+ equip_sets(prefix..'aftercast',ts,tab.spell)
+ end
+ end
+end