diff options
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/lua-addons/addons/GearSwap/triggers.lua | 343 |
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 |