Skip to content

Commit

Permalink
Add support for items in shortcuts addon.
Browse files Browse the repository at this point in the history
  • Loading branch information
bsb002-flash-tester committed Nov 24, 2021
1 parent 7620dd2 commit 410cd5e
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 47 deletions.
22 changes: 19 additions & 3 deletions addons/shortcuts/helper_functions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,33 @@ function bracket_closer(str,opener,closer)
end

-----------------------------------------------------------------------------------
--Name: strip()
--Name: strip_non_alphanumeric_convert_digits_to_roman()
--Args:
---- name (string): Name to be slugged
---- name (string): Name to be stripped
-----------------------------------------------------------------------------------
--Returns:
---- string with a gsubbed version of name that removes non-alphanumeric characters,
-------- forces the string to lower-case, and converts numbers to Roman numerals,
-------- which are upper case.
-----------------------------------------------------------------------------------
function strip(name)
function strip_non_alphanumeric_convert_digits_to_roman(name)
return name:gsub('[^%w]',''):lower():gsub('(%d+)',to_roman)
end

-----------------------------------------------------------------------------------
--Name: strip_non_alphanumeric_keep_plus()
--Args:
---- name (string): Name to be stripped
-----------------------------------------------------------------------------------
--Returns:
---- string with a gsubbed version of name that removes non-alphanumeric characters,
-------- but allows the character '+', and forces the string to lower-case. Does not
-------- convert numbers to roman numerals.
-----------------------------------------------------------------------------------
function strip_non_alphanumeric_keep_plus(name)
return name:gsub('[^%w+]',''):lower()
end


-----------------------------------------------------------------------------------
--Name: to_roman()
Expand Down Expand Up @@ -186,6 +200,8 @@ function check_usability(player,resource,id)
return true
elseif resource == 'mounts' and math.floor((windower.packets.last_incoming(0x0AE):byte(math.floor(id/8)+5)%2^(id%8+1))/2^(id%8)) == 1 then
return true
elseif resource == 'items' then
return true
end
end

Expand Down
124 changes: 90 additions & 34 deletions addons/shortcuts/shortcuts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,16 @@ default_aliases = {
cw5="Curing Waltz V",
hw="Healing Waltz"
}
default_settings = {
include_items = false,
}

aliases = config.load('data\\aliases.xml',default_aliases)
aliases = config.load('data/aliases.xml', default_aliases)
settings = config.load('data/settings.xml', default_settings)
config.save(aliases)
config.save(settings)
setmetatable(aliases,nil)
setmetatable(settings,nil)


require 'statics'
Expand Down Expand Up @@ -166,12 +172,12 @@ windower.register_event('outgoing text',function(original,modified)
if modified:sub(1,1) ~= '/' then return modified end
debug_chat('outgoing_text: '..modified..' '..tostring(windower.ffxi.get_mob_by_target('st')))
temp_org = temp_org:gsub(' <wait %d+>',''):sub(2)

if logging then
logfile:write('\n\n',tostring(os.clock()),'temp_org: ',temp_org,'\nModified: ',modified)
logfile:flush()
end

-- If it's the command that was just sent, blank lastsent and pass it through with only the changes applied by other addons
if modified == lastsent then
lastsent = ''
Expand Down Expand Up @@ -218,11 +224,11 @@ function command_logic(original,modified)
potential_targ = splitline[splitline.n]
end
local a,b,spell = string.find(original,'"(.-)"')

if unhandled_list[command] then
return modified,true
end

if spell then
spell = spell:lower()
elseif splitline.n == 3 then
Expand All @@ -232,17 +238,17 @@ function command_logic(original,modified)
spell = splitline[2]..' '..splitline[3]
end
end

if targ_reps[potential_targ] then
potential_targ = targ_reps[potential_targ]
end

if ignore_list[command] then -- If the command is legitimate and on the blacklist, return it unaltered.
lastsent = ''
return modified,true
elseif command2_list[command] and not valid_target(potential_targ,true) then
-- If the command is legitimate and requires target completion but not ability interpretation

if not command2_list[command].args then -- If there are not any secondary commands
local temptarg = valid_target(potential_targ) or target_make(command2_list[command]) -- Complete the target or make one.
if temptarg ~= '<me>' then -- These commands, like emotes, check, etc., don't need to default to <me>
Expand All @@ -253,7 +259,7 @@ function command_logic(original,modified)

debug_chat('258: input '..lastsent)
if logging then
logfile:write('\n\n',tostring(os.clock()),'Original: ',original,'\n(162) ',lastsent)
logfile:write('\n\n',tostring(os.clock()),'Original: ',original,'\n(162) ',lastsent)
logfile:flush()
end
windower.send_command('@input '..lastsent)
Expand Down Expand Up @@ -339,54 +345,104 @@ end
---- Sends a command if the command needs to be changed.
-----------------------------------------------------------------------------------
function interp_text(splitline,offset,modified)
local temptarg,abil
local no_targ_abil = strip(table.concat(splitline,' ',1+offset,splitline.n))

if validabils[no_targ_abil] then
abil = no_targ_abil
-- Assume there was not a target suffix on the command.
local preliminary_action_name = table.concat(splitline,' ',1+offset,splitline.n)
local preliminary_action_name_normalized_as_item = strip_non_alphanumeric_keep_plus(preliminary_action_name)
local preliminary_action_name_normalized_as_nonitem = strip_non_alphanumeric_convert_digits_to_roman(preliminary_action_name)

-- Note: The normalized 'item' name is almost strictly more specific than
-- the normalized 'nonitem' name, and thus the former must be searched
-- before the latter to avoid falsely matching the wrong entry.
local temporary_target_name, normalized_preliminary_action_name
if validabils[preliminary_action_name_normalized_as_item] then
normalized_preliminary_action_name = preliminary_action_name_normalized_as_item
elseif validabils[preliminary_action_name_normalized_as_nonitem] then
normalized_preliminary_action_name = preliminary_action_name_normalized_as_nonitem
elseif splitline.n > 1 then
temptarg = valid_target(targ_reps[splitline[splitline.n]] or splitline[splitline.n])
temporary_target_name = valid_target(targ_reps[splitline[splitline.n]] or splitline[splitline.n])
end

if temptarg then abil = _raw.table.concat(splitline,' ',1+offset,splitline.n-1)
elseif not abil then abil = _raw.table.concat(splitline,' ',1+offset,splitline.n) end

local strippedabil = strip(abil) -- Slug the ability
-- Compute a better name to look up based on the result of the above.
local finalized_action_name = normalized_preliminary_action_name
if temporary_target_name then
finalized_action_name = _raw.table.concat(splitline,' ',1+offset,splitline.n-1)
elseif not normalized_preliminary_action_name then
finalized_action_name = _raw.table.concat(splitline,' ',1+offset,splitline.n)
end

-- Re-normalize the action name, but using the finalized name
local finalized_action_name_normalized_as_item = strip_non_alphanumeric_keep_plus(finalized_action_name)
local finalized_action_name_normalized_as_nonitem = strip_non_alphanumeric_convert_digits_to_roman(finalized_action_name)

-- Note: The normalized 'item' name is almost strictly more specific than
-- the normalized 'nonitem' name, and thus the former must be searched
-- before the latter to avoid falsely matching the wrong entry.
local actions_by_normalized_name
if validabils[finalized_action_name_normalized_as_item] then
actions_by_normalized_name = validabils[finalized_action_name_normalized_as_item]
else
actions_by_normalized_name = validabils[finalized_action_name_normalized_as_nonitem]
end

if validabils[strippedabil] then
local options,nonoptions,num_opts, r_line = {},{},0
if actions_by_normalized_name then
local options,nonoptions,num_opts = {},{},0
local player = windower.ffxi.get_player()
for v in validabils[strippedabil]:it() do
for v in actions_by_normalized_name:it() do
if check_usability(player,v.res,v.id) then
options[v.res] = v.id
num_opts = num_opts + 1
elseif v.res ~= nil then
nonoptions[v.res] = v.id
end
end
if num_opts > 0 then
-- If there are usable options then prioritize:
-- Prefix, if given -> Spells -> Job Abilities -> Weapon Skills -> Monster Skills
r_line = res[(offset == 1 and options[command_list[splitline[1]]] and command_list[splitline[1]]) or (options.spells and 'spells') or (options.job_abilities and 'job_abilities') or (options.weapon_skills and 'weapon_skills') or (options.monster_skills and 'monster_skills') or (options.mounts and 'mounts')][options[command_list[splitline[1]]] or options.spells or options.job_abilities or options.weapon_skills or options.monster_skills or options.mounts]
elseif num_opts == 0 then
r_line = res[(offset == 1 and nonoptions[command_list[splitline[1]]] and command_list[splitline[1]]) or (nonoptions.spells and 'spells') or (nonoptions.weapon_skills and 'weapon_skills') or (nonoptions.job_abilities and 'job_abilities') or (nonoptions.monster_skills and 'monster_skills') or (nonoptions.mounts and 'mounts')][nonoptions[command_list[splitline[1]]] or nonoptions.spells or nonoptions.weapon_skills or nonoptions.job_abilities or nonoptions.monster_skills or nonoptions.mounts]

-- If there are usable options then prioritize:
-- Prefix, if given -> Spells -> Job Abilities -> Weapon Skills -> Monster Skills
local r_type,r_idx,r_line
local opts_to_use = num_opts > 0 and options or nonoptions
if offset == 1 and opts_to_use[command_list[splitline[1]]] then
r_type = command_list[splitline[1]]
else
r_type = (opts_to_use.spells and 'spells')
or (opts_to_use.job_abilities and 'job_abilities')
or (opts_to_use.weapon_skills and 'weapon_skills')
or (opts_to_use.monster_skills and 'monster_skills')
or (opts_to_use.mounts and 'mounts')
or (opts_to_use.items and 'items')
end
if opts_to_use[command_list[splitline[1]]] then
r_idx = opts_to_use[command_list[splitline[1]]]
else
r_idx = opts_to_use.spells
or opts_to_use.job_abilities
or opts_to_use.weapon_skills
or opts_to_use.monster_skills
or opts_to_use.mounts
or opts_to_use.items
end
r_line = res[r_type][r_idx]

-- Modify r_line to contain 'prefix' for items.
if r_line and not r_line.prefix and r_type == 'items' then
r_line = r_line:copy()
r_line.prefix = '/item'
end

local targets = table.reassign({},r_line.targets)

-- Handling for abilities that change potential targets.
if r_line.skill == 40 and r_line.cast_time == 8 and L(player.buffs):contains(409) then
targets.Party = true -- Pianissimo changes the target list of
targets.Party = true -- Pianissimo changes the target list of
elseif r_line.skill == 44 and r_line.en:find('Indi-') and L(player.buffs):contains(584) then
targets.Party = true -- Indi- spells can be cast on others when Entrust is up
end

local abil_name = r_line.english -- Remove spaces at the end of the ability name.
while abil_name:sub(-1) == ' ' do
abil_name = abil_name:sub(1,-2)
end
local out_tab = {prefix = in_game_res_commands[r_line.prefix:gsub("/","")], name = abil_name, target = temptarg or target_make(targets)}

local out_tab = {prefix = in_game_res_commands[r_line.prefix:gsub("/","")], name = abil_name, target = temporary_target_name or target_make(targets)}
if not out_tab.prefix then print('Could not find prefix',r_line.prefix) end
lastsent = out_tab.prefix..' "'..out_tab.name..'" '..out_tab.target
if logging then
Expand Down
20 changes: 12 additions & 8 deletions addons/shortcuts/statics.lua
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,11 @@ validabils = {}
-- List of valid prefixes to be interpreted with the resources. The values currently have no use.
command_list = {['ja']='job_abilities',['jobability']='job_abilities',['so']='spells',['song']='spells',['ma']='spells',['magic']='spells',['nin']='spells',['ninjutsu']='spells',
['ra']='Ranged Attack',['range']='Ranged Attack',['throw']='Ranged Attack',['shoot']='Ranged Attack',['monsterskill']='monster_skills',['ms']='monster_skills',
['ws']='weapon_skills',['weaponskill']='weapon_skills',['item']='Ability',['pet']='job_abilities',['mo']='mounts',['mount']='mounts'}
['ws']='weapon_skills',['weaponskill']='weapon_skills',['item']='items',['pet']='job_abilities',['mo']='mounts',['mount']='mounts'}

in_game_res_commands = {['ja']='/ja',['jobability']='/ja',['pet']='/ja',
['so']='/ma',['song']='/ma',['ma']='/ma',['magic']='/ma',['nin']='/ma',['ninjutsu']='/ma',
['monsterskill']='/ms',['ms']='/ms',['ws']='/ws',['weaponskill']='/ws',
['monsterskill']='/ms',['ms']='/ms',['ws']='/ws',['weaponskill']='/ws',['item']='/item',
['ra']='/ra',['range']='/ra',['throw']='/ra',['shoot']='/ra',['mount']='/mo',['mo']='/mo'}

-- List of other commands that might use name completion.
Expand Down Expand Up @@ -161,7 +161,7 @@ command2_list = {
['returnfaith']=new_cmd_entry(Party_targets,{all=No_targets}),
['bstpet']=new_cmd_entry(No_targets,{['1']=BST_targets,['2']=BST_targets,['3']=BST_targets,['4']=BST_targets,['5']=BST_targets,['6']=BST_targets,['7']=BST_targets}),
}

unhandled_list = {['p']=true,['s']=true,['sh']=true,['yell']=true,['echo']=true,['t']=true,['l']=true,['breaklinkshell']=true}

-- List of commands to be ignored
Expand All @@ -176,7 +176,7 @@ st_targs = T{'<st>','<stpc>','<stal>','<stnpc>','<stpt>'}
targ_reps = {t='<t>',me='<me>',ft='<ft>',scan='<scan>',bt='<bt>',lastst='<lastst>',r='<r>',pet='<pet>',p0='<p0>',p1='<p1>',p2='<p2>',p3='<p3>',p4='<p4>',
p5='<p5>',a10='<a10>',a11='<a11>',a12='<a12>',a13='<a13>',a14='<a14>',a15='<a15>',a20='<a20>',a21='<a21>',a22='<a22>',a23='<a23>',a24='<a24>',a25='<a25>',
st='<st>',stpc='<stpc>',stal='<stal>',stnpc='<stnpc>',stpt='<stpt>',focust='<focust>'}

language = 'english' -- windower.ffxi.get_info()['language']:lower()


Expand All @@ -198,9 +198,10 @@ end
-- Iterate through resources and make validabils.
function validabils_it(resource)
for id,v in pairs(res[resource]) do
if (not v.monster_level and v.prefix) or (v.monster_level and v.monster_level ~= -1 and v.ja:sub(1,1) ~= '#' ) then
if (not v.monster_level and v.prefix) or (v.monster_level and v.monster_level ~= -1 and v.ja:sub(1,1) ~= '#' ) or (v.category == 'Usable') then
-- Monster Abilities contains a large number of player-usable moves (but not monstrosity-usable). This excludes them.
make_abil(strip(v.english),resource,id)
local name = resource ~= 'items' and strip_non_alphanumeric_convert_digits_to_roman(v.english) or strip_non_alphanumeric_keep_plus(v.english)
make_abil(name,resource,id)
end
end
end
Expand All @@ -209,4 +210,7 @@ validabils_it('spells')
validabils_it('job_abilities')
validabils_it('weapon_skills')
validabils_it('monster_skills')
validabils_it('mounts')
validabils_it('mounts')
if settings.include_items then
validabils_it('items')
end
4 changes: 2 additions & 2 deletions addons/shortcuts/targets.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
-----------------------------------------------------------------------------------
function valid_target(targ,flag)
local spell_targ
local san_targ = find_san(strip(targ))
local san_targ = find_san(strip_non_alphanumeric_convert_digits_to_roman(targ))
-- If the target is whitelisted, pass it through.
if pass_through_targs:contains(targ:lower()) or st_targs:contains(targ:lower()) or (tonumber(targ:lower()) and windower.ffxi.get_mob_by_id(tonumber(targ:lower()))) then
return targ:lower()
Expand All @@ -48,7 +48,7 @@ function valid_target(targ,flag)
local current_target = windower.ffxi.get_mob_by_target('t')
local targar = {}
for i,v in pairs(windower.ffxi.get_mob_array()) do
if string.find(strip(v.name),san_targ) and (v.valid_target or v.id == windower.ffxi.get_player().id) then -- Malformed pattern somehow
if string.find(strip_non_alphanumeric_convert_digits_to_roman(v.name),san_targ) and (v.valid_target or v.id == windower.ffxi.get_player().id) then -- Malformed pattern somehow
-- Handling for whether it's a monster or not
if v.is_npc and v.spawn_type ~= 14 and current_target then
if v.id == current_target.id then
Expand Down

0 comments on commit 410cd5e

Please sign in to comment.