summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua')
-rw-r--r--Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua947
1 files changed, 947 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua b/Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua
new file mode 100644
index 0000000..05cfd36
--- /dev/null
+++ b/Data/BuiltIn/Libraries/lua-addons/addons/battlemod/parse_action_packet.lua
@@ -0,0 +1,947 @@
+function parse_action_packet(act)
+ -- Make a function that returns the action array with additional information
+ -- actor : type, name, is_npc
+ -- target : type, name, is_npc
+ if not Self then
+ Self = windower.ffxi.get_player()
+ if not Self then
+ return act
+ end
+ end
+ act.actor = player_info(act.actor_id)
+ act.action = get_spell(act) -- Pulls the resources line for the action
+ act.actor.name = act.actor and act.actor.name and string.gsub(act.actor.name,'[- ]', {['-'] = string.char(0x81,0x7C), [' '] = string.char(0x81,0x3F)}) --fix for ffxi chat splits on trusts with - and spaces
+ targets_condensed = false
+
+ if not act.action then
+ return act
+ end
+ for i,v in ipairs(act.targets) do
+ v.target = {}
+ v.target[1] = player_info(v.id)
+ if #v.actions > 1 then
+ for n,m in ipairs(v.actions) do
+ if res.action_messages[m.message] then m.fields = fieldsearch(res.action_messages[m.message][language]) end
+ if res.action_messages[m.add_effect_message] then m.add_effect_fields = fieldsearch(res.action_messages[m.add_effect_message][language]) end
+ if res.action_messages[m.spike_effect_message] then m.spike_effect_fields = fieldsearch(res.action_messages[m.spike_effect_message][language]) end
+
+ if res.buffs[m.param] then --and m.param ~= 0 then
+ m.status = res.buffs[m.param][language]
+ end
+ if res.buffs[m.add_effect_param] then -- and m.add_effect_param ~= 0 then
+ m.add_effect_status = res.buffs[m.add_effect_param][language]
+ end
+ if res.buffs[m.spike_effect_param] then -- and m.spike_effect_param ~= 0 then
+ m.spike_effect_status = res.buffs[m.spike_effect_param][language]
+ end
+ m.number = 1
+ if m.has_add_effect then
+ m.add_effect_number = 1
+ end
+ if m.has_spike_effect then
+ m.spike_effect_number = 1
+ end
+ if not check_filter(act.actor,v.target[1],act.category,m.message) then
+ m.message = 0
+ m.add_effect_message = 0
+ end
+ if m.spike_effect_message ~= 0 and not check_filter(v.target[1],act.actor,act.category,m.message) then
+ m.spike_effect_message = 0
+ end
+ if condensedamage and n > 1 then -- Damage/Action condensation within one target
+ for q=1,n-1 do
+ local r = v.actions[q]
+
+ if r.message ~= 0 and m.message ~= 0 then
+ if m.message == r.message or (condensecrits and S{1,67}:contains(m.message) and S{1,67}:contains(r.message)) then
+ if (m.effect == r.effect) or (S{1,67}:contains(m.message) and S{0,1,2,3}:contains(m.effect) and S{0,1,2,3}:contains(r.effect)) then -- combine kicks and crits
+ if m.reaction == r.reaction then --or (S{8,10}:contains(m.reaction) and S{8,10}:contains(r.reaction)) then -- combine hits and guards
+-- windower.add_to_chat(8, 'Condensed: '..m.message..':'..r.message..' - '..m.effect..':'..r.effect..' - '..m.reaction..':'..r.reaction)
+ r.number = r.number + 1
+ if not sumdamage then
+ if not r.cparam then
+ r.cparam = r.param
+ if condensecrits and r.message == 67 then
+ r.cparam = r.cparam..'!'
+ end
+ end
+ r.cparam = r.cparam..', '..m.param
+ if condensecrits and m.message == 67 then
+ r.cparam = r.cparam..'!'
+ end
+ end
+ r.param = m.param + r.param
+ if condensecrits and m.message == 67 then
+ r.message = m.message
+ r.effect = m.effect
+ end
+ m.message = 0
+ else
+-- windower.add_to_chat(8, 'Didn\'t condense: '..m.message..':'..r.message..' - '..m.effect..':'..r.effect..' - '..m.reaction..':'..r.reaction)
+ end
+ else
+-- windower.add_to_chat(8, 'Didn\'t condense: '..m.message..':'..r.message..' - '..m.effect..':'..r.effect..' - '..m.reaction..':'..r.reaction)
+ end
+ else
+-- windower.add_to_chat(8, 'Didn\'t condense: '..m.message..':'..r.message..' - '..m.effect..':'..r.effect..' - '..m.reaction..':'..r.reaction)
+ end
+ end
+ if m.has_add_effect and r.add_effect_message ~= 0 then
+ if m.add_effect_effect == r.add_effect_effect and m.add_effect_message == r.add_effect_message and m.add_effect_message ~= 0 then
+ r.add_effect_number = r.add_effect_number + 1
+ if not sumdamage then
+ r.cadd_effect_param = (r.cadd_effect_param or r.add_effect_param)..', '..m.add_effect_param
+ end
+ r.add_effect_param = m.add_effect_param + r.add_effect_param
+ m.add_effect_message = 0
+ end
+ end
+ if m.has_spike_effect and r.spike_effect_message ~= 0 then
+ if r.spike_effect_effect == r.spike_effect_effect and m.spike_effect_message == r.spike_effect_message and m.spike_effect_message ~= 0 then
+ r.spike_effect_number = r.spike_effect_number + 1
+ if not sumdamage then
+ r.cspike_effect_param = (r.cspike_effect_param or r.spike_effect_param)..', '..m.spike_effect_param
+ end
+ r.spike_effect_param = m.spike_effect_param + r.spike_effect_param
+ m.spike_effect_message = 0
+ end
+ end
+ end
+ end
+ end
+ else
+ local tempact = v.actions[1]
+ if res.action_messages[tempact.message] then tempact.fields = fieldsearch(res.action_messages[tempact.message][language]) end
+ if res.action_messages[tempact.add_effect_message] then tempact.add_effect_fields = fieldsearch(res.action_messages[tempact.add_effect_message][language]) end
+ if res.action_messages[tempact.spike_effect_message] then tempact.spike_effect_fields = fieldsearch(res.action_messages[tempact.spike_effect_message][language]) end
+
+
+ --if tempact.add_effect_fields and tempact.add_effect_fields.status then windower.add_to_chat(8,tostring(tempact.add_effect_fields.status)..' '..res.action_messages[tempact.add_effect_message][language]) end
+
+ if not check_filter(act.actor,v.target[1],act.category,tempact.message) then
+ tempact.message = 0
+ tempact.add_effect_message = 0
+ end
+ if tempact.spike_effect_message ~= 0 and not check_filter(v.target[1],act.actor,act.category,tempact.message) then
+ tempact.spike_effect_message = 0
+ end
+ tempact.number = 1
+ if tempact.has_add_effect and tempact.message ~= 674 then
+ tempact.add_effect_number = 1
+ end
+ if tempact.has_spike_effect then
+ tempact.spike_effect_number = 1
+ end
+ if res.buffs[tempact.param] then -- and tempact.param ~= 0 then
+ tempact.status = res.buffs[tempact.param][language]
+ end
+ if res.buffs[tempact.add_effect_param] then -- and tempact.add_effect_param ~= 0 then
+ tempact.add_effect_status = res.buffs[tempact.add_effect_param][language]
+ end
+ if res.buffs[tempact.spike_effect_param] then -- and tempact.spike_effect_param ~= 0 then
+ tempact.spike_effect_status = res.buffs[tempact.spike_effect_param][language]
+ end
+ end
+
+ if condensetargets and i > 1 then
+ for n=1,i-1 do
+ local m = act.targets[n]
+ --windower.add_to_chat(8,m.actions[1].message..' '..v.actions[1].message)
+ if (v.actions[1].message == m.actions[1].message and v.actions[1].param == m.actions[1].param) or
+ (message_map[m.actions[1].message] and message_map[m.actions[1].message]:contains(v.actions[1].message) and v.actions[1].param == m.actions[1].param) or
+ (message_map[m.actions[1].message] and message_map[m.actions[1].message]:contains(v.actions[1].message) and v.actions[1].param == m.actions[1].param) then
+ m.target[#m.target+1] = v.target[1]
+ v.target[1] = nil
+ v.actions[1].message = 0
+ end
+ end
+ end
+ end
+
+ for i,v in pairs(act.targets) do
+ for n,m in pairs(v.actions) do
+ if m.message ~= 0 and res.action_messages[m.message] ~= nil then
+ local col = res.action_messages[m.message].color
+ local targ = assemble_targets(act.actor,v.target,act.category,m.message)
+ local color = color_filt(col,v.target[1].id==Self.id)
+ if m.reaction == 11 and act.category == 1 then m.simp_name = 'parried by'
+ --elseif m.reaction == 12 and act.category == 1 then m.simp_name = 'blocked by'
+ elseif m.message == 1 and (act.category == 1 or act.category == 11) then m.simp_name = 'hit'
+ elseif m.message == 15 then m.simp_name = 'missed'
+ elseif m.message == 29 or m.message == 84 then m.simp_name = 'is paralyzed'
+ elseif m.message == 30 then m.simp_name = 'anticipated by'
+ elseif m.message == 31 then m.simp_name = 'absorbed by'
+ elseif m.message == 32 then m.simp_name = 'dodged by'
+ elseif m.message == 67 and (act.category == 1 or act.category == 11) then m.simp_name = 'critical hit'
+ elseif m.message == 106 then m.simp_name = 'intimidated by'
+ elseif m.message == 153 then m.simp_name = act.action.name..' fails'
+ elseif m.message == 244 then m.simp_name = 'Mug fails'
+ elseif m.message == 282 then m.simp_name = 'evaded by'
+ elseif m.message == 373 then m.simp_name = 'absorbed by'
+ elseif m.message == 352 then m.simp_name = 'RA'
+ elseif m.message == 353 then m.simp_name = 'critical RA'
+ elseif m.message == 354 then m.simp_name = 'missed RA'
+ elseif m.message == 576 then m.simp_name = 'RA hit squarely'
+ elseif m.message == 577 then m.simp_name = 'RA struck true'
+ elseif m.message == 157 then m.simp_name = 'Barrage'
+ elseif m.message == 76 then m.simp_name = 'No targets within range'
+ elseif m.message == 77 then m.simp_name = 'Sange'
+ elseif m.message == 360 then m.simp_name = act.action.name..' (JA reset)'
+ elseif m.message == 426 or m.message == 427 then m.simp_name = 'Bust! '..act.action.name
+ elseif m.message == 435 or m.message == 436 then m.simp_name = act.action.name..' (JAs)'
+ elseif m.message == 437 or m.message == 438 then m.simp_name = act.action.name..' (JAs and TP)'
+ elseif m.message == 439 or m.message == 440 then m.simp_name = act.action.name..' (SPs, JAs, TP, and MP)'
+ elseif T{252,265,268,269,271,272,274,275,379,650,747}:contains(m.message) then m.simp_name = 'Magic Burst! '..act.action.name
+ elseif not act.action then
+ m.simp_name = ''
+ act.action = {}
+ else m.simp_name = act.action.name or ''
+ end
+
+ -- Debuff Application Messages
+ if simplify and message_map[82]:contains(m.message) then
+ if m.status == 'Evasion Down' then
+ m.message = 237
+ end
+ if m.status == 'addle' then m.status = 'addled'
+ elseif m.status == 'bind' then m.status = 'bound'
+ elseif m.status == 'blindness' then m.status = 'blinded'
+ elseif m.status == 'Inundation' then m.status = 'inundated'
+ elseif m.status == 'paralysis' then m.status = 'paralyzed'
+ elseif m.status == 'petrification' then m.status = 'petrified'
+ elseif m.status == 'poison' then m.status = 'poisoned'
+ elseif m.status == 'silence' then m.status = 'silenced'
+ elseif m.status == 'sleep' then m.status = 'asleep'
+ elseif m.status == 'slow' then m.status = 'slowed'
+ elseif m.status == 'stun' then m.status = 'stunned'
+ elseif m.status == 'weight' then m.status = 'weighed down'
+ end
+ end
+
+ -- Some messages uses the english log version of the buff
+ if not simplify and log_form_messages:contains(m.message) then
+ m.status = res.buffs[m.param].enl
+ end
+
+ -- if m.message == 93 or m.message == 273 then m.status=color_it('Vanish',color_arr['statuscol']) end
+
+ -- Special Message Handling
+ if m.message == 93 or m.message == 273 then
+ m.status=color_it('Vanish',color_arr['statuscol'])
+ elseif m.message == 522 and simplify then
+ targ = targ..' ('..color_it('stunned',color_arr['statuscol'])..')'
+ elseif m.message == 416 and simplify then
+ targ = targ..' ('..color_it('Magic Attack Boost and Magic Defense Boost',color_arr['statuscol'])..')'
+ elseif m.message == 1023 and simplify then
+ targ = targ..' ('..color_it('attacks and defenses enhanced',color_arr['statuscol'])..')'
+ elseif m.message == 762 and simplify then
+ targ = targ..' ('..color_it('all status parameters boosted',color_arr['statuscol'])..')'
+ elseif m.message == 779 and simplify then
+ targ = 'A barrier pulsates around '..targ
+ elseif m.message == 780 and simplify then
+ targ = 'Takes aim on '..targ
+ elseif T{158,188,245,324,592,658}:contains(m.message) and simplify then
+ -- When you miss a WS or JA. Relevant for condensed battle.
+ m.status = 'Miss' --- This probably doesn't work due to the if a==nil statement below.
+ elseif m.message == 653 or m.message == 654 then
+ m.status = color_it('Immunobreak',color_arr['statuscol'])
+ elseif m.message == 655 or m.message == 656 then
+ m.status = color_it('Completely Resists',color_arr['statuscol'])
+ elseif m.message == 85 or m.message == 284 then
+ if m.unknown == 2 then
+ m.status = color_it('Resists!',color_arr['statuscol'])
+ else
+ m.status = color_it('Resists',color_arr['statuscol'])
+ end
+ elseif m.message == 351 then
+ m.status = color_it('status ailments',color_arr['statuscol'])
+ m.simp_name = color_it('remedy',color_arr['itemcol'])
+ elseif T{75,114,156,189,248,283,312,323,336,355,408,422,423,425,659}:contains(m.message) then
+ m.status = color_it('No effect',color_arr['statuscol']) -- The status code for "No Effect" is 255, so it might actually work without this line
+ end
+ if m.message == 188 then
+ m.simp_name = m.simp_name..' (Miss)'
+ -- elseif m.message == 189 then
+ -- m.simp_name = m.simp_name..' (No Effect)'
+ elseif T{78,198,328}:contains(m.message) then
+ m.simp_name = '(Too Far)'
+ end
+ local msg,numb = simplify_message(m.message)
+ if not color_arr[act.actor.owner or act.actor.type] then windower.add_to_chat(123,'Battlemod error, missing filter:'..tostring(act.actor.owner)..' '..tostring(act.actor.type)) end
+ if m.fields.status then numb = m.status else numb = pref_suf((m.message == 674 and m.add_effect_param or m.cparam or m.param),m.message,act.actor.damage,col) end
+
+ if msg and m.message == 70 and not simplify then -- fix pronoun on parry
+ if v.target[1].race == 0 then
+ msg = msg:gsub(' his ',' its ')
+ elseif female_races:contains(v.target[1].race) then
+ msg = msg:gsub(' his ',' her ')
+ end
+ end
+
+ local count = ''
+ if m.message == 377 and act.actor_id == Self.id then
+ parse_quantity = true
+ item_quantity.id = act.action.item2_id
+ count = '${count}'
+ end
+
+ if not simplify then
+ if col == 'D' or grammar_numb_msg:contains(m.message) then
+ msg = grammatical_number_fix(msg, (m.cparam or m.param), m.message)
+ end
+ if act.action.item_id or act.action.item2_id then
+ msg = item_article_fix(act.action.item_id,act.action.item2_id,msg)
+ end
+ if common_nouns:contains(act.actor.id) then
+ msg = actor_noun(msg)
+ end
+ if plural_entities:contains(act.actor.id) then
+ msg = plural_actor(msg, m.message)
+ end
+ if targets_condensed or plural_entities:contains(v.target[1].id) then
+ msg = plural_target(msg, m.message)
+ end
+ end
+
+ local roll = showrollinfo and act.category == 6 and corsair_rolls[act.param] and corsair_rolls[act.param][m.param] or ''
+ local reaction_lookup = reaction_offsets[act.category] and (m.reaction - reaction_offsets[act.category]) or 0
+ local has_line_break = string.find(res.action_messages[m.message].en, '${lb}') and true or false
+ local prefix = (not has_line_break or simplify) and get_prefix(act.category, m.effect, m.message, m.unknown, reaction_lookup) or ''
+ local prefix2 = has_line_break and get_prefix(act.category, m.effect, m.message, m.unknown, reaction_lookup) or ''
+ local message = prefix..make_condensedamage_number(m.number)..( clean_msg((msg or tostring(m.message))
+ :gsub('${spell}',color_it(act.action.spell or 'ERROR 111',color_arr.spellcol))
+ :gsub('${ability}',color_it(act.action.ability or 'ERROR 112',color_arr.abilcol))
+ :gsub('${item}',color_it(act.action.item or 'ERROR 113',color_arr.itemcol))
+ :gsub('${item2}',count..color_it(act.action.item2 or 'ERROR 121',color_arr.itemcol))
+ :gsub('${weapon_skill}',color_it(act.action.weapon_skill or 'ERROR 114',color_arr.wscol))
+ :gsub('${abil}',m.simp_name or 'ERROR 115')
+ :gsub('${numb}',numb..roll or 'ERROR 116')
+ :gsub('${actor}\'s',color_it(act.actor.name or 'ERROR 117',color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name)
+ :gsub('${actor}',color_it(act.actor.name or 'ERROR 117',color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name)
+ :gsub('${target}\'s',targ)
+ :gsub('${target}',targ)
+ :gsub('${lb}','\7'..prefix2)
+ :gsub('${number}',(act.action.number or m.param)..roll)
+ :gsub('${status}',m.status or 'ERROR 120')
+ :gsub('${gil}',m.param..' gil'), m.message))
+ if m.message == 377 and act.actor_id == Self.id then
+ send_delayed_message:schedule(0.5,color,message)
+ else
+ windower.add_to_chat(color,message)
+ end
+ if not non_block_messages:contains(m.message) then
+ m.message = 0
+ end
+ end
+ if m.has_add_effect and m.add_effect_message ~= 0 and add_effect_valid[act.category] then
+ local targ = assemble_targets(act.actor,v.target,act.category,m.add_effect_message)
+ local col = res.action_messages[m.add_effect_message].color
+ local color = color_filt(col,v.target[1].id==Self.id)
+ if m.add_effect_message > 287 and m.add_effect_message < 303 then m.simp_add_name = skillchain_arr[m.add_effect_message-287]
+ elseif m.add_effect_message > 384 and m.add_effect_message < 399 then m.simp_add_name = skillchain_arr[m.add_effect_message-384]
+ elseif m.add_effect_message > 766 and m.add_effect_message < 769 then m.simp_add_name = skillchain_arr[m.add_effect_message-752]
+ elseif m.add_effect_message > 768 and m.add_effect_message < 771 then m.simp_add_name = skillchain_arr[m.add_effect_message-754]
+ elseif m.add_effect_message == 603 then m.simp_add_name = 'AE: TH'
+ elseif m.add_effect_message == 605 then m.simp_add_name = 'AE: Death'
+ elseif m.add_effect_message == 776 then m.simp_add_name = 'AE: Chainbound'
+ else m.simp_add_name = 'AE'
+ end
+ local msg,numb = simplify_message(m.add_effect_message)
+ if not simplify then
+ if col == 'D' or grammar_numb_msg:contains(m.add_effect_message) then
+ msg = grammatical_number_fix(msg, (m.cparam or m.param), m.add_effect_message)
+ end
+ if common_nouns:contains(act.actor.id) then
+ msg = actor_noun(msg)
+ end
+ if plural_entities:contains(act.actor.id) then
+ msg = plural_actor(msg, m.add_effect_message)
+ end
+ if targets_condensed or plural_entities:contains(v.target[1].id) then
+ msg = plural_target(msg, m.add_effect_message)
+ end
+ end
+ if m.add_effect_fields.status then numb = m.add_effect_status else numb = pref_suf((m.cadd_effect_param or m.add_effect_param),m.add_effect_message,act.actor.damage,col) end
+ if not act.action then
+-- windower.add_to_chat(color, 'act.action==nil : '..m.message..' - '..m.add_effect_message..' - '..msg)
+ else
+ windower.add_to_chat(color,make_condensedamage_number(m.add_effect_number)..(clean_msg(msg
+ :gsub('${spell}',act.action.spell or 'ERROR 127')
+ :gsub('${ability}',act.action.ability or 'ERROR 128')
+ :gsub('${item}',act.action.item or 'ERROR 129')
+ :gsub('${weapon_skill}',act.action.weapon_skill or 'ERROR 130')
+ :gsub('${abil}',m.simp_add_name or act.action.name or 'ERROR 131')
+ :gsub('${numb}',numb or 'ERROR 132')
+ :gsub('${actor}\'s',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name)
+ :gsub('${actor}',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name)
+ :gsub('${target}\'s',targ)
+ :gsub('${target}',targ)
+ :gsub('${lb}','\7')
+ :gsub('${number}',m.add_effect_param)
+ :gsub('${status}',m.add_effect_status or 'ERROR 178'), m.add_effect_message)))
+ if not non_block_messages:contains(m.add_effect_message) then
+ m.add_effect_message = 0
+ end
+ end
+ end
+ if m.has_spike_effect and m.spike_effect_message ~= 0 and spike_effect_valid[act.category] then
+ local targ = assemble_targets(act.actor,v.target,act.category,m.spike_effect_message)
+ local col = res.action_messages[m.spike_effect_message].color
+ local color = color_filt(col,act.actor.id==Self.id)
+
+ local actor = act.actor
+ if m.spike_effect_message == 14 then
+ m.simp_spike_name = 'from counter'
+ elseif T{33,606}:contains(m.spike_effect_message) then
+ m.simp_spike_name = 'counter'
+ actor = v.target[1] --Counter dmg is done by the target, fix for coloring the dmg
+ elseif m.spike_effect_message == 592 then
+ m.simp_spike_name = 'missed counter'
+ elseif m.spike_effect_message == 536 then
+ m.simp_spike_name = 'retaliation'
+ actor = v.target[1] --Retaliation dmg is done by the target, fix for coloring the dmg
+ elseif m.spike_effect_message == 535 then
+ m.simp_spike_name = 'from retaliation'
+ else
+ m.simp_spike_name = 'spikes'
+ actor = v.target[1] --Spikes dmg is done by the target, fix for coloring the dmg
+ end
+
+ local msg = simplify_message(m.spike_effect_message)
+ if not simplify then
+ if col == 'D' or grammar_numb_msg:contains(m.spike_effect_message) then
+ msg = grammatical_number_fix(msg, (m.cparam or m.param), m.spike_effect_message)
+ end
+ if common_nouns:contains(act.actor.id) then
+ msg = actor_noun(msg)
+ end
+ if plural_entities:contains(act.actor.id) then
+ msg = plural_actor(msg, m.spike_effect_message)
+ end
+ if targets_condensed or plural_entities:contains(v.target[1].id) then
+ msg = plural_target(msg, m.spike_effect_message)
+ end
+ end
+ if m.spike_effect_fields.status then numb = m.spike_effect_status else numb = pref_suf((m.cspike_effect_param or m.spike_effect_param),m.spike_effect_message,actor.damage,col) end
+ windower.add_to_chat(color,make_condensedamage_number(m.spike_effect_number)..(clean_msg(msg
+ :gsub('${spell}',act.action.spell or 'ERROR 142')
+ :gsub('${ability}',act.action.ability or 'ERROR 143')
+ :gsub('${item}',act.action.item or 'ERROR 144')
+ :gsub('${weapon_skill}',act.action.weapon_skill or 'ERROR 145')
+ :gsub('${abil}',m.simp_spike_name or act.action.name or 'ERROR 146')
+ :gsub('${numb}',numb or 'ERROR 147')
+ :gsub('${actor}\'s',color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..'\'s'..act.actor.owner_name)
+ :gsub((simplify and '${target}' or '${actor}'),color_it(act.actor.name,color_arr[act.actor.owner or act.actor.type])..act.actor.owner_name)
+ :gsub('${target}\'s',targ)
+ :gsub((simplify and '${actor}' or '${target}'),targ)
+ :gsub('${lb}','\7')
+ :gsub('${number}',m.spike_effect_param)
+ :gsub('${status}',m.spike_effect_status or 'ERROR 150'), m.spike_effect_message)))
+ if not non_block_messages:contains(m.spike_effect_message) then
+ m.spike_effect_message = 0
+ end
+ end
+ end
+ end
+
+ return act
+end
+
+function pref_suf(param,msg_ID,actor_dmg,col)
+ local outstr = (col == 'D' or dmg_drain_msg:contains(msg_ID)) and color_it(tostring(param),color_arr[actor_dmg]) or tostring(param)
+ local msg = res.action_messages[msg_ID] or nil
+ if msg then
+ if msg.prefix then
+ outstr = msg.prefix..' '..outstr
+ end
+ if msg.suffix then
+ if msg.suffix == 'shadow' and param ~= 1 then
+ outstr = outstr..' shadows'
+ elseif msg.suffix == 'Petra' and param ~= 1 then
+ outstr = outstr..' Petras'
+ elseif msg.suffix == 'effects disappears' and param ~= 1 then
+ outstr = outstr..' effects disappear'
+ elseif msg_ID == 641 then
+ outstr = outstr..' 1 attribute drained'
+ elseif msg.suffix == 'attributes drained' and param == 1 then
+ outstr = outstr..' attribute drained'
+ elseif msg.suffix == 'status effect drained' and param ~= 1 then
+ outstr = outstr..' status effects drained'
+ elseif msg.suffix == 'status ailments disappears' and param ~= 1 then
+ outstr = outstr..' status ailments disappear'
+ elseif msg.suffix == 'status ailments absorbed' and param == 1 then
+ outstr = outstr..' status ailment absorbed'
+ elseif msg.suffix == 'status ailments healed' and param == 1 then
+ outstr = outstr..' status ailment healed'
+ elseif msg.suffix == 'status benefits absorbed' and param == 1 then
+ outstr = outstr..' status benefit absorbed'
+ elseif msg.suffix == 'status effects removed' and param == 1 then
+ outstr = outstr..' status effect removed'
+ elseif msg.suffix == 'magic effects drained' and param == 1 then
+ outstr = outstr..' magic effect drained'
+ elseif msg.suffix == 'magical effects received' and param == 1 then
+ outstr = outstr..' magical effect received'
+ elseif msg.suffix == 'magical effects copied' and param == 1 then
+ outstr = outstr..' magical effect copied'
+ else
+ outstr = outstr..' '..msg.suffix
+ end
+ end
+ end
+ return outstr
+end
+
+function simplify_message(msg_ID)
+ local msg = res.action_messages[msg_ID][language]
+ local fields = fieldsearch(msg)
+
+ if simplify and not T{23,64,133,204,210,211,212,213,214,350,442,516,531,557,565,582}:contains(msg_ID) then
+ if T{93,273,522,653,654,655,656,85,284,75,114,156,189,248,283,312,323,336,351,355,408,422,423,425,453,659,158,245,324,658}:contains(msg_ID) then
+ fields.status = true
+ end
+ if msg_ID == 31 or msg_ID == 798 or msg_ID == 799 then
+ fields.actor = true
+ end
+ if (msg_ID > 287 and msg_ID < 303) or (msg_ID > 384 and msg_ID < 399) or (msg_ID > 766 and msg_ID < 771) or
+ T{129,152,161,162,163,165,229,384,453,603,652,798}:contains(msg_ID) then
+ fields.ability = true
+ end
+
+ if T{125,593,594,595,596,597,598,599}:contains(msg_ID) then
+ fields.ability = true
+ fields.item = true
+ end
+
+ if T{129,152,153,160,161,162,163,164,165,166,167,168,229,244,652}:contains(msg_ID) then
+ fields.actor = true
+ fields.target = true
+ end
+
+ if msg_ID == 139 then
+ fields.number = true
+ end
+
+ local Despoil_msg = {[593] = 'Attack Down', [594] = 'Defense Down', [595] = 'Magic Atk. Down', [596] = 'Magic Def. Down', [597] = 'Evasion Down', [598] = 'Accuracy Down', [599] = 'Slow',}
+ if line_full and fields.number and fields.target and fields.actor then
+ msg = line_full
+ elseif line_aoebuff and fields.status and fields.target then --and fields.actor then -- and (fields.spell or fields.ability or fields.item or fields.weapon_skill) then
+ msg = line_aoebuff
+ elseif line_item and fields.item2 then
+ if fields.number then
+ msg = line_itemnum
+ else
+ msg = line_item
+ end
+ elseif line_steal and fields.item and fields.ability then
+ if T{593,594,595,596,597,598,599}:contains(msg_ID) then
+ msg = line_steal..''..string.char(0x07)..'AE: '..color_it(Despoil_msg[msg_ID],color_arr['statuscol'])
+ else
+ msg = line_steal
+ end
+ elseif line_nonumber and not fields.number then
+ msg = line_nonumber
+ elseif line_aoe and T{264}:contains(msg_ID) then
+ msg = line_aoe
+ elseif line_noactor and not fields.actor and (fields.spell or fields.ability or fields.item or fields.weapon_skill) then
+ msg = line_noactor
+ elseif line_noability and not fields.actor then
+ msg = line_noability
+ elseif line_notarget and fields.actor and fields.number then
+ if msg_ID == 798 then --Maneuver message
+ msg = line_notarget..'%'
+ elseif msg_ID == 799 then --Maneuver message with overload
+ msg = line_notarget..'% (${actor} overloaded)'
+ else
+ msg = line_notarget
+ end
+ end
+ end
+ return msg
+end
+
+function assemble_targets(actor,targs,category,msg)
+ local targets = {}
+ local samename = {}
+ local total = 0
+ for i,v in pairs(targs) do
+ -- Done in two loops so that the ands and commas don't get out of place.
+ -- This loop filters out unwanted targets.
+ if check_filter(actor,v,category,msg) or check_filter(v,actor,category,msg) then
+ if samename[v.name] and condensetargetname then
+ samename[v.name] = samename[v.name] + 1
+ else
+ targets[#targets+1] = v
+ samename[v.name] = 1
+ end
+ total = total + 1
+ end
+ end
+ local out_str
+ if targetnumber and total > 1 then
+ out_str = '{'..total..'}: '
+ else
+ out_str = ''
+ end
+
+ for i,v in pairs(targets) do
+ local name = string.gsub(v.name,' ', string.char(0x81,0x3F)) --fix for ffxi chat splits on space
+ local article = common_nouns:contains(v.id) and (not simplify or msg == 206) and 'The ' or ''
+ local numb = condensetargetname and samename[v.name] > 1 and ' {'..samename[v.name]..'}' or ''
+ if i == 1 then
+ name = color_it(name,color_arr[v.owner or v.type])..v.owner_name
+ if samename[v.name] > 1 then
+ targets_condensed = true
+ else
+ if (not simplify or msg == 206) and #targets == 1 and string.find(res.action_messages[msg][language], '${target}\'s') then
+ name = color_it(name,color_arr[v.owner or v.type])..(plural_entities:contains(v.id) and '\'' or '\'s')..v.owner_name
+ end
+ targets_condensed = false
+ end
+ out_str = out_str..article..name..numb
+ else
+ targets_condensed = true
+ name = color_it(name,color_arr[v.owner or v.type])..v.owner_name
+ out_str = conjunctions(out_str,article..name..numb,#targets,i)
+ end
+ end
+ out_str = string.gsub(out_str,'-', string.char(0x81,0x7C)) --fix for ffxi chat splits on trusts with -
+ return out_str
+end
+
+function make_condensedamage_number(number)
+ if swingnumber and condensedamage and 1 < number then
+ return '['..number..'] '
+ else
+ return ''
+ end
+end
+
+function player_info(id)
+ local player_table = windower.ffxi.get_mob_by_id(id)
+ local typ,dmg,owner,filt,owner_name
+
+ if player_table == nil then
+ return {name=nil,id=nil,is_npc=nil,type='debug',owner=nil, owner_name=nil,race=nil}
+ end
+
+ for i,v in pairs(windower.ffxi.get_party()) do
+ if type(v) == 'table' and v.mob and v.mob.id == player_table.id then
+ typ = i
+ if i == 'p0' then
+ filt = 'me'
+ dmg = 'mydmg'
+ elseif i:sub(1,1) == 'p' then
+ filt = 'party'
+ dmg = 'partydmg'
+ else
+ filt = 'alliance'
+ dmg = 'allydmg'
+ end
+ end
+ end
+
+ if not filt then
+ if player_table.is_npc then
+ if player_table.index>1791 or player_table.charmed then
+ typ = 'other_pets'
+ filt = 'other_pets'
+ owner = 'other'
+ dmg = 'otherdmg'
+ for i,v in pairs(windower.ffxi.get_party()) do
+ if type(v) == 'table' and v.mob and v.mob.pet_index and v.mob.pet_index == player_table.index then
+ if i == 'p0' then
+ typ = 'my_pet'
+ filt = 'my_pet'
+ dmg = 'mydmg'
+ end
+ owner = i
+ owner_name = showownernames and ' ('..color_it(v.mob.name, color_arr[owner or typ])..')'
+ break
+ elseif type(v) == 'table' and v.mob and v.mob.fellow_index and v.mob.fellow_index == player_table.index then
+ if i == 'p0' then
+ typ = 'my_fellow'
+ filt = 'my_fellow'
+ dmg = 'mydmg'
+ end
+ owner = i
+ owner_name = showownernames and ' ('..color_it(v.mob.name, color_arr[owner or typ])..')'
+ break
+ end
+ end
+ else
+ typ = 'mob'
+ filt = 'monsters'
+ dmg = 'mobdmg'
+
+ if filter.enemies then
+ for i,v in pairs(Self.buffs) do
+ if domain_buffs:contains(v) then
+ -- If you are in Domain Invasion, or a Reive, or various other places
+ -- then all monsters should be considered enemies.
+ filt = 'enemies'
+ break
+ end
+ end
+
+ if filt ~= 'enemies' then
+ for i,v in pairs(windower.ffxi.get_party()) do
+ if type(v) == 'table' and nf(v.mob,'id') == player_table.claim_id then
+ filt = 'enemies'
+ break
+ end
+ end
+ end
+ end
+ end
+ else
+ typ = 'other'
+ filt = 'others'
+ dmg = 'otherdmg'
+ end
+ end
+ if not typ then typ = 'debug' end
+ return {name=player_table.monstrosity_name or player_table.name,id=id,is_npc = player_table.is_npc,type=typ,damage=dmg,filter=filt,owner=(owner or nil), owner_name=(owner_name or ''),race = player_table.race}
+end
+
+function get_spell(act)
+ local spell, abil_ID, effect_val = {}
+ local msg_ID = act.targets[1].actions[1].message
+
+ if T{7,8,9}:contains(act['category']) then
+ abil_ID = act.targets[1].actions[1].param
+ elseif T{3,4,5,6,11,13,14,15}:contains(act.category) then
+ abil_ID = act.param
+ effect_val = act.targets[1].actions[1].param
+ end
+
+ if act.category == 1 then
+ spell.english = 'hit'
+ spell.german = spell.english
+ spell.japanese = spell.english
+ spell.french = spell.english
+ elseif act.category == 2 and act.category == 12 then
+ if msg_ID == 77 then
+ spell = res.job_abilities[171] -- Sange
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ end
+ elseif msg_ID == 157 then
+ spell = res.job_abilities[60] -- Barrage
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ end
+ else
+ spell.english = 'Ranged Attack'
+ spell.german = spell.english
+ spell.japanese = spell.english
+ spell.french = spell.english
+ end
+ else
+ if not res.action_messages[msg_ID] then
+ if T{4,8}:contains(act['category']) then
+ spell = res.spells[abil_ID]
+ elseif T{6,14,15}:contains(act['category']) or T{7,13}:contains(act['category']) and false then
+ spell = res.job_abilities[abil_ID] -- May have to correct for charmed pets some day, but I'm not sure there are any monsters with TP moves that give no message.
+ elseif T{3,7,11}:contains(act['category']) then
+ if abil_ID < 256 then
+ spell = res.weapon_skills[abil_ID] -- May have to correct for charmed pets some day, but I'm not sure there are any monsters with TP moves that give no message.
+ else
+ spell = res.monster_abilities[abil_ID]
+ end
+ elseif T{5,9}:contains(act['category']) then
+ spell = res.items[abil_ID]
+ else
+ spell = {none=tostring(msg_ID)} -- Debugging
+ end
+ return spell
+ end
+
+ local fields = fieldsearch(res.action_messages[msg_ID][language])
+
+ if fields.spell then
+ spell = res.spells[abil_ID]
+ if spell then
+ spell.name = color_it(spell[language],color_arr.spellcol)
+ spell.spell = color_it(spell[language],color_arr.spellcol)
+ end
+ elseif fields.ability then
+ spell = res.job_abilities[abil_ID]
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ if msg_ID == 139 then
+ spell.number = 'Nothing'
+ end
+ end
+ elseif fields.weapon_skill then
+ if abil_ID > 256 then -- WZ_RECOVER_ALL is used by chests in Limbus
+ spell = res.monster_abilities[abil_ID]
+ if not spell then
+ spell = {english= 'Special Attack'}
+ end
+ elseif abil_ID <= 256 then
+ spell = res.weapon_skills[abil_ID]
+ end
+ if spell then
+ spell.name = color_it(spell[language],color_arr.wscol)
+ spell.weapon_skill = color_it(spell[language],color_arr.wscol)
+ end
+ elseif msg_ID == 303 then
+ spell = res.job_abilities[74] -- Divine Seal
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ end
+ elseif msg_ID == 304 then
+ spell = res.job_abilities[75] -- 'Elemental Seal'
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ end
+ elseif msg_ID == 305 then
+ spell = res.job_abilities[76] -- 'Trick Attack'
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ end
+ elseif msg_ID == 311 or msg_ID == 312 then
+ spell = res.job_abilities[79] -- 'Cover'
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ end
+ elseif msg_ID == 240 or msg_ID == 241 then
+ spell = res.job_abilities[43] -- 'Hide'
+ if spell then
+ spell.name = color_it(spell[language],color_arr.abilcol)
+ spell.ability = color_it(spell[language],color_arr.abilcol)
+ end
+ end
+
+ if fields.item then
+ if T{125,593,594,595,596,597,598,599}:contains(msg_ID) then
+ local item_article = not simplify and add_item_article(effect_val) or ''
+ spell.item = color_it(item_article..res.items[effect_val]['english_log'], color_arr.itemcol)
+ spell.item_id = res.items[effect_val].id
+ else
+ spell = res.items[abil_ID]
+ local item_article = not simplify and add_item_article(spell.id) or ''
+ if spell then
+ spell.name = color_it(item_article..spell['english_log'],color_arr.itemcol)
+ spell.item = color_it(item_article..spell['english_log'],color_arr.itemcol)
+ spell.item_id = abil_ID
+ end
+ end
+ end
+
+ if fields.item2 then
+ local item_article = not simplify and add_item_article(effect_val) or ''
+ local tempspell = (msg_ID == 377 or msg_ID == 674) and res.items_grammar[effect_val] and res.items_grammar[effect_val].plural or item_article..res.items[effect_val].english_log
+ spell.item2 = color_it(tempspell,color_arr.itemcol)
+ spell.item2_id = effect_val
+ if fields.number then
+ spell.number = act.targets[1].actions[1].add_effect_param
+ end
+ end
+ end
+
+ if spell and not spell.name then spell.name = spell[language] end
+ return spell
+end
+
+
+function color_filt(col,is_me)
+ --Used to convert situational colors from the resources into real colors
+ --Depends on whether or not the target is you, the same as using in-game colors
+ -- Returns a color code for windower.add_to_chat()
+ -- Does not currently support a Debuff/Buff distinction
+ if col == 'D' then -- Damage
+ if is_me then
+ return 28
+ else
+ return 20
+ end
+ elseif col == 'M' then -- Misses
+ if is_me then
+ return 29
+ else
+ return 21
+ end
+ elseif col == 'H' then -- Healing
+ if is_me then
+ return 30
+ else
+ return 22
+ end
+ elseif col == 'B' then -- Beneficial effects
+ if is_me then
+ return 56
+ else
+ return 60
+ end
+ elseif col == 'DB' then -- Detrimental effects (I don't know how I'd split these)
+ if is_me then
+ return 57
+ else
+ return 61
+ end
+ elseif col == 'R' then -- Resists
+ if is_me then
+ return 59
+ else
+ return 63
+ end
+ else
+ return col
+ end
+end
+
+function get_prefix(category, effect, message, unknown, reaction_lookup)
+ local prefix = S{1,3,4,6,11,13,14,15}:contains(category) and (bit.band(unknown,1)==1 and 'Cover! ' or '')
+ ..(bit.band(unknown,4)==4 and 'Magic Burst! ' or '') --Used on Swipe/Lunge MB
+ ..(bit.band(unknown,8)==8 and 'Immunobreak! ' or '') --Unused? Displayed directly on message
+ ..(showcritws and bit.band(effect,2)==2 and S{1,3,11}:contains(category) and message~=67 and 'Critical Hit! ' or '') --Unused? Crits have their own message
+ ..(showblocks and reaction_lookup == 4 and 'Blocked! ' or '')
+ ..(showguards and reaction_lookup == 2 and 'Guarded! ' or '')
+ ..(reaction_lookup == 3 and S{3,4,6,11,13,14,15}:contains(category) and 'Parried! ' or '') --Unused? They are send the same as missed
+ return prefix
+end
+
+function condense_actions(action_array)
+ for i,v in pairs(action_array) do
+ local comb_table = {}
+ for n,m in pairs(v) do
+ if comb_table[m.primary.name] then
+ if m.secondary.name == 'number' then
+ comb_table[m.primary.name].secondary.name = tostring(tonumber(comb_table[m.primary.name].secondary.name)+tonumber(m.secondary.name))
+ end
+ comb_table[m.primary.name].count = comb_table[m.primary.name].count + 1
+ else
+ comb_table[m.primary.name] = m
+ comb_table[m.primary.name].count = 1
+ end
+ m = nil -- Could cause next() error
+ end
+ for n,m in pairs(comb_table) do
+ v[#v+1] = m
+ end
+ end
+ return action_array
+end
+
+function condense_targets(action_array)
+ local comb_table = {}
+ for i,v in pairs(action_array) do
+ local was_created = false
+ for n,m in pairs(comb_table) do
+ if table.equal(v,m,3) then -- Compares 3 levels deep
+ n[#n+1] = i[1]
+ was_created = true
+ end
+ end
+ if not was_created then
+ comb_table[{i[1]}] = v
+ end
+ end
+ return comb_table
+end