Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions Singer/Singer addon for in gearswap used.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@



--[[ for gearswap work singer addon cycle songs playlist faster and easy

add in function

function job_setup()

send_command('lua l Singer')--;sing off;sing active off


state.Singer = M{['description']='Singer','seg','Cuijatender','haste4','seg','seg4','shinryu','shinryu4','mboze','mboze2', 'xevioso', 'kalunga', 'ngai','arebati', 'ongo', 'bumba',
'haste','haste4', 'magic', 'ph','sortie4', 'ody4', 'ody','sortie',} --'aria',

end

function job_self_command(commandArgs, eventArgs)

if commandArgs[1]:lower() == 'singer' then
send_command('@input //sing playlist "'..state.Singer.value..'"')
end

end


for binds add

function user_job_setup()

send_command('bind tab gs c cycle singer;gs c singer')
send_command('bind ^tab gs c cycleback singer;gs c singer')

end












]]
124 changes: 96 additions & 28 deletions Singer/Singer.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
_addon.author = 'Ivaar'
_addon.author = 'Ivaar', 'PBW' ,'Aragan' --ADD CCSV AUTO BY 'Aragan'
_addon.commands = {'Singer','sing'}
_addon.name = 'Singer'
_addon.version = '1.20.08.18'
_addon.version = '1.30.20.0' -- last version update by 'Aragan'

require('luau')
require('pack')
Expand All @@ -12,21 +12,26 @@ config = require('config')
get = require('sing_get')
cast = require('sing_cast')
song_timers = require('song_timers')
res = require('resources') -- مكتبة الـ abilities الرسمية


default = {
interval = 0.1,
delay=4,
marcato='Sentinel\'s Scherzo',
delay=6,
marcato='Honor March',
soul_voice=false,
clarion=false,
ccsv=false,
actions=false,
pianissimo=false,
nightingale=true,
troubadour=true,
nightingale=false,
troubadour=false,
nitro=false,
debuffing=false,
recast={song={min=20,max=25},buff={min=5,max=10}},
active=true,
timers=true,
song_debuffs='',
recast={song={min=0,max=0},buff={min=0,max=0}},
active=false,
timers=false,
aoe={['party']=true, ['p1'] = true,['p2'] = true,['p3'] = true,['p4'] = true,['p5'] = true},
min_ws=20,
max_ws=99,
Expand All @@ -35,6 +40,10 @@ default = {

settings = config.load(default)


-- Force refresh state
_force_refresh = false
_force_refresh_index = 1
setting = T{
buffs = T{
haste = L{},
Expand All @@ -44,14 +53,18 @@ setting = T{
},
debuffs = L{},
debuffs = L{"Carnage Elegy","Pining Nocturne",},
dummy = L{"Knight's Minne","Knight's Minne II",},
songs = L{"Advancing March","Victory March","Blade Madrigal","Sword Madrigal","Valor Minuet V",},
dummy = L{"Puppet's Operetta","Scop's Operetta","Shining Fantasia",},
songs = L{"Honor March","Victory March","Valor Minuet V","Valor Minuet IV",},
song = {},
playlist = T{
clear = L{}
},
}

local song_debuffs = {
['Carnage Elegy'] = true,
['Pining Nocturne'] = true,
-- ['Foe Requiem VII'] = true,
}
local save_file

do
Expand Down Expand Up @@ -110,18 +123,16 @@ function colorize(row, str)
return '\\cs(0,255,0)%s\\cr':format(str)
end

local buttons = {'active','actions','nightingale','troubadour','pianissimo','debuffing','party','p1','p2','p3','p4','p5'}

local buttons = {'active','actions','nitro','ccsv','debuffing','pianissimo','party','p1','p2','p3','p4','p5'}
local display_box = function()
local str = colorize(1, 'Singer')
str = str .. colorize(2, '\n Actions: [%s]':format(settings.actions and 'On' or 'Off'))

if not settings.active then return str end

str = str..colorize(3, '\n Nightingale:[%s]':format(settings.nightingale and 'On' or 'Off'))
str = str..colorize(4, '\n Troubadour:[%s]':format(settings.troubadour and 'On' or 'Off'))
str = str..colorize(5, '\n Pianissimo:[%s]':format(settings.pianissimo and 'On' or 'Off'))
str = str..colorize(6, '\n Debuffing:[%s]':format(settings.debuffing and 'On' or 'Off'))
str = str..colorize(3, '\n Nitro:[%s]':format(settings.nitro and 'On' or 'Off'))
str = str..colorize(4, '\n Ccsv:[%s]':format(settings.ccsv and 'On' or 'Off'))
str = str..colorize(5, '\n Debuffing:[%s]':format(settings.debuffing and 'On' or 'Off'))
str = str..colorize(6, '\n Pianissimo:[%s]':format(settings.pianissimo and 'On' or 'Off'))
str = str..colorize(7, '\n AoE: [%s]':format(settings.aoe.party and 'On' or 'Off'))

if settings.aoe.party then
Expand Down Expand Up @@ -189,7 +200,7 @@ function do_stuff()
if is_moving or buffs.stun or buffs.sleep or buffs.charm or buffs.terror or buffs.petrification then return end

local JA_WS_lock = buffs.amnesia or buffs.impairment

if use_ws and not JA_WS_lock and play.status == 1 then
local targ = windower.ffxi.get_mob_by_target('t')
local goal_tp
Expand Down Expand Up @@ -250,19 +261,24 @@ function do_stuff()

if settings.debuffing then
local targ = windower.ffxi.get_mob_by_target('bt')

if targ and targ.hpp > 0 and targ.valid_target and targ.distance:sqrt() < 20 then
for song in setting.debuffs:it() do
local effect
for k,v in pairs(get.debuffs) do
for k, v in pairs(get.debuffs) do
if table.find(v, song) then
effect = k
effect = k
break
end
end

if effect and (not debuffed[targ.id] or not debuffed[targ.id][effect]) and spell_recasts[get.song_by_name(song).id] == 0 then
cast.MA(song,'<bt>')

-- التحقق مما إذا كان الهدف قد تأثر بالفعل بالتعويذة
if effect and (not debuffed[targ.id] or not debuffed[targ.id][effect]) then
if spell_recasts[get.song_by_name(song).id] == 0 then
cast.MA(song, '<bt>')
debuffed[targ.id] = debuffed[targ.id] or {}
debuffed[targ.id][effect] = true
end
break
end
end
Expand Down Expand Up @@ -408,6 +424,10 @@ short_commands = {
['p'] = 'pianissimo',
['n'] = 'nightingale',
['t'] = 'troubadour',
['n'] = 'nitro',
['cc'] = 'CCSV',
['c'] = 'clarion',
['s'] = 'soul_voice',
['play'] = 'playlist',
}

Expand All @@ -434,7 +454,9 @@ function resolve_song(commands)
end

windower.register_event('addon command', function(...)
local commands = T(arg):map(windower.convert_auto_trans .. string.lower)

-- hook for action on/off
local commands = T(arg):map(windower.convert_auto_trans .. string.lower)

commands[1] = short_commands[commands[1]] or commands[1]

Expand Down Expand Up @@ -734,6 +756,29 @@ windower.register_event('addon command', function(...)
assert(loadstring(table.concat(commands, ' ',2)))()
end
bard_status:text(display_box())

-- Force Refresh command: //singer fr on|off|toggle|once
if cmd == 'fr' or cmd == 'forcer' or cmd == 'refresh' then
local arg = (args and args[1]) and tostring(args[1]):lower() or 'once'
if arg == 'on' then
_force_refresh = true and true or true
_force_refresh_index = 1
windower.add_to_chat(207, '[Singer] ForceRefresh: On (queued).')
elseif arg == 'off' then
_force_refresh = false
_force_refresh_index = 1
windower.add_to_chat(207, '[Singer] ForceRefresh: Off.')
elseif arg == 'toggle' then
_force_refresh = not _force_refresh
if _force_refresh then _force_refresh_index = 1 end
windower.add_to_chat(207, ('[Singer] ForceRefresh: %s.'):format(_force_refresh and 'On' or 'Off'))
else -- once
_force_refresh = true
_force_refresh_index = 1
windower.add_to_chat(207, '[Singer] ForceRefresh: Once queued.')
end
return
end
end)

function event_change()
Expand Down Expand Up @@ -789,3 +834,26 @@ windower.register_event('mouse', mouse_event)
windower.register_event('unload', song_timers.reset)
windower.register_event('status change', status_change)
windower.register_event('zone change','job change','logout', event_change)


-- Minimal addon command handler (append) for action on/off if not present
windower.register_event('addon command', function(cmd, ...)
cmd = (cmd or ''):lower()
local args = {...}
if cmd == 'action' or cmd == 'actions' then
local arg = (args[0] or args[1] or ''):lower()
if arg == 'on' then
settings.actions = true
config.save(settings)
_force_refresh = true
_force_refresh_index = 1
windower.add_to_chat(207, '[Singer] Actions ON → Force refresh queued.')
return
elseif arg == 'off' then
settings.actions = false
config.save(settings)
windower.add_to_chat(207, '[Singer] Actions OFF')
return
end
end
end)
35 changes: 32 additions & 3 deletions Singer/sing_cast.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ function cast.MA(str,ta)
end

function cast.check_song(song_list,targ,buffs,spell_recasts,recasts,JA_WS_lock,recast)

-- Force refresh AoE songs once when requested
if _force_refresh and (targ == 'AoE' or targ == 'party' or (type(targ) == 'string' and targ:lower():find('aoe')) or type(targ) == 'table') then
_force_refresh_index = _force_refresh_index or 1
local desired = math.min(#song_list, get.maxsongs(targ, buffs) or #song_list)
local name = song_list[_force_refresh_index]
local song = get.song_by_name(name)
if song and spell_recasts[song.id] == 0 then
cast.MA(song.enl, '<me>')
_force_refresh_index = _force_refresh_index + 1
if _force_refresh_index > desired then
_force_refresh = false
_force_refresh_index = 1
windower.add_to_chat(207, '[Singer] Force refresh complete.')
end
return true
else
-- If spell not ready, don't block normal logic; next tick will try again.
end
end
local maxsongs = get.maxsongs(targ,buffs)
local currsongs = timers[targ] and table.length(timers[targ]) or 0
local basesongs = get.base_songs
Expand All @@ -35,10 +55,19 @@ function cast.check_song(song_list,targ,buffs,spell_recasts,recasts,JA_WS_lock,r
os.time() - timers[targ][song.enl].ts + recast > 0 or
(buffs.troubadour and not timers[targ][song.enl].nt) or
(buffs['soul voice'] and not timers[targ][song.enl].sv)) then

if ta == '<me>' and settings.nightingale and not JA_WS_lock and not buffs.nightingale and recasts[109] <= 0 and recasts[110] <= 0 then

if ta == '<me>' and settings.ccsv and not JA_WS_lock and not buffs['Clarion Call'] and recasts[254] <= 0 and recasts[0] <= 0 then
cast.JA('input /ja \"Clarion Call\" <me>')
elseif ta == '<me>' and settings.ccsv and not JA_WS_lock and not buffs['Soul Voice'] and recasts[0] <= 0 then
for targ, songs in pairs(timers) do
for song in pairs(songs) do
timers[targ][song].sv = false
end
end
cast.JA('input /ja \"Soul Voice \" <me>')
elseif ta == '<me>' and settings.nitro and not JA_WS_lock and not buffs.nightingale and recasts[109] <= 0 and recasts[110] <= 0 then
cast.JA('input /ja "Nightingale" <me>')
elseif ta == '<me>' and settings.troubadour and not JA_WS_lock and not buffs.troubadour and recasts[110] <= 0 then
elseif ta == '<me>' and settings.nitro and not JA_WS_lock and not buffs.troubadour and recasts[110] <= 0 then
for targ, songs in pairs(timers) do
for song in pairs(songs) do
timers[targ][song].nt = false
Expand Down
6 changes: 5 additions & 1 deletion Singer/sing_get.lua
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,11 @@ local equippable_bags = {
'Wardrobe',
'Wardrobe2',
'Wardrobe3',
'Wardrobe4'
'Wardrobe4',
'Wardrobe5',
'Wardrobe6',
'Wardrobe7',
'Wardrobe8'
}

local extra_song_harp = {
Expand Down
Loading