Gearswap Support Thread

Eorzea Time
 
 
 
Langues: JP EN FR DE
Ffxivpro Yellow Box
2689 users online
Forum » Windower » Support » Gearswap Support Thread
Gearswap Support Thread
First Page 2 3 ... 189 190
Offline
Posts: 1430
By DaneBlood 2026-03-15 23:29:05
Link | Citer | R
 
im trying to fix my fastcast for WHM since it drops to much HP for me

sets.fastcast={
main={ name="Grioavolr", augments={'"Fast Cast"+7',}},
sub="Clerisy Strap",
ammo="Impatiens",
head="Ebers Cap +3",
body={ name="Inyanga Jubbah +2", priority=0},
hands={ name="Fanatic Gloves", augments={'MP+50','Healing magic skill +10','"Conserve MP"+7','"Fast Cast"+7',}},
legs="Pinga Pants",
feet={ name="Telchine Pigaches", augments={'"Fast Cast"+5','HP+50',}},
neck={ name="Clr. Torque +2", augments={'Path: A',}},
waist="Witful Belt",
left_ear={ name="Etiolation Earring", priority=50},
right_ear="Malignance Earring",
left_ring={ name="Gelatinous Ring +1", priority=150},
right_ring="Lebeche Ring",
back="Perimede Cape",

THe above set puts me at 2318
but i always seme to drop to 2191 as i cast a spell

my cure sets has 2315 HP in it
and my idle set gas 2353

but adding in the priories for gelantinues ring did notthing in diffrence HP wise
then i added priorty on ear slots with 50hp and that did no change either.

am i doing the priorities wrong and is there a way to set the order its getting equiped with gearswpa ?


-- edit --
oopsie it looks like the drop comes when im switching into the idle set.

I just disabled the fast cast and tried to look for timmings and it looks to be my idle set i need to fix

-- edit 2 --
Yup re-enabled my fastcast set and disabled my idle set and it did not drop that low

oh well
Online
By Dodik 2026-03-16 10:51:32
Link | Citer | R
 
It's transitions that drop HP, not sets themselves.

Idle -> precast -> midcast -> idle.

One or more of those transitions drop HP from one set to the other. If you have HP+% items anywhere, those should be swapped first (high priority number). Then any static HP+ items.
necroskull Necro Bump Detected! [69 days between previous and next post]
Offline
By LightningHelix 2026-05-24 17:30:56
Link | Citer | R
 
I am using mote's libs and trying to make an aftercast set for Boost to put Ask Sash in the waist slot immediately. The motivation here is that it goes to my idle set, which does not have Ask Sash in it, very briefly before it checks job_buff_change(buff, gain), and I'm losing a tick of Regain. (This has been a known issue people posted about, I'm an idiot, etc.) I'm failing miserably.

I tried to overkill it with multiple DISTINCT things I thought might work:
Code
sets.buff.Boost = {waist="Ask Sash"}
sets.midcast['Boost'] = sets.buff.Boost --this works fine
sets.aftercast['Boost'] = sets.buff.Boost --this does not, see below
sets.aftercast.JA.Boost = sets.buff.Boost --this does not, see below

function job_aftercast(spell, action, spellMap, eventArgs)
    windower.add_to_chat(216, 'inside aftercast')
   
    if spell.english == "Boost" then
        windower.add_to_chat(216, 'boost set?')
        equip(sets.buff.Boost)
        return true
    else
        --otherwise, do nothing
    end

end

The "return true" in job_aftercast is because, per the comments in mote's gearswaps files, "Return true if we handled the aftercast work. Otherwise it will fall back to the general aftercast() code in Mote-Include." and I do NOT want to equip generic sets.idle! That function looks to call handle_actions(spell, 'aftercast')... which then messes around in the _G namespace and I'm too stupid to figure it out from there.

The two aftercast sets prevent the file from even loading because it complains about the general existence of sets.aftercast - this is not surprising to me because I've never used one in my life before!
Quote:
GearSwap has detected an error in the user function get_sets:
...Windower/addons/gearswap/data/Joespreadsheet/MNK.lua:264: attempt to index field 'aftercast' (a nil value)
I'm certainly not going to create a blank aftercast set if I can avoid it, because that seems like it could break something else.

The job_aftercast is correctly being called enough to write my add-to-chat debug statements, but debug mode shows that it's not actually equipping the set that I expect even for a moment, nor bypassing the regular idle set:

(ignore the bits about not having the Gloves, they're on Coelestrox today)

It is neither
-trying to equip sets.buff.Boost
-not trying to equip the default sets.idle

so I assume I've done something horribly wrong. Any help would be much appreciated, I assume this is a one-liner but I cannot figure out the one line!
 Bismarck.Radec
Offline
Serveur: Bismarck
Game: FFXI
User: Radec
Posts: 218
By Bismarck.Radec 2026-05-24 18:02:25
Link | Citer | R
 
Rather than actually returning true, try setting 'eventArgs.handled' to true before you return, like so:
Code
function job_aftercast(spell, action, spellMap, eventArgs)
    windower.add_to_chat(216, 'inside aftercast')
   
    if spell.english == "Boost" then
        windower.add_to_chat(216, 'boost set?')
        equip(sets.buff.Boost)
        eventArgs.handled = true
    else
        --otherwise, do nothing
    end

end


As for why this should work, here's a snip of mote-include with the _G[ .. stuff changed to the specific function during aftercast. Hopefully it makes more sense
Code
**This starts around line 257, depending on your mote-include version**

        -- Job-specific handling of this action
        if not eventArgs.cancel and not eventArgs.handled and job_aftercast then
            job_aftercast(spell, action, spellMap, eventArgs) **** Your function is here
            
            if eventArgs.cancel then
                cancel_spell()
            end
        end
    
        -- Default handling of this action
        if not eventArgs.cancel and not eventArgs.handled and default_aftercast then **** Because we set eventArgs.handled to true, this bit will be skipped. Right now, this is what gives you sets.idle as the post-boost set.
            default_aftercast(spell, spellMap)
            display_breadcrumbs(spell, spellMap, action)
        end
        
        -- Global post-handling of this action
        if not eventArgs.cancel and user_post_aftercast then
            user_post_aftercast(spell, action, spellMap, eventArgs) 
        end
[+]
Offline
Posts: 82
By darkwaffle 2026-05-24 18:33:58
Link | Citer | R
 
sets.aftercast is just causing errors because sets.aftercast doesn't exist when you're trying to put things into it, you can declare it with
Code
sets.aftercast = {}

but I don't think you need to do that for anything either.

I think by 'return true' it's referring to the eventArgs rather than a literal return. handle_actions appears to just check eventArgs.cancel and eventArgs.handled to determine if it should proceed with calling other functions, I don't think it's expecting any value to be returned from your job_aftercast. Otherwise I think you're on the right track, I'd try removing 'return true' and replacing it with
Code
eventArgs.handled = true


and see if that works. I think what you have written is valid, it's just still proceeding into default_aftercast afterwards and equipping, presumably, your normal idle set instead. Alternatively if you still run into problems I think you can do the exact same thing in job_post_aftercast instead - it's basically the same process and function except it's the last thing that handle_action calls so anything you choose to equip will overwrite the default set instead of vice versa.
[+]
Offline
By LightningHelix 2026-05-24 18:39:52
Link | Citer | R
 

...Well gosh dang, that's exactly what I wanted, yes!

Thank you so much! Worked like a charm and now my Ask Sash isn't vanishing for exactly long enough to lose that first Regain tick.
 Bahamut.Khelek
Offline
Serveur: Bahamut
Game: FFXI
User: Khelek
Posts: 12
By Bahamut.Khelek 2026-05-31 08:52:39
Link | Citer | R
 
I want to cancel actions in pretarget if I'm midaction, and I've tried this before. But I remember midaction used to get stuck for a really long time when I was manawalling, so I gave up on it. I believe it was mainly if I interacted with a chest?
the code I used was:
Code
function pretarget()
 if midaction() then
  cancel_spell()
  return
 end
end


I was wondering if anyone knows if midaction still locks up for really long periods, and/or if there's a fix if that's the case.
Offline
Posts: 82
By darkwaffle 2026-05-31 11:25:46
Link | Citer | R
 
I wrangled with that myself a few months ago and I don't remember my exact findings but I think the gist of it was this.

Midaction can get stuck but gearswap will resolve it itself if it is left idle for a few seconds (2-3) / you wait a few seconds before doing something to 'wake' Gearswap. However if you are button mashing then I think you can enter a state where each press will cause Gearswap to check midaction, find that not enough time has passed, it will update some sort of midaction timestamp and then the process repeats leaving you stuck indefinitely while you are rapidly pressing buttons.

I found the cause of this that I could recreate (I assume it could also occur due to dropped packets never telling you that you completed an action or something like that) was generally casting spell X, letting it complete and then trying to start casting spell Y before the 'global cooldown' had passed and then continuing to quickly press the spell Y button. X completes, Y starts (or rather Gearswap thinks Y starts), Gearswap sets midaction = true, server says you can't do it yet and I don't think Gearswap handles that information to unset midaction.

The workaround I put in place for this was to setup an incoming chunk listener for for 'Unable to cast/use' messages. When I receive one I record the time and then during precast handling before I check midaction I first check this timestamp. Anytime I've received an 'unable to do thing' message within the last two seconds I manually set midaction to false before proceeding with everything else.

As far as I know it's been working well although even prior to putting this in place I never really had a problem with it, my friend is using my library though and can't not button mash which is what uncovered this particular scenario at least lol.

Precast logic
Code
	-- The client has received an 'unable to cast/use' message. This can sometimes lead to invalid midaction() responses.
	-- If the message we received within the last two seconds then set midaction = false. 
	-- This is a 'failsafe' to try to prevent users getting 'stuck' behind midaction termination.
	if STATE_UNABLE_TO_CAST_TIMESTAMP and os.clock() - STATE_UNABLE_TO_CAST_TIMESTAMP <= 2 then
		midaction(false)
	end


Listener setup
Code
function RegisterOnChunk()
	LIBRARY_PACKETS = require "packets"
	RegisterWindowerEvent("incoming chunk", OnChunk)
end

function OnChunk(id, original, modified, injected, blocked)
	if id == 0x029 then

		local MessagePacket = LIBRARY_PACKETS.parse('incoming', original)
		local Message = MessagePacket["Message"]

		-- Collection of messages that indicate the character attempted to perform an action but was unable due to the 'global cooldown'
		local UnableToActionMessages =
		{
			[17] = true, 	-- Spell
			[18] = true, 	-- Spell
			[55] = true, 	-- Item
			[56] = true, 	-- Item
			[87] = true, 	-- JA
			[88] = true, 	-- JA
			[89] = true, 	-- WS
			[90] = true		-- WS
		}

		if UnableToActionMessages[Message] then
			STATE_UNABLE_TO_CAST_TIMESTAMP = os.clock()
		end
	end
end
Offline
Posts: 15
By Ceowolf 2026-06-07 10:07:59
Link | Citer | R
 
I recently created new lua's and have been getting the following error in game: Lua runtime error: gearswap/equip_processing.lua:62:attempt to index field '?' (a nil value).

The error occurs sporadically and I can't figure out why. All gear appears to swap when it is supposed to and debug mode does not point to anything. I used Co-pilot to write the lua and it has been unsuccessful in fixing this issue. I have 4 other job files that are similar and also experience the error.

I have been experiencing a lot of game crashes that may or may not be related to this error so any help would be greatly appreciated.

First post and sorry for length or formatting.

Runfencer Lua
-----------------------------------------
-- RUN.lua
-- Modernized for Mote-Include + Global-Include + TH support
-----------------------------------------

if player.main_job ~= 'RUN' then
return
end

-----------------------------------------
-- GET SETS
-----------------------------------------

function get_sets()
include('Global-Include.lua')
mote_include_version = 2
include('Mote-Include.lua')
end

-----------------------------------------
-- JOB SETUP
-----------------------------------------

function job_setup()
include('Mote-TreasureHunter')
init_global()


-- Rune cycling
state.RuneIndex = M{
['description']='Rune',
'Ignis','Gelus','Flabra','Tellus','Sulpor','Unda','Lux','Tenebrae'
}
end

function user_setup()
state.OffenseMode:options('DD','Tank','HybridTank','MaxHasteTP')

set_macro_page(6, 33)

send_command('bind ^insert gs c rune_forward')
send_command('bind ^delete gs c rune_backward')
send_command('bind ^` gs c cast_rune')
end

function user_unload()
send_command('unbind ^insert')
send_command('unbind ^delete')
send_command('unbind ^`')
clear_global_keybinds()
end

-----------------------------------------
-- GEAR SETS
-----------------------------------------

function init_gear_sets()

---------------------------------------------------------
-- TREASURE HUNTER
---------------------------------------------------------
sets.TreasureHunter = {
head="White Rarab Cap +1",
ammo="Per. Lucky Egg",
legs={name="Herculean Trousers", augments={'Pet: "Mag.Atk.Bns."+30','Enmity-6','"Treasure Hunter"+2',}},
}

---------------------------------------------------------
-- PRECAST
---------------------------------------------------------
sets.precast = {}
sets.precast.JA = {}

sets.Enmity = {
ammo="Seeth. Bomblet +1",
head="Halitus Helm",
body="Ayanmo Corazza +2",
hands="Futhark Mitons",
legs="Zoar Subligar",
feet="CSM Boots +1",
neck="Unmoving Collar +1",
waist="Sailfi Belt +1",
left_ear="Crep. Earring",
right_ear="Cessance Earring",
left_ring="Murky Ring",
right_ring="Defending Ring",
back={ name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

sets.precast.JA['Vallation'] = set_combine(sets.Enmity, {body="Runeist Coat +2"})
sets.precast.JA['Valiance'] = sets.precast.JA['Vallation']
sets.precast.JA['Pflug'] = set_combine(sets.Enmity, {feet="Runeist Bottes"})
sets.precast.JA['Battuta'] = sets.Enmity
sets.precast.JA['Liement'] = set_combine(sets.Enmity, {body="Futhark Coat" })
sets.precast.JA['Gambit'] = set_combine(sets.Enmity, {hands="Runeist Mitons +1" })
sets.precast.JA['Rayke'] = set_combine(sets.Enmity, {feet="Futhark Boots" })
sets.precast.JA['Swordplay'] = set_combine(sets.Enmity, {hands="Futhark Mitons" })
sets.precast.JA['One For All'] = sets.Enmity
sets.precast.JA['Elemental Sforzo'] = set_combine(sets.Enmity, {body="Futhark Coat" })

sets.precast.JA['Vivacious Pulse'] = sets.Enmity
sets.precast.JA['Lunge'] = sets.Enmity
sets.precast.JA['Swipe'] = sets.precast.JA['Lunge']

sets.precast.FC = {
ammo="Seeth. Bomblet +1",
head="Rune. Bandeau +2",
body={name="Adhemar Jacket +1", augments={'STR+12','DEX+12','Attack+20',}},
hands="CSM Gloves +1",
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Melic Torque",
waist="Sailfi Belt +1",
left_ear="Loquac. Earring",
right_ear="Enchntr. Earring +1",
left_ring="Murky Ring",
right_ring="Ayanmo Ring",
back={ name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

sets.precast.FC['Enhancing Magic'] = set_combine(sets.precast.FC, {
head="Rune. Bandeau +2",
legs="Futhark Trousers",
})

---------------------------------------------------------
-- WEAPONSKILL
---------------------------------------------------------
sets.precast.WS = {
ammo="Seeth. Bomblet +1",
head="Halitus Helm",
body={name="Adhemar Jacket +1", augments={'STR+12','DEX+12','Attack+20',}},
hands="CSM Gloves +1",
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Rep. Plat. Medal",
waist="Sailfi Belt +1",
left_ear="Crep. Earring",
right_ear="Cessance Earring",
left_ring="Rufescent Ring",
right_ring="Sroda Ring",
back={name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

---------------------------------------------------------
-- ENGAGED SETS
---------------------------------------------------------
sets.engaged = {}

sets.engaged.DD = {
ammo="Seeth. Bomblet +1",
head="Rune. Bandeau +2",
body={name="Adhemar Jacket +1", augments={'STR+12','DEX+12','Attack+20',}},
hands={name="Herculean Gloves", augments={'Accuracy+15','"Conserve MP"+3','Accuracy+13 Attack+13','Mag. Acc.+16 "Mag.Atk.Bns."+16',}},
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Lissome Necklace",
waist="Sailfi Belt +1",
left_ear="Crep. Earring",
right_ear="Cessance Earring",
left_ring="Chirich Ring",
right_ring="Moonbeam Ring",
back={name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

sets.engaged.Tank = set_combine(sets.engaged.DD, {
left_ring="Murky Ring",
right_ring="Defending Ring",
})

sets.engaged.HybridTank = set_combine(sets.engaged.Tank, {})

sets.engaged.MaxHasteTP = set_combine(sets.engaged.DD, {})

---------------------------------------------------------
-- MIDCAST
---------------------------------------------------------
sets.midcast = {}

sets.midcast['Enhancing Magic'] = {
ammo="Seeth. Bomblet +1",
head="Rune. Bandeau +2",
body={name="Adhemar Jacket +1", augments={'STR+12','DEX+12','Attack+20',}},
hands="CSM Gloves +1",
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Melic Torque",
waist="Sailfi Belt +1",
left_ear="Loquac. Earring",
right_ear="Enchntr. Earring +1",
left_ring="Murky Ring",
right_ring="Ayanmo Ring",
back={ name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}
sets.midcast.Phalanx = sets.midcast['Enhancing Magic']
sets.midcast['Divine Magic'] = sets.Enmity
sets.midcast.Flash = sets.Enmity
sets.midcast.Foil = sets.Enmity
sets.midcast.Crusade = sets.Enmity
sets.midcast.Embolden = {}

---------------------------------------------------------
-- IDLE
---------------------------------------------------------
sets.idle = {
ammo="Homiliary",
head="Rune. Bandeau +2",
body="Runeist Coat +2",
hands="CSM Gloves +1",
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Elite Royal Collar",
waist="Sailfi Belt +1",
left_ear="Crep. Earring",
right_ear="Cessance Earring",
left_ring="Murky Ring",
right_ring="Shneddick Ring",
back={name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

sets.idle.Town = set_combine(sets.idle, {})
sets.idle.LatentRefresh = {}

---------------------------------------------------------
-- DEFENSE (F10/F11)
---------------------------------------------------------
sets.defense = {}

sets.defense.PDT = {
ammo="Crepuscular Pebble",
head="Rune. Bandeau +2",
body="Ayanmo Corazza +2",
hands="CSM Gloves +1",
legs="Aya. Cosciales +2",
feet="CSM Boots +1",
neck="Elite Royal Collar",
waist="Sailfi Belt +1",
left_ear="Crep. Earring",
right_ear="Cessance Earring",
left_ring="Murky Ring",
right_ring="Defending Ring",
back={name="Ogma's Cape", augments={'DEX+20','Accuracy+20 Attack+20','DEX+10','"Dbl.Atk."+10','Damage taken-5%'}},
}

sets.defense.MDT = set_combine(sets.defense.PDT, {
})

---------------------------------------------------------
-- OTHER
---------------------------------------------------------
sets.Kiting = {right_ring="Shneddick Ring" }
info.tagged_mobs = T{}
end

-----------------------------------------
-- JOB LOGIC (Mote-native)
-----------------------------------------

function job_aftercast(spell, action, spellMap, eventArgs)
if player and player.status and player.status ~= '' then
handle_equipping_gear(player.status)
end
end

function job_buff_change(buff, gain)
if type(global_buff_change) == 'function' then
global_buff_change(buff, gain)
end
end


function job_post_midcast(spell, action, spellMap, eventArgs)
if spell.skill == 'Enhancing Magic' and buffactive['Embolden'] and sets.midcast.Embolden then
equip(sets.midcast.Embolden)
end
end
-----------------------------------------
-- RUNE CYCLING
-----------------------------------------

function job_self_command(cmdParams, eventArgs)
local cmd = cmdParams[1]

if cmd == 'rune_forward' then
state.RuneIndex:cycle()
add_to_chat(122, 'Rune: '..state.RuneIndex.value)
return
end

if cmd == 'rune_backward' then
state.RuneIndex:cycleback()
add_to_chat(122, 'Rune: '..state.RuneIndex.value)
return
end

if cmd == 'cast_rune' then
send_command('input /ja "'..state.RuneIndex.value..'" <me>')
return
end

if type(global_self_command) == 'function' then
global_self_command(cmd, cmdParams)
end
end


-----------------------------------------
-- CUSTOMIZATION
-----------------------------------------
function customize_idle_set(idleSet)
idleSet = customize_global_idle_set(idleSet)
return idleSet
end

function customize_melee_set(meleeSet)
return meleeSet
end

Global-Include.lua
-----------------------------------------
-- Global-Include.lua
-- Shared logic for all jobs
-----------------------------------------

-- Job Keybind Action
-- ALL JOBS F9 Cycle Offense Mode
-- ALL JOBS F10 Emergency PDT
-- F11 Emergency MDT
-- Ctrl + F12 Cancel Emergency PDT/MDT
-- Ctrl + t Treasure Mode cycle
-- Ctrl + W Warp Ring
-- F12 Update gear
-- RUN Ctrl + Inser Cycle runes Forward
-- RUN Ctrl + Delete Cycle Runes Backward
-- RUN Ctrl + ` Cast Rune
-- BLU Ctrl + L Toggle Learning Mode
-- BLU ` Casts Sudden Lunge
-- BLM Ctrl + M Toggle Magic Burst
-- BLM WIN + W Toggle Weapon Lock
-- DRK — No job‑specific binds
-- PUP WIN + P Cycle Pet Mode

-----------------------------------------
-- Global-Include.lua
-- Shared logic for all jobs (Mote-compatible)
-----------------------------------------

-----------------------------------------
-- GLOBAL STATE SETUP
-----------------------------------------

function init_global_states()
-- Only custom toggles (Mote owns Offense/Defense/Idle/Treasure)
state.Kiting = M(false, 'Kiting')
end

-----------------------------------------
-- GLOBAL KEYBINDS
-----------------------------------------

function init_global_keybinds()
-- Warp Ring
send_command('bind ^w gs c warp')

-- Kiting toggle
send_command('bind ^k gs c kiting')
send_command('bind ^t gs c cycle TreasureMode')
end

function clear_global_keybinds()
send_command('unbind ^w')
send_command('unbind ^k')
send_command('unbind ^t')
end

-----------------------------------------
-- GLOBAL SELF COMMANDS
-----------------------------------------

function global_self_command(cmd, cmdParams)
local command = cmd

-----------------------------------------------------
-- Warp Ring
-----------------------------------------------------
if command == 'warp' then
add_to_chat(122, 'Warp Ring activated.')
send_command('input /equip ring2 "Warp Ring"; wait 11; input /item "Warp Ring" <me>')
return
end

-----------------------------------------------------
-- Kiting toggle
-----------------------------------------------------
if command == 'kiting' then
state.Kiting:toggle()
add_to_chat(122, 'Kiting: '..tostring(state.Kiting.value))
return
end
end

-----------------------------------------
-- GLOBAL BUFF HANDLING
-----------------------------------------

function global_buff_change(buff, gain)
if type(buff) ~= 'string' then
return
end

if buff == 'Silence' and gain then
local has_echo =
(player and player.inventory and player.inventory['Echo Drops']) or
(player and player.wardrobe and player.wardrobe['Echo Drops'])

if has_echo then
send_command('input /item "Echo Drops" <me>')
end
end
end

-----------------------------------------
-- GLOBAL IDLE LOGIC
-----------------------------------------

function customize_global_idle_set(idleSet)
if player and player.mpp and player.mpp < 51 and sets and sets.idle and sets.idle.LatentRefresh then
idleSet = set_combine(idleSet, sets.idle.LatentRefresh)
end

if state and state.Kiting and state.Kiting.value and sets and sets.Kiting then
idleSet = set_combine(idleSet, sets.Kiting)
end

return idleSet
end

-----------------------------------------
-- GLOBAL INITIALIZATION
-----------------------------------------

function init_global()
init_global_states()
init_global_keybinds()
end

-----------------------------------------
-- OPTIONAL MODE CHANGE NOTIFICATIONS
-----------------------------------------

function notify_mode_change(modeName, modeState)
add_to_chat(122, modeName..": "..modeState.value)
end
Offline
Posts: 82
By darkwaffle 2026-06-08 21:58:07
Link | Citer | R
 
Line 62 of equip_processing is
Code
return (res.items[item_id][language..'_log']:lower() == name:lower() or res.items[item_id][language]:lower() == name:lower())


Gearswap checks for the existence of res.items[item_id] in the line before this so it sounds like the lookup of the item name using the language.._log or language key is returning nil and then trying to call lower() from nil is causing the error. Have you done anything that would change the value of the 'language' variable in Gearswap or made any alterations to the resource files? Namely items.lua or the resources.lua library. It might be worth including a chat message somewhere to check the value of language if you're not sure, as far as I know only 'english' and 'japanese' are valid.
Code
windower.add_to_chat(1,"LANGUAGE= " .. language)
 Kujata.Tetsuiga
Offline
Serveur: Kujata
Game: FFXI
User: Tetsuiga
Posts: 45
By Kujata.Tetsuiga 2026-06-18 08:41:05
Link | Citer | R
 
Greetings all, having a slight issue with my sch gearswap, it's a very lightly modfied Mirdain's. If im on the Unlocked weapon preset, it tries to use my fast cast set as a precast for weapon skills, thus switching staves, and killing my TP. I can't seem to figure out why or how to stop it.

Offline
Posts: 15
By Thaylia 2026-06-18 10:51:46
Link | Citer | R
 
I think your Idle weapon leaks into your sets.WS when calling "built_set".

An easy fix would be to add this:
Code
-- Augment basic equipment sets
function precast_custom(spell)
local equipSet = {}

if spell.type == "WeaponSkill" and state.WeaponMode.value == "Unlocked" then
equipSet = set_combine(equipSet, { main = player.equipment.main, sub = player.equipment.sub })
end

It makes sure to keep your current main weapon equipped when you WS.
[+]
 Kujata.Tetsuiga
Offline
Serveur: Kujata
Game: FFXI
User: Tetsuiga
Posts: 45
By Kujata.Tetsuiga 2026-06-18 12:58:51
Link | Citer | R
 
Thank you so very much !!! It was driving me insane trying to figure it out lol.
 Bahamut.Xismal
Offline
Serveur: Bahamut
Game: FFXI
User: Xismal
Posts: 1
By Bahamut.Xismal 2026-06-19 04:50:17
Link | Citer | R
 
Would appreciate some help/guidance diagnosing my gearswap issue please. Note: I am using Mirdain's lua and modified the equipment sets based on the gear I have. I am not very good at the codes.

Issue:
The weapons I defined in precast and midcast are not being swapped in; instead what I have selected as weaponmode is "locked in" when I am casting a spell. I don't want to use "Unlocked" mode as I want to specify which weaponset to use as aftercast idle and this can change depending on the situation.

Want to achieve:
Idleset (weaponset selected here) > Precast (swap in defined weapons) > Midcast (swap in defined weapons) > Aftercast (swap back to idleset with the weaponset defined at start)

My lua codes (truncated codes that are not relevant):
Start/Idle/Weaponset
Code
--Set default mode (IdleTown,RefreshDT)
state.OffenseMode:options('IdleTown', 'RefreshDT')
state.OffenseMode:set('IdleTown')

--Weapon Modes
state.WeaponMode:options('DaybreakArchduke','MalignanceDT','Unlocked')
state.WeaponMode:set('DaybreakArchduke')


function get_sets()

	-- Weapon setup
	sets.Weapons = {}

	sets.Weapons['DaybreakArchduke'] = {
		main="Daybreak",
		sub="Archduke's Shield",
	}

	sets.Weapons['MalignanceDT'] = {
		main="Malignance Pole",
		sub="Oneiros Grip",
	}

	sets.Weapons['Unlocked'] = {}

	-- Standard Idle set with -DT,Refresh,Regen and movement gear
	
	sets.Idle = {}
	
	sets.Idle.IdleTown = set_combine(sets.Idle, {
		ammo="Staunch Tathlum +1",
		head="Null Masque",
		body="Theo. Bliaut +4",
		hands="Nyame Gauntlets",
		legs="Nyame Flanchard",
		feet="Nyame Sollerets",
		neck={ name="Clr. Torque +2", augments={'Path: A',}},
		waist="Carrier's Sash",
		left_ear="Alabaster Earring",
		right_ear="Arete del Luna +1",
		left_ring="Warp Ring",
		right_ring="Shneddick Ring +1",
		back={ name="Alaunus's Cape", augments={'MND+20','Eva.+20 /Mag. Eva.+20','Mag. Evasion+10','"Fast Cast"+10','Damage taken-5%',}},
	})
	
	sets.Idle.RefreshDT = set_combine(sets.Idle, {
		ammo="Homiliary",
		head="Null Masque",
		body="Theo. Bliaut +4",
		hands="Nyame Gauntlets",
		legs="Nyame Flanchard",
		feet="Nyame Sollerets",
		neck={ name="Clr. Torque +2", augments={'Path: A',}},
		waist="Null Belt",
		left_ear="Alabaster Earring",
		right_ear="Odnowa Earring +1",
		left_ring="Murky Ring",
		right_ring="Shneddick Ring +1",
		back="Null Shawl",
	})
	


Precast
Code
	-- ===================================================================================================================
	--		sets.Precast
	-- ===================================================================================================================

	sets.Precast = {}

	-- Used for Magic Spells (Cap 80%)
	sets.Precast.FastCast = {
		main="C. Palug Hammer",
		sub="Chanter's Shield",
		ammo="Impatiens",
		head={ name="Vanya Hood", augments={'MP+50','"Fast Cast"+10','Haste+2%',}},
		body="Inyanga Jubbah +2",
		hands={ name="Gende. Gages +1", augments={'Phys. dmg. taken -4%','Magic dmg. taken -2%','"Cure" spellcasting time -5%',}},
		legs="Aya. Cosciales +2",
		feet="Regal Pumps +1",
		neck={ name="Clr. Torque +2", augments={'Path: A',}},
		waist="Witful Belt",
		left_ear="Malignance Earring",
		right_ear="Loquac. Earring",
		left_ring="Lebeche Ring",
		right_ring="Kishar Ring",
		back="Perimede Cape",
	}

	-- Used for Cure cast
	-- 3k HP, 80% Cast Speed, 25% gear haste
	sets.Precast.Cure = set_combine(sets.Precast.FastCast, {
		main={ name="Queller Rod", augments={'Healing magic skill +15','"Cure" potency +10%','"Cure" spellcasting time -7%',}},
		sub="Sors Shield",
		ammo="Impatiens",
		head={ name="Vanya Hood", augments={'MP+50','"Fast Cast"+10','Haste+2%',}},
		body="Inyanga Jubbah +2",
		hands={ name="Gende. Gages +1", augments={'Phys. dmg. taken -4%','Magic dmg. taken -2%','"Cure" spellcasting time -5%',}},
		legs="Ebers Pant. +1",
		feet={ name="Vanya Clogs", augments={'"Cure" potency +5%','"Cure" spellcasting time -15%','"Conserve MP"+6',}},
		neck={ name="Clr. Torque +2", augments={'Path: A',}},
		waist="Witful Belt",
		left_ear="Malignance Earring",
		right_ear="Mendi. Earring",
		left_ring="Lebeche Ring",
		right_ring="Kishar Ring",
		back="Perimede Cape",
	})



Midcast
Code
	-- ===================================================================================================================
	--		sets.Midcast
	-- ===================================================================================================================

	--Base set for midcast - if not defined will notify and use your idle set for surviability
	sets.Midcast = set_combine(sets.Idle, sets.Idle.RefreshDT, { })

	--This set is used as base as is overwrote by specific gear changes (Spell Interruption Rate Down)
	sets.Midcast.SIRD = {}

	-- Cure Set
	sets.Midcast.Cure = {
		main="Chatoyant Staff",
		sub="Achaq Grip",
		ammo="Pemphredo Tathlum",
		head={ name="Kaykaus Mitra +1", augments={'MP+80','MND+12','Mag. Acc.+20',}},
		body="Ebers Bliaut +1",
		hands="Theo. Mitts +4",
		legs="Ebers Pant. +1",
		feet={ name="Kaykaus Boots +1", augments={'Mag. Acc.+20','"Cure" potency +6%','"Fast Cast"+4',}},
		neck={ name="Clr. Torque +2", augments={'Path: A',}},
		waist="Gishdubar Sash",
		left_ear="Glorious Earring",
		right_ear="Mendi. Earring",
		left_ring="Murky Ring",
		right_ring="Mephitas's Ring +1",
		back={ name="Alaunus's Cape", augments={'MND+20','Eva.+20 /Mag. Eva.+20','Mag. Evasion+10','"Fast Cast"+10','Damage taken-5%',}},
    }




Aftercast (I only saw one defined for WS which I didnt modify yet)
Code
	-- ===================================================================================================================
	--		sets.aftercast
	-- ===================================================================================================================

	sets.WS = {
	    ammo="Oshasha's Treatise",
		head={ name="Nyame Helm", augments={'Path: B',}},
		body={ name="Nyame Mail", augments={'Path: B',}},
		hands={ name="Nyame Gauntlets", augments={'Path: B',}},
		legs={ name="Nyame Flanchard", augments={'Path: B',}},
		feet={ name="Nyame Sollerets", augments={'Path: B',}},
		neck="Fotia Gorget",
		waist="Fotia Belt",
		left_ear={ name="Moonshade Earring", augments={'Accuracy+4','TP Bonus +250',}},
		right_ear="Ishvara Earring",
		left_ring="Ilabrat Ring",
		right_ring="Epaminondas's Ring",
		back={ name="Alaunus's Cape", augments={'DEX+20','Accuracy+20 Attack+20','Accuracy+10','"Dbl.Atk."+10','Damage taken-5%',}},
	}


DO NOT EDIT at the end of the lua
Code
-------------------------------------------------------------------------------------------------------------------
-- DO NOT EDIT BELOW THIS LINE UNLESS YOU NEED TO MAKE JOB SPECIFIC RULES
-------------------------------------------------------------------------------------------------------------------

-- Called when the player's subjob changes.
function sub_job_change_custom(new, old)
	-- Typically used for Macro pallet changing
end

--Adjust custom precast actions
function pretarget_custom(spell,action)

end
-- Augment basic equipment sets
function precast_custom(spell)
	local equipSet = {}

	return equipSet
end
-- Augment basic equipment sets
function midcast_custom(spell)
	local equipSet = {}

	return equipSet
end
-- Augment basic equipment sets
function aftercast_custom(spell)
	local equipSet = {}
	if not buffactive['Afflatus Solace'] and not buffactive['Afflatus Misery'] then
		add_to_chat(8,'You are not in a stance')
	end
	return equipSet
end
--Function is called when the player gains or loses a buff
function buff_change_custom(name,gain)
	local equipSet = {}

	return equipSet
end
--This function is called when a update request the correct equipment set
function choose_set_custom()
	local equipSet = {}

	return equipSet
end
--Function is called when the player changes states
function status_change_custom(new,old)
	local equipSet = {}

	return equipSet
end
--Function is called when a self command is issued
function self_command_custom(command)

end
-- Function is called when the job lua is unloaded
function user_file_unload()

end

--Function used to automate Job Ability use - Checked first
function check_buff_JA()
	local buff = 'None'
	return buff
end

--Function used to automate Spell use
function check_buff_SP()
	local buff = 'None'
	return buff
end

function pet_change_custom(pet,gain)
	local equipSet = {}
	
	return equipSet
end

function pet_aftercast_custom(spell)
	local equipSet = {}

	return equipSet
end

function pet_midcast_custom(spell)
	local equipSet = {}

	return equipSet
end



Scenario example 1:
I selected "DaybreakArchduke" weaponset (for refresh+idle).

When I cast a spell say "Cure" for example,
a. Precast- I am expecting it to swap to Queller Rod but it is locked in Daybreak+Archduke (granted this is instantaneous and I might not see it). -FAIL
b. Midcast- I am expecting it to swap to Chatoyant Staff just as the spell lands but it is locked in Daybreak+Archduke. -FAIL
c. Aftercast- I am expecting it to swap to Daybreak+Archduke but since the above is locked all the while, I cannot discern. -CANT TELL


Scenario example 2:
I selected "Unlocked" weaponset (but equipped Daybreak+Archduke for refresh+idle).

When I cast a spell say "Cure" for example,
a. Precast- I am expecting it to swaps to Queller Rod and it swaps to Queller Rod (granted this is instantaneous and I might not see it). -SUCCESS
b. Midcast- I am expecting it to swap to Chatoyant Staff just as the spell lands and it swaps Chatoyant Staff. -SUCCESS
c. Aftercast- I am expecting it to swap to Daybreak+Archduke but it stays as Chatoyang Staff. -FAIL

What should I change or add to achieve what I am seeking?
Quote:
Want to achieve:
Idleset (weaponset selected here) > Precast (swap in defined weapons) > Midcast (swap in defined weapons) > Aftercast (swap back to idleset with the weaponset defined at start)
 Phoenix.Crevox
Offline
Serveur: Phoenix
Game: FFXI
User: Crevox
Posts: 46
By Phoenix.Crevox 2026-06-30 17:14:47
Link | Citer | R
 
Experiencing an issue with Gearswap where it's not swapping fast enough in a lot of cases, specifically with Summoner. Using a blood pact will have the lowered recast, but watching my gear in real time (either with EquipViewer or with the actual menu) it's just not swapping to the midcast set fast enough a lot of the time, and a bunch of pieces are left on from the precast or idle sets. This seems to specifically happen more in party scenarios/battle content. I saw the Packetflow addon and tried that, and thought it was helping for a while, but it's still happening very frequently. Things like Hysteric Assault will hit for 60k+, then next cast it just doesn't swap a bunch of stuff because it was too slow and it hits for 30k.

Here is my Gearswap: https://pastebin.com/ZB2xQPZm

My game also seems more laggy lately in general (frame rate). I usually could maintain 60 FPS in a lot of cases but even running through some regular areas will cause it drop frames. I can't tell if this is just how the game is or if something is wrong with my game, or I'm running some laggy addons or something. Any way to poll those? My computer is a monster so it's not down to computer parts (Ryzen, 5090, etc). I'm using dgVoodoo and large address aware. Any known addons or configuration settings that would cause lag like this?

Quote:
What should I change or add to achieve what I am seeking?

This post is 11 days old but...

You should use the command "gs showswaps" and "gs debugmode" to see what it's doing in the Windower console. It will output to chat what sets it's trying to equip and what items it's equipping. This way you don't have to look so closely at your equipment and can see what it's trying to do.

He's using custom idle sets so make sure you have an idle set with your F9-F12 keys. You can also just put the idle set you want to use in sets.idle instead. Without seeing the entire lua since you split it up, I can't really debug further.
 Bismarck.Radec
Offline
Serveur: Bismarck
Game: FFXI
User: Radec
Posts: 218
By Bismarck.Radec 2026-06-30 17:56:46
Link | Citer | R
 
Phoenix.Crevox said: »
SMN Things

This isn't a recent thing, but pet-midcast has always been iffy if it works. The fix for this is generally moving pet-midcast gear to the aftercast of the related JA, something like so:
Code
function job_aftercast(spell, action, spellMap, eventArgs)
	--Equip the pet-enhancing gear right after you use the pact JA
	if type(spell.type) == 'string' and spell.type:startswith('BloodPact') then
		equip(get_pet_midcast_set(spell, spellMap))
		eventArgs.handled = true
	end
end

function job_pet_midcast(spell, action, spellMap, eventArgs)
	--Don't do anything during pet midcast
	eventArgs.handled = true
end

function job_pet_aftercast(spell, action, spellMap, eventArgs)
	--Return to Idle, Engaged, etc as needed.
	handle_equipping_gear(player.status)
end

-----------------------
Bahamut.Xismal said: »
What should I change or add to achieve what I am seeking?

You're misunderstanding the purpose of a weapon mode - it's the weapons you want to equip always so you don't lose TP, not the set to return to when idle.
What you're looking to achieve is better considered an idle mode - weapons to return to when not doing anything else.

Mirdain files looks like they combine this with "OffenseMode" rather than a dedicated "IdleMode". With the obvious caveat that this will also affect your ability to specify a TP set, try adding an offensemode to support what you're after.
Code
--Set default mode (IdleTown,RefreshDT)
state.OffenseMode:options('IdleTown', 'RefreshDT', 'DaybreakArchduke')
state.OffenseMode:set('IdleTown')

--Weapon Modes
state.WeaponMode:options('Naegling','Unlocked')
state.WeaponMode:set('Unlocked')

--What you might use a Weapon set for
sets.Weapons['Naegling'] = {
	main="Naegling",
	sub="Genmei Shield",
}

sets.Idle['DaybreakArchduke'] = {
	main="Daybreak",
	sub="Archduke's Shield",
}


The relevant include section that handles this:
Code
Starting at line 3186 of https://github.com/Mirdain/Gearswap/blob/master/Mirdain-Include.lua
....
if sets.Idle then
	built_set = sets.Idle

	-- Idle state
	if sets.Idle[state.OffenseMode.value] then
		built_set = set_combine(built_set, sets.Idle[state.OffenseMode.value])
	else warn('sets.Idle.'..state.OffenseMode.value..' not found!') end	
....
[+]
 Phoenix.Crevox
Offline
Serveur: Phoenix
Game: FFXI
User: Crevox
Posts: 46
By Phoenix.Crevox 2026-07-01 12:23:39
Link | Citer | R
 
Bismarck.Radec said: »
This isn't a recent thing, but pet-midcast has always been iffy if it works. The fix for this is generally moving pet-midcast gear to the aftercast of the related JA, something like so:

Holy cow, this is so much better so far. Thank you for the help, I'm so glad I posted to ask.
[+]
Offline
Posts: 15
By Ceowolf 2026-07-07 20:54:55
Link | Citer | R
 
Hi all - what would cause gearswap to give the following error while tabbing targets in town? "Gearswap: lua runtime error: Gearswap/equip_processing.lua:62:attempt to index field '?' (a nil value)".

I will get the error while running through town and tabbing from target to target after 2-4 mins. Debug and Showswaps mode indicate no gear is changing and pretty much nothing is happening. The error also pops in combat from time to time. I think identifying why it happens in town might help me resolve it. I have not changed any standard Gearswap files and recently reinstalled it and windower.

My lua that will generate the error quickest is below.

Thanks for the help.
 Bismarck.Radec
Offline
Serveur: Bismarck
Game: FFXI
User: Radec
Posts: 218
By Bismarck.Radec 2026-07-07 22:31:03
Link | Citer | R
 
I'm not sure how you're triggering this, but my money is on that this is caused for you by your fastcast set ammo being "Seething Bomblet +1" instead of "Seeth. Bomblet +1"

More in depth:

Edit, there's a redirect in place that changes "english_log" to "enl", so none of this is correct. Not sure what's causing it, good luck. Try forcing a resources update.
Offline
Posts: 15
By Ceowolf 2026-07-08 18:01:12
Link | Citer | R
 
Thanks for looking, I was excited because it sounded like an easy fix. I'll try redownloading gearswap again. I'm still not sure why this error occurs in town when nothing is swapping; when I am tabbing NPC's.
 Bismarck.Radec
Offline
Serveur: Bismarck
Game: FFXI
User: Radec
Posts: 218
By Bismarck.Radec 2026-07-08 18:46:07
Link | Citer | R
 
Specifically for resources update - make sure the files in windower/res/ get updated.

Fenrir.Niflheim said: »
...

If you are not seeing the correct file in your directory, your update may have failed and got locked up.

To fix that you just need to delete the resource folder and the updates folder then launch windower.

If something blocked an update, wearing or trying to equip new gear could cause that error as well - nothing I noticed in your file, but if you had any of the new limbus weapons/grips equipped manually that could be the cause.
Offline
Posts: 15
By Ceowolf 2026-07-08 22:00:01
Link | Citer | R
 
I'll try that out tomorrow. I did some testing tonight and found that if I remove Mote-TreasureHunter, the error goes away.
Offline
Posts: 15
By Ceowolf 2026-07-09 20:27:09
Link | Citer | R
 
I removed the resource and updates folder, let Windower redownload the files and still got the error. I also tried a super simple lua with no gear equipped and got the error on my main and a mule. Not sure where to go from here.
Code
function get_sets()
end

windower.register_event('target change', function()
end)
Offline
By Shichishito 2026-08-06 23:42:45
Link | Citer | R
 
I'd like to toggle thru a list of enchantment items and use them once the enchantment timer ticked to 0 after equipping the item.
The problem is if I work with in game waits like this:
Code
send_command('wait 9;input /item "Warp Ring" <me>')

It does use the enchantment but it always executes this line. Means if I toggle down the list it would attempt to trigger several enchantments even if I only wanted the enchantment of a item at the bottom of the list.

Afaik there is no windower functionality related to enchantments so I figured if I time the delay in lua I'd get more control over when to send the command or to send it not at all.

trying to trigger the event with if statements doesn't execute the code (tested with echo)
Code
-- create time stamp variable
local equipped_item_enchantment_timestamp = 0
-- time it takes till warp ring becomes use able after equipping
local warp_ring_timer = 9

if state.EnchantmentLockMode.value == "WarpRing" then
    -- equip enchantment item and disable ring slot
    enable('ring1')
    equip(sets.WarpRing)
    disable('ring1')

    -- Take time stamp at the moment the enchantment item gets equipped
    equipped_item_enchantment_timestamp = math.floor(os.clock())

    --- if loop in hopes to trigger when condition met
    if equipped_item_enchantment_timestamp + warp_ring_timer == math.floor(os.clock()) then
        -- this echo doesn't trigger
        windower.send_command('@input /echo Warp Ring Timer = ' .. equipped_item_enchantment_timestamp .. '')
        send_command('/item "Warp Ring" <me>')
    end
end

and using while do or repeat until loops instead of if then it causes the game to freeze or crash.
Code
repeat 
    windower.send_command('@input /echo Hoxne Ampulla Timer = ' .. equipped_item_enchantment_timestamp .. '')
    send_command('/item "Hoxne Ampulla" <me>')
until equipped_item_enchantment_timestamp + hoxne_ampulla_timer == math.floor(os.clock())
 Fenrir.Brimstonefox
Offline
Serveur: Fenrir
Game: FFXI
User: Brimstone
Posts: 488
By Fenrir.Brimstonefox 2026-08-07 08:10:36
Link | Citer | R
 
Lua is mostly event based functions in gearswap, meaning something has to happen to trigger the code, which is why the first does nothing.

The 2nd I assume is overloading something (probably sending millions of commands per second).

I would probably just:
between equip and use (you could also put this in the loop to control it, fractional seconds will work):
Code
coroutine.sleep(9)


could try this too (found it when googling the above, haven't tested)
Code
coroutine.schedule(function()
    send_command('/item "Warp Ring" <me>')
end, 9)


Edit: 1 second is an eternity in computer time (let alone 9) I do not know how either of these would work wrt locking the current event vs operating other functions.
[+]
 Asura.Lunafreya
Offline
Serveur: Asura
Game: FFXI
User: Lunafreya
Posts: 870
By Asura.Lunafreya 2026-08-12 14:02:50
Link | Citer | R
 
I've had this problem in my COR lua for as long as I can remember...it's from Arislan.

When I /ra, more often than not I will visually aim my weapon and before the ranged attack actually goes it, I will get interrupted saying "you do not have an appropriate ranged weapon equipped". If I re-attempt to /ra after that it works fine....and then again the same issue.

I use equipviewer and do not see my ranged/ammo slots changing at all so I can't quite pinpoint what is going wrong here.
Code
-- Original: Motenten / Modified: Arislan

-------------------------------------------------------------------------------------------------------------------
--  Keybinds
-------------------------------------------------------------------------------------------------------------------

--  Modes:      [ F9 ]              Cycle Offense Modes
--              [ CTRL+F9 ]         Cycle Hybrid Modes
--              [ ALT+F9 ]          Cycle Ranged Modes
--              [ WIN+F9 ]          Cycle Weapon Skill Modes
--              [ F10 ]             Emergency -PDT Mode
--              [ ALT+F10 ]         Toggle Kiting Mode
--              [ F11 ]             Emergency -MDT Mode
--              [ F12 ]             Update Current Gear / Report Current Status
--              [ CTRL+F12 ]        Cycle Idle Modes
--              [ ALT+F12 ]         Cancel Emergency -PDT/-MDT Mode
--              [ WIN+C ]           Toggle Capacity Points Mode
--              [ WIN+` ]           Toggle use of Luzaf Ring.
--              [ WIN+Q ]           Quick Draw shot mode selector.
--
--  Abilities:  [ CTRL+- ]          Quick Draw primary shot element cycle forward.
--              [ CTRL+= ]          Quick Draw primary shot element cycle backward.
--              [ ALT+- ]           Quick Draw secondary shot element cycle forward.
--              [ ALT+= ]           Quick Draw secondary shot element cycle backward.
--              [ CTRL+[ ]          Quick Draw toggle target type.
--              [ CTRL+] ]          Quick Draw toggle use secondary shot.
--
--              [ CTRL+C ]          Crooked Cards
--              [ CTRL+` ]          Double-Up
--              [ CTRL+X ]          Fold
--              [ CTRL+S ]          Snake Eye
--              [ CTRL+NumLock ]    Triple Shot
--              [ CTRL+Numpad/ ]    Berserk
--              [ CTRL+Numpad* ]    Warcry
--              [ CTRL+Numpad- ]    Aggressor
--
--  Spells:     [ WIN+, ]           Utsusemi: Ichi
--              [ WIN+. ]           Utsusemi: Ni
--
--  Weapons:    [ CTRL+G ]          Cycles between available ranged weapons
--              [ CTRL+W ]          Toggle Ranged Weapon Lock
--
--  WS:         [ CTRL+Numpad7 ]    Savage Blade
--              [ CTRL+Numpad8 ]    Last Stand
--              [ CTRL+Numpad4 ]    Leaden Salute
--              [ CTRL+Numpad6 ]    Wildfire
--              [ CTRL+Numpad1 ]    Requiescat
--
--  RA:         [ Numpad0 ]         Ranged Attack
--
--
--              (Global-Binds.lua contains additional non-job-related keybinds)


-------------------------------------------------------------------------------------------------------------------
--  Custom Commands (preface with /console to use these in macros)
-------------------------------------------------------------------------------------------------------------------
    
--  gs c qd                         Uses the currently configured shot on the target, with either <t> or
--                                  <stnpc> depending on setting.
--  gs c qd t                       Uses the currently configured shot on the target, but forces use of <t>.
--
--  gs c cycle mainqd               Cycles through the available steps to use as the primary shot when using
--                                  one of the above commands.
--  gs c cycle altqd                Cycles through the available steps to use for alternating with the
--                                  configured main shot.
--  gs c toggle usealtqd            Toggles whether or not to use an alternate shot.
--  gs c toggle selectqdtarget      Toggles whether or not to use <stnpc> (as opposed to <t>) when using a shot.
--
--  gs c toggle LuzafRing           Toggles use of Luzaf Ring on and off


-------------------------------------------------------------------------------------------------------------------
-- Setup functions for this job.  Generally should not be modified.
-------------------------------------------------------------------------------------------------------------------

-- Initialization function for this job file.
function get_sets()
    mote_include_version = 2
    
    -- Load and initialize the include file.
    include('Mote-Include.lua')
end

-- Setup vars that are user-independent.  state.Buff vars initialized here will automatically be tracked.
function job_setup()
    -- QuickDraw Selector
    state.Mainqd = M{['description']='Primary Shot', 'Fire Shot', 'Ice Shot', 'Wind Shot', 'Earth Shot', 'Thunder Shot', 'Water Shot'}
    state.Altqd = M{['description']='Secondary Shot', 'Fire Shot', 'Ice Shot', 'Wind Shot', 'Earth Shot', 'Thunder Shot', 'Water Shot'}
    state.UseAltqd = M(false, 'Use Secondary Shot')
    state.SelectqdTarget = M(false, 'Select Quick Draw Target')
    state.IgnoreTargetting = M(false, 'Ignore Targetting')

    state.DualWield = M(false, 'Dual Wield III')
    state.QDMode = M{['description']='Quick Draw Mode', 'STP', 'Magic Enhance', 'Magic Attack'}

    state.Currentqd = M{['description']='Current Quick Draw', 'Main', 'Alt'}
    
    -- Whether to use Luzaf's Ring
    state.LuzafRing = M(false, "Luzaf's Ring")
    -- Whether a warning has been given for low ammo
    state.warned = M(false)

    define_roll_values()

    lockstyleset = 80

    update_offense_mode()    
    determine_haste_group()
end

-------------------------------------------------------------------------------------------------------------------
-- User setup functions for this job.  Recommend that these be overridden in a sidecar file.
-------------------------------------------------------------------------------------------------------------------

-- Setup vars that are user-dependent.  Can override this function in a sidecar file.
function user_setup()
    state.OffenseMode:options('STP', 'Normal', 'LowAcc', 'MidAcc', 'HighAcc')
    state.HybridMode:options('Normal', 'DT', 'Crit')
    state.RangedMode:options('STP', 'Normal', 'Acc', 'HighAcc', 'Critical')
    state.WeaponskillMode:options('Normal', 'Acc')
    state.CastingMode:options('Normal', 'Resistant')
    state.IdleMode:options('Normal', 'DT', 'Refresh')

    state.WeaponLock = M(false, 'Weapon Lock')    
    state.Gun = M{['description']='Current Gun', 'Death Penalty', 'Fomalhaut', 'Ataktos', 'Armageddon'}
    state.CP = M(false, "Capacity Points Mode")

    gear.RAbullet = "Devastating bullet"
    gear.WSbullet = "Devastating bullet"
    gear.MAbullet = "Living bullet"
    gear.QDbullet = "Living bullet"
    --gear.RAbullet = "Eminent bullet"
    --gear.WSbullet = "Eminent bullet"	
    --gear.MAbullet = "Eminent bullet"
    --gear.QDbullet = "Eminent bullet"	
    options.ammo_warning_limit = 10

    -- Additional local binds
    -- include('Global-Binds.lua') -- OK to remove this line
    -- include('Global-GEO-Binds.lua') -- OK to remove this line

    send_command('bind ^` input /ja "Double-up" <me>')
    send_command('bind ^c input /ja "Crooked Cards" <me>')
    send_command('bind ^s input /ja "Snake Eye" <me>')
    send_command('bind ^f input /ja "Fold" <me>')
    send_command('bind !` input /ja "Bolter\'s Roll" <me>')
    send_command ('bind @` gs c toggle LuzafRing')

    send_command('bind ^- gs c cycleback mainqd')
    send_command('bind ^= gs c cycle mainqd')
    send_command('bind !- gs c cycle altqd')
    send_command('bind != gs c cycleback altqd')
    send_command('bind ^[ gs c toggle selectqdtarget')
    send_command('bind ^] gs c toggle usealtqd')

    send_command('bind @c gs c toggle CP')
    send_command('bind @q gs c cycle QDMode')
    send_command('bind @g gs c cycle Gun')
    send_command('bind @w gs c toggle WeaponLock')

    send_command('bind ^numlock input /ja "Triple Shot" <me>')

    if player.sub_job == 'WAR' then
        send_command('bind ^numpad/ input /ja "Berserk" <me>')
        send_command('bind ^numpad* input /ja "Warcry" <me>')
        send_command('bind ^numpad- input /ja "Aggressor" <me>')
    end

    send_command('bind ^numpad7 input /ws "Savage Blade" <t>')
    send_command('bind ^numpad8 input /ws "Last Stand" <t>')
    send_command('bind ^numpad4 input /ws "Leaden Salute" <t>')
    send_command('bind ^numpad6 input /ws "Wildfire" <t>')
    send_command('bind ^numpad1 input /ws "Requiescat" <t>')
    send_command('bind ^numpad2 input /ws "Burning Blade" <t>')
    send_command('bind ^numpad3 input /ws "Flat Blade" <t>')

    send_command('bind numpad0 input /ra <t>')

    select_default_macro_book()
    set_lockstyle()
end


-- Called when this job file is unloaded (eg: job change)
function user_unload()
    send_command('unbind ^`')
    send_command('unbind ^c')
    send_command('unbind ^s')
    send_command('unbind ^f')
    send_command('unbind !`')
    send_command('unbind @`')
    send_command('unbind ^-')
    send_command('unbind ^=')
    send_command('unbind !-')
    send_command('unbind !=')
    send_command('unbind ^[')
    send_command('unbind ^]')
    send_command('unbind ^,')
    send_command('unbind @c')
    send_command('unbind @q')
    send_command('unbind @g')
    send_command('unbind @w')
    send_command('unbind ^numlock')
    send_command('unbind ^numpad/')
    send_command('unbind ^numpad*')
    send_command('unbind ^numpad-')
    send_command('unbind ^numpad8')
    send_command('unbind ^numpad4')
    send_command('unbind ^numpad6')
    send_command('unbind ^numpad1')
    send_command('unbind ^numpad2')
    send_command('unbind ^numpad3')
    send_command('unbind numpad0')

    send_command('unbind #`')
    send_command('unbind #1')
    send_command('unbind #2')
    send_command('unbind #3')
    send_command('unbind #4')
    send_command('unbind #5')
    send_command('unbind #6')
    send_command('unbind #7')
    send_command('unbind #8')
    send_command('unbind #9')
    send_command('unbind #0')
end

-- Define sets and vars used by this job file.
function init_gear_sets()



	------------------------------------------------------------------------------------------------
	------------------------------------ Augmented Gear --------------------------------------------
	------------------------------------------------------------------------------------------------
	
	Camulus = {}
	Camulus.TP = {}
	Camulus.AGIWSD = {}
	Camulus.STRWSD = {}
	Camulus.Snapshot = {}
	
	
	HerculeanFeet = {}
	HerculeanFeet.TP = {}
	HerculeanFeet.WSD = {}
	
	
	HerculeanLegs = {}
	HerculeanLegs.TP = {}
	HerculeanLegs.WSD = {}
	
	
	HerculeanHead = {}
	HerculeanHead.WSD = {}
	HerculeanHead.MAB = {}
    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Precast Sets ------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.precast.JA['Snake Eye'] = {legs="Lanun Trews +1"}
    sets.precast.JA['Wild Card'] = {feet="Lanun Bottes +3"}
    sets.precast.JA['Random Deal'] = {body="Lanun Frac +3"}

    sets.precast.CorsairRoll = {
		main="Rostam",
        head="Lanun Tricorne +1",
		body="Malignance Tabard", --8/0
        hands="Chasseur's Gants +1",
		legs="Malignance Tights",
		feet="Malignance Boots", --6/0
        neck="Regal Necklace",
		ear1="Etiolation Earring",
		ear2="Odnowa Earring +1",
        ring1="Luzaf's Ring",
		ring2="Murky Ring", --10/10
        waist="Null Belt", --4/0
		back="Camulus's Mantle"
        }

    sets.precast.CorsairRoll["Caster's Roll"] = set_combine(sets.precast.CorsairRoll, {legs="Chas. Culottes +1"})
    sets.precast.CorsairRoll["Courser's Roll"] = set_combine(sets.precast.CorsairRoll, {feet="Chass. Bottes +1"})
    sets.precast.CorsairRoll["Blitzer's Roll"] = set_combine(sets.precast.CorsairRoll, {head="Chass. Tricorne +1"})
    sets.precast.CorsairRoll["Tactician's Roll"] = set_combine(sets.precast.CorsairRoll, {body="Chasseur's Frac +1"})
    sets.precast.CorsairRoll["Allies' Roll"] = set_combine(sets.precast.CorsairRoll, {hands="Chasseur's Gants +1"})
    
    sets.precast.LuzafRing = set_combine(sets.precast.CorsairRoll, {ring1="Luzaf's Ring"})
    sets.precast.FoldDoubleBust = {hands="Lanun Gants +2"}

    sets.precast.Waltz = {
        body="Passion Jacket",
        neck="Phalaina Locket",
        ring1="Asklepian Ring",
        waist="Gishdubar Sash",
        }

    sets.precast.Waltz['Healing Waltz'] = {}
    
    sets.precast.FC = {
        head="Carmine Mask +1", --14
        body=gear.Taeon_FC_body, --9
        hands="Leyline Gloves", --8
        legs="Rawhide Trousers", --5
        feet="Carmine Greaves +1", --8
        neck="Orunmila's Torque", --5
        ear1="Loquacious Earring", --2
        ear2="Enchntr. Earring +1", --2
        ring1="Weather. Ring +1", --6(4)
        ring2="Kishar Ring", --4
        }

    sets.precast.FC.Utsusemi = set_combine(sets.precast.FC, {
        body="Passion Jacket",
        neck="Magoraga Beads",
        ring1="Lebeche Ring",
        })

    -- (10% Snapshot from JP Gifts)
    sets.precast.RA = {
		head={ name="Taeon Chapeau", augments={'Accuracy+17 Attack+17','"Snapshot"+5','"Snapshot"+5',}}, --10
		body="Oshosi Vest", --12
		hands="Carmine Fin. Ga. +1", --7
		legs="Oshosi Trousers", --10
		feet="Meg. Jam. +1", --8
		waist="Impulse Belt", --5
		back={ name="Camulus's Mantle", augments={'"Snapshot"+10',}}, --10
        } --61 from gear, 10 from JP Gifts, 71 total

    sets.precast.RA.Flurry1 = set_combine(sets.precast.RA, {
        body="Laksa. Frac +3", --0/20
        }) --47/46

    sets.precast.RA.Flurry2 = set_combine(sets.precast.RA.Flurry1, {
        waist="Yemaya Belt", --3/0
        }) --30/65


    ------------------------------------------------------------------------------------------------
    ------------------------------------- Weapon Skill Sets ----------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.precast.WS = {
		ammo=gear.RAbullet,    
		head="Nyame Helm",
		body="Nyame Mail",
		hands="Nyame Gauntlets",
		legs="Nyame Flanchard",
		feet="Nyame Sollerets",
		neck="Rep. Plat. Medal",
		waist="Fotia Belt",
		left_ear="Ishvara Earring",
		right_ear="Moonshade Earring",
		left_ring="Ephramad's Ring",
		right_ring="Regal Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
        }

    sets.precast.WS.Acc = set_combine(sets.precast.WS, {})

    sets.precast.WS['Last Stand'] = sets.precast.WS

    sets.precast.WS['Last Stand'].Acc = set_combine(sets.precast.WS['Last Stand'], {})

    sets.precast.WS['Wildfire'] = {
		ammo=gear.MAbullet,
		head={ name="Herculean Helm", augments={'"Mag.Atk.Bns."+22','Weapon skill damage +3%','INT+6','Mag. Acc.+9',}},
		body="Lanun Frac +3",
		hands="Nyame Gauntlets",
		legs="Nyame Flanchard",
		feet="Lanun Bottes +3",
		neck="Comm. Charm +1",
		waist="Eschan Stone",
		left_ear="Friomisi Earring",
		right_ear="Hecate's Earring",
		left_ring="Dingir Ring",
		right_ring="Ilabrat Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
        }

    sets.precast.WS['Leaden Salute'] = set_combine(sets.precast.WS['Wildfire'],{
		head="Pixie Hairpin +1",
		right_ring="Archon Ring",
		right_ear="Moonshade Earring",
		waist="Svelt. Gouriz +1"
		})

    sets.precast.WS['Leaden Salute'].FullTP = sets.precast.WS['Leaden Salute']
        
    sets.precast.WS['Evisceration'] = {}

    sets.precast.WS['Evisceration'].Acc = set_combine(sets.precast.WS['Evisceration'], {})

    sets.precast.WS['Savage Blade'] = {
		head="Nyame Helm",
		body="Nyame Mail",
		hands="Nyame Gauntlets",
		legs="Nyame Flanchard",
		feet="Nyame Sollerets",
		neck="Rep. Plat. Medal",
		waist="Sailfi Belt +1",
		left_ear="Ishvara Earring",
		right_ear="Moonshade Earring",
		left_ring="Ephramad's Ring",
		right_ring="Regal Ring",
		back={ name="Camulus's Mantle", augments={'STR+20','Accuracy+20 Attack+20','Weapon skill damage +10%',}},
	}
        
    sets.precast.WS['Savage Blade'].Acc = set_combine(sets.precast.WS['Savage Blade'], {})

    sets.precast.WS['Swift Blade'] = set_combine(sets.precast.WS, {})

    sets.precast.WS['Swift Blade'].Acc = set_combine(sets.precast.WS['Swift Blade'], {})

    sets.precast.WS['Requiescat'] = set_combine(sets.precast.WS['Swift Blade'], {}) --MND

    sets.precast.WS['Requiescat'].Acc = set_combine(sets.precast.WS['Requiescat'], {})

    sets.precast.WS['Aeolian Edge'] = set_combine(sets.precast.WS['Wildfire'], {})

    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Midcast Sets ------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.midcast.FastRecast = sets.precast.FC

    sets.midcast.SpellInterrupt = {
        legs="Carmine Cuisses +1", --20
        ring1="Evanescence Ring", --5
        }

    sets.midcast.Cure = {
        neck="Incanter's Torque",
        ear1="Roundel Earring",
        ear2="Mendi. Earring",
        ring1="Lebeche Ring",
        ring2="Haoma's Ring",
        waist="Bishop's Sash",
        }    

    sets.midcast.Utsusemi = sets.midcast.SpellInterrupt

    -- Occult Acumen Set
    sets.midcast['Dark Magic'] = {
        ammo=gear.QDbullet,
        head=gear.Herc_MAB_head,
        body="Mummu Jacket +2",
        hands=gear.Adhemar_B_hands,
        legs="Chas. Culottes +1",
        feet="Carmine Greaves +1",
        neck="Iskur Gorget",
        ear1="Dedition Earring",
        ear2="Telos Earring",
        ring1="Archon Ring",
        ring2="Dingir Ring",
        back=gear.COR_RA_Cape,
        waist="Oneiros Rope",        
        }

    sets.midcast.CorsairShot = {
		head={ name="Herculean Helm", augments={'"Mag.Atk.Bns."+16','Weapon skill damage +5%','DEX+10',}},
		body={ name="Lanun Frac +3", augments={'Enhances "Loaded Deck" effect',}},
		hands={ name="Carmine Fin. Ga. +1", augments={'Rng.Atk.+20','"Mag.Atk.Bns."+12','"Store TP"+6',}},
		legs={ name="Herculean Trousers", augments={'Mag. Acc.+17 "Mag.Atk.Bns."+17','Weapon skill damage +2%','MND+2','Mag. Acc.+9','"Mag.Atk.Bns."+13',}},
		feet={ name="Lanun Bottes +3", augments={'Enhances "Wild Card" effect',}},
		neck={ name="Comm. Charm +1", augments={'Path: A',}},
		waist="Eschan Stone",
		left_ear="Friomisi Earring",
		right_ear="Hecate's Earring",
		left_ring="Dingir Ring",
		right_ring="Acumen Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},        }

    sets.midcast.CorsairShot.STP = {
		head="Malignance Chapeau",
		body="Malignance Tabard",
		hands="Malignance Gloves",
		legs="Malignance Tights",
		feet="Malignance Boots",
		neck="Sanctity Necklace",
		waist="Eschan Stone",
		left_ear="Friomisi Earring",
		right_ear="Hecate's Earring",
		left_ring="Dingir Ring",
		right_ring="Ilabrat Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
	}
    sets.midcast.CorsairShot.Resistant = set_combine(sets.midcast.CorsairShot, {
		head="Malignance Chapeau",
		body="Malignance Tabard",
		hands="Malignance Gloves",
		legs="Malignance Tights",
		feet="Malignance Boots",
		neck="Sanctity Necklace",
		waist="Eschan Stone",
		left_ear="Hermetic Earring",
		right_ear="Enchntr. Earring",
		left_ring="Stikini Ring",
		right_ring="Mummu Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
        })
	
    sets.midcast.CorsairShot['Light Shot'] = sets.midcast.CorsairShot.Resistant
    sets.midcast.CorsairShot['Dark Shot'] = sets.midcast.CorsairShot.Resistant
    sets.midcast.CorsairShot.Enhance = {body="Mirke Wardecors", feet="Chass. Bottes +1"}

    -- Ranged gear
    sets.midcast.RA = {
        ammo=gear.RAbullet,    
		head="Malignance Chapeau",
		body="Malignance Tabard",
		hands="Malignance Gloves",
		legs="Malignance Tights",
		feet="Malignance Boots",
		neck="Ocachi Gorget",
		waist="Yemaya Belt",
		left_ear="Telos Earring",
		right_ear="Enervating Earring",
		left_ring="Dingir Ring",
		right_ring="Ilabrat Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Rng.Acc.+20 Rng.Atk.+20','"Store TP"+10',}},
        }

    sets.midcast.RA.Acc = set_combine(sets.midcast.RA, {})

    sets.midcast.RA.HighAcc = set_combine(sets.midcast.RA.Acc, {})

    sets.midcast.RA.STP = set_combine(sets.midcast.RA, {})


    sets.midcast.RA.Critical = --Arma AM3 No Triple Shot
	{
		head="Meghanada Visor +2",
		body="Nisroch Jerkin",
		hands="Mummu Wrists +2",
		legs="Mummu Kecks +2",
		feet="Oshosi Leggings",
		neck="Ocachi Gorget",
		waist="Kwahu Kachina Belt",
		left_ear="Telos Earring",
		right_ear="Enervating Earring",
		left_ring="Begrudging Ring",
		right_ring="Mummu Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Rng.Acc.+20 Rng.Atk.+20','"Store TP"+10',}},
	}

    sets.midcast.RA.TripleShot = { -- TripleShot no AM3
		head="Oshosi Mask",
		body="Chasseur's Frac +1",
		hands="Lanun Gants +3",
		legs="Oshosi Trousers",
		feet="Oshosi Leggings",
		neck="Marked Gorget",
		waist="Yemaya Belt",
		left_ear="Neritic Earring",
		right_ear="Enervating Earring",
		left_ring="Hajduk Ring",
		right_ring="Ilabrat Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Rng.Acc.+20 Rng.Atk.+20','"Store TP"+10',}},
        }

	sets.midcast.RA.TripleShotAM3 = { -- Arma AM3 + TripleShot Up
		head="Meghanada Visor +2",
		body="Nisroch Jerkin",
		hands="Lanun Gants +3",
		legs="Oshosi Trousers",
		feet="Oshosi Leggings",
		neck="Marked Gorget",
		waist="Kwahu Kachina Belt",
		left_ear="Telos Earring",
		right_ear="Enervating Earring",
		left_ring="Hajduk Ring",
		right_ring="Mummu Ring",
		back={ name="Camulus's Mantle", augments={'AGI+20','Rng.Acc.+20 Rng.Atk.+20','"Store TP"+10',}},
}
	


    ------------------------------------------------------------------------------------------------
    ----------------------------------------- Idle Sets --------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.resting = {}

    sets.idle = {
        head="Nyame Helm",
        body="Nyame Mail",
        hands="Nyame Gauntlets",
        legs="Carmine Cuisses +1",
        feet="Nyame Sollerets",
        neck="Bathy Choker",
        ear1="Eabani Earring",
        ear2="Odnowa Earring +1",
        ring1="Ephramad's Ring",
        ring2="Defending Ring",
        back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
        waist="Flume Belt",
        }

    sets.idle.DT = set_combine(sets.idle, {
        head="Malignance Chapeau", --5/0
        body="Malignance Tabard", --8/0
        hands="Malignance Gloves", --7/5
		legs="Malignance Tights",
        feet="Malignance Boots", --6/0
        neck="Loricate Torque +1", --6/6
        ear2="Etiolation Earring", --0/3
        ring1="Gelatinous Ring +1",
		ring2="Defending Ring", --10/10
        back="Solemnity Cape", --5/5
        waist="Flume Belt", --4/0
		--ammo="Staunch Tathlum +1"
        })

    sets.idle.Refresh = set_combine(sets.idle, {})

    sets.idle.Town = set_combine(sets.idle, {
        head="Null Masque",
        body="Nisroch Jerkin",
        hands="Regal Gloves",
        legs="Carmine Cuisses +1",
        feet="Lanun Bottes +3",
        neck="Regal Necklace",
        ear1="Telos Earring",
        ear2="Moonshade Earring",
        ring1="Dingir Ring",
        ring2="Archon Ring",
        back={ name="Camulus's Mantle", augments={'AGI+20','Mag. Acc+20 /Mag. Dmg.+20','AGI+10','Weapon skill damage +10%',}},
        waist="Liv. Bul. Pouch",
        })


    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Defense Sets ------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.defense.PDT = sets.idle.DT
    sets.defense.MDT = sets.idle.DT

    sets.Kiting = {legs="Carmine Cuisses +1"}


    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Engaged Sets ------------------------------------------
    ------------------------------------------------------------------------------------------------

    -- Variations for TP weapon and (optional) offense/defense modes.  Code will fall back on previous
    -- sets if more refined versions aren't defined.
    -- If you create a set with both offense and defense modes, the offense mode should be first.
    -- EG: sets.engaged.Dagger.Accuracy.Evasion

    sets.engaged = {
		head={ name="Adhemar Bonnet +1", augments={'STR+12','DEX+12','Attack+20',}},
		body="Adhemar Jacket +1",
		hands={ name="Adhemar Wrist. +1", augments={'STR+12','DEX+12','Attack+20',}},
		legs={ name="Samnuha Tights", augments={'STR+10','DEX+10','"Dbl.Atk."+3','"Triple Atk."+3',}},
		feet={ name="Herculean Boots", augments={'Attack+25','"Triple Atk."+3','DEX+9','Accuracy+12',}},
		neck="Ocachi Gorget",
		waist="Windbuffet Belt",
		left_ear="Telos Earring",
		right_ear="Suppanomimi",
		left_ring="Epona's Ring",
		right_ring="Petrov Ring",
		back={ name="Camulus's Mantle", augments={'DEX+20','Accuracy+20 Attack+20','Accuracy+2','"Dbl.Atk."+10','Phys. dmg. taken-10%',}},
        }

    sets.engaged.LowAcc = set_combine(sets.engaged, {})
    sets.engaged.MidAcc = set_combine(sets.engaged, {})
    sets.engaged.HighAcc = set_combine(sets.engaged, {})
    sets.engaged.STP = set_combine(sets.engaged, {})

    -- * DNC Subjob DW Trait: +15%
    -- * NIN Subjob DW Trait: +25%
    
    -- No Magic Haste (74% DW to cap)
    sets.engaged.DW = set_combine(sets.engaged, {})
    sets.engaged.DW.LowAcc  = set_combine(sets.engaged.LowAcc, {})
    sets.engaged.DW.MidAcc  = set_combine(sets.engaged.MidAcc, {})
    sets.engaged.DW.HighAcc = set_combine(sets.engaged.HighAcc, {})
    sets.engaged.DW.STP     = set_combine(sets.engaged.STP, {})

    -- 15% Magic Haste (67% DW to cap)
    sets.engaged.DW.LowHaste = set_combine(sets.engaged, {})
    sets.engaged.DW.LowAcc.LowHaste = set_combine(sets.engaged.LowAcc, {})
    sets.engaged.DW.MidAcc.LowHaste = set_combine(sets.engaged.MidAcc, {})
    sets.engaged.DW.HighAcc.LowHaste = set_combine(sets.engaged.HighAcc, {})
    sets.engaged.DW.STP.LowHaste = set_combine(sets.engaged.STP, {})

    -- 30% Magic Haste (56% DW to cap)
    sets.engaged.DW.MidHaste = set_combine(sets.engaged, {})
    sets.engaged.DW.LowAcc.MidHaste = set_combine(sets.engaged.LowAcc, {})
    sets.engaged.DW.MidAcc.MidHaste = set_combine(sets.engaged.MidAcc, {})
    sets.engaged.DW.HighAcc.MidHaste = set_combine(sets.engaged.HighAcc, {})
    sets.engaged.DW.STP.MidHaste = set_combine(sets.engaged.STP, {})

    -- 35% Magic Haste (51% DW to cap)
    sets.engaged.DW.HighHaste = set_combine(sets.engaged, {})
    sets.engaged.DW.LowAcc.HighHaste = set_combine(sets.engaged.LowAcc, {})
    sets.engaged.DW.MidAcc.HighHaste = set_combine(sets.engaged.MidAcc, {})
    sets.engaged.DW.HighAcc.HighHaste = set_combine(sets.engaged.HighAcc, {}) 
    sets.engaged.DW.STP.HighHaste = set_combine(sets.engaged.STP, {})
        
    -- 45% Magic Haste (36% DW to cap)
    sets.engaged.DW.MaxHaste = set_combine(sets.engaged, {})
    sets.engaged.DW.LowAcc.MaxHaste = set_combine(sets.engaged.LowAcc, {})
    sets.engaged.DW.MidAcc.MaxHaste = set_combine(sets.engaged.MidAcc, {})
    sets.engaged.DW.HighAcc.MaxHaste = set_combine(sets.engaged.HighAcc, {})
    sets.engaged.DW.STP.MaxHaste = set_combine(sets.engaged.STP, {})

    sets.LessDualWield = {back=gear.COR_TP_Cape}

    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Hybrid Sets -------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.engaged.Hybrid = 
	{
		legs="Malignance Tights",
		head="Malignance Chapeau",
		hands="Malignance Gloves",
		feet="Malignance Boots",
		body="Malignance Tabard",
		ring1="Epona's Ring",
		ring2="Defending Ring",
		waist="Kentarch Belt +1",
		neck="Loricate Torque +1"
	}

    sets.engaged.Crit = 
	{
		legs="Mummu Kecks +2",
		--head="Malignance Chapeau",
		hands="Mummu Wrists +2",
		--feet="Malignance Boots",
		body="Mummu Jacket +2",
		--ring1="Epona's Ring",
		--ring2="Defending Ring",
		--waist="Kentarch Belt +1",
		--neck="Loricate Torque +1"
	}


    
    sets.engaged.DT = set_combine(sets.engaged, sets.engaged.Hybrid)
    sets.engaged.LowAcc.DT = set_combine(sets.engaged.LowAcc, sets.engaged.Hybrid)
    sets.engaged.MidAcc.DT = set_combine(sets.engaged.MidAcc, sets.engaged.Hybrid)
    sets.engaged.HighAcc.DT = set_combine(sets.engaged.HighAcc, sets.engaged.Hybrid)
    sets.engaged.STP.DT = set_combine(sets.engaged.STP, sets.engaged.Hybrid)

    sets.engaged.DW.DT = set_combine(sets.engaged.DW, sets.engaged.Hybrid)
    sets.engaged.DW.LowAcc.DT = set_combine(sets.engaged.DW.LowAcc, sets.engaged.Hybrid)
    sets.engaged.DW.MidAcc.DT = set_combine(sets.engaged.DW.MidAcc, sets.engaged.Hybrid)
    sets.engaged.DW.HighAcc.DT = set_combine(sets.engaged.DW.HighAcc, sets.engaged.Hybrid)
    sets.engaged.DW.STP.DT = set_combine(sets.engaged.DW.STP, sets.engaged.Hybrid)

    sets.engaged.DW.DT.LowHaste = set_combine(sets.engaged.DW.LowHaste, sets.engaged.Hybrid)
    sets.engaged.DW.LowAcc.DT.LowHaste = set_combine(sets.engaged.DW.LowAcc.LowHaste, sets.engaged.Hybrid)
    sets.engaged.DW.MidAcc.DT.LowHaste = set_combine(sets.engaged.DW.MidAcc.LowHaste, sets.engaged.Hybrid)
    sets.engaged.DW.HighAcc.DT.LowHaste = set_combine(sets.engaged.DW.HighAcc.LowHaste, sets.engaged.Hybrid)    
    sets.engaged.DW.STP.DT.LowHaste = set_combine(sets.engaged.DW.STP.LowHaste, sets.engaged.Hybrid)

    sets.engaged.DW.DT.MidHaste = set_combine(sets.engaged.DW.MidHaste, sets.engaged.Hybrid)
    sets.engaged.DW.LowAcc.DT.MidHaste = set_combine(sets.engaged.DW.LowAcc.MidHaste, sets.engaged.Hybrid)
    sets.engaged.DW.MidAcc.DT.MidHaste = set_combine(sets.engaged.DW.MidAcc.MidHaste, sets.engaged.Hybrid)
    sets.engaged.DW.HighAcc.DT.MidHaste = set_combine(sets.engaged.DW.HighAcc.MidHaste, sets.engaged.Hybrid)    
    sets.engaged.DW.STP.DT.MidHaste = set_combine(sets.engaged.DW.STP.MidHaste, sets.engaged.Hybrid)

    sets.engaged.DW.DT.HighHaste = set_combine(sets.engaged.DW.HighHaste, sets.engaged.Hybrid)
    sets.engaged.DW.LowAcc.DT.HighHaste = set_combine(sets.engaged.DW.LowAcc.HighHaste, sets.engaged.Hybrid)
    sets.engaged.DW.MidAcc.DT.HighHaste = set_combine(sets.engaged.DW.MidAcc.HighHaste, sets.engaged.Hybrid)
    sets.engaged.DW.HighAcc.DT.HighHaste = set_combine(sets.engaged.DW.HighAcc.HighHaste, sets.engaged.Hybrid)    
    sets.engaged.DW.STP.DT.HighHaste = set_combine(sets.engaged.DW.HighHaste.STP, sets.engaged.Hybrid)

    sets.engaged.DW.DT.MaxHaste = set_combine(sets.engaged.DW.MaxHaste, sets.engaged.Hybrid)
    sets.engaged.DW.LowAcc.DT.MaxHaste = set_combine(sets.engaged.DW.LowAcc.MaxHaste, sets.engaged.Hybrid)
    sets.engaged.DW.MidAcc.DT.MaxHaste = set_combine(sets.engaged.DW.MidAcc.MaxHaste, sets.engaged.Hybrid)
    sets.engaged.DW.HighAcc.DT.MaxHaste = set_combine(sets.engaged.DW.HighAcc.MaxHaste, sets.engaged.Hybrid)    
    sets.engaged.DW.STP.DT.MaxHaste = set_combine(sets.engaged.DW.STP.MaxHaste, sets.engaged.Hybrid)



    sets.engaged.Crit = set_combine(sets.engaged, sets.engaged.Crit)
    sets.engaged.LowAcc.Crit = set_combine(sets.engaged.LowAcc, sets.engaged.Crit)
    sets.engaged.MidAcc.Crit = set_combine(sets.engaged.MidAcc, sets.engaged.Crit)
    sets.engaged.HighAcc.Crit = set_combine(sets.engaged.HighAcc, sets.engaged.Crit)
    sets.engaged.STP.Crit = set_combine(sets.engaged.STP, sets.engaged.Crit)

    sets.engaged.DW.Crit = set_combine(sets.engaged.DW, sets.engaged.Crit)
    sets.engaged.DW.LowAcc.Crit = set_combine(sets.engaged.DW.LowAcc, sets.engaged.Crit)
    sets.engaged.DW.MidAcc.Crit = set_combine(sets.engaged.DW.MidAcc, sets.engaged.Crit)
    sets.engaged.DW.HighAcc.Crit = set_combine(sets.engaged.DW.HighAcc, sets.engaged.Crit)
    sets.engaged.DW.STP.Crit = set_combine(sets.engaged.DW.STP, sets.engaged.Crit)

    sets.engaged.DW.Crit.LowHaste = set_combine(sets.engaged.DW.LowHaste, sets.engaged.Crit)
    sets.engaged.DW.LowAcc.Crit.LowHaste = set_combine(sets.engaged.DW.LowAcc.LowHaste, sets.engaged.Crit)
    sets.engaged.DW.MidAcc.Crit.LowHaste = set_combine(sets.engaged.DW.MidAcc.LowHaste, sets.engaged.Crit)
    sets.engaged.DW.HighAcc.Crit.LowHaste = set_combine(sets.engaged.DW.HighAcc.LowHaste, sets.engaged.Crit)    
    sets.engaged.DW.STP.Crit.LowHaste = set_combine(sets.engaged.DW.STP.LowHaste, sets.engaged.Crit)

    sets.engaged.DW.Crit.MidHaste = set_combine(sets.engaged.DW.MidHaste, sets.engaged.Crit)
    sets.engaged.DW.LowAcc.Crit.MidHaste = set_combine(sets.engaged.DW.LowAcc.MidHaste, sets.engaged.Crit)
    sets.engaged.DW.MidAcc.Crit.MidHaste = set_combine(sets.engaged.DW.MidAcc.MidHaste, sets.engaged.Crit)
    sets.engaged.DW.HighAcc.Crit.MidHaste = set_combine(sets.engaged.DW.HighAcc.MidHaste, sets.engaged.Crit)    
    sets.engaged.DW.STP.Crit.MidHaste = set_combine(sets.engaged.DW.STP.MidHaste, sets.engaged.Crit)

    sets.engaged.DW.Crit.HighHaste = set_combine(sets.engaged.DW.HighHaste, sets.engaged.Crit)
    sets.engaged.DW.LowAcc.Crit.HighHaste = set_combine(sets.engaged.DW.LowAcc.HighHaste, sets.engaged.Crit)
    sets.engaged.DW.MidAcc.Crit.HighHaste = set_combine(sets.engaged.DW.MidAcc.HighHaste, sets.engaged.Crit)
    sets.engaged.DW.HighAcc.Crit.HighHaste = set_combine(sets.engaged.DW.HighAcc.HighHaste, sets.engaged.Crit)    
    sets.engaged.DW.STP.Crit.HighHaste = set_combine(sets.engaged.DW.HighHaste.STP, sets.engaged.Crit)

    sets.engaged.DW.Crit.MaxHaste = set_combine(sets.engaged.DW.MaxHaste, sets.engaged.Crit)
    sets.engaged.DW.LowAcc.Crit.MaxHaste = set_combine(sets.engaged.DW.LowAcc.MaxHaste, sets.engaged.Crit)
    sets.engaged.DW.MidAcc.Crit.MaxHaste = set_combine(sets.engaged.DW.MidAcc.MaxHaste, sets.engaged.Crit)
    sets.engaged.DW.HighAcc.Crit.MaxHaste = set_combine(sets.engaged.DW.HighAcc.MaxHaste, sets.engaged.Crit)    
    sets.engaged.DW.STP.Crit.MaxHaste = set_combine(sets.engaged.DW.STP.MaxHaste, sets.engaged.Crit)



    ------------------------------------------------------------------------------------------------
    ---------------------------------------- Special Sets ------------------------------------------
    ------------------------------------------------------------------------------------------------

    sets.buff.Doom = {ring1="Eshmun's Ring", ring2="Eshmun's Ring", waist="Gishdubar Sash"}

    sets.Obi = {waist="Hachirin-no-Obi"}
    sets.CP = {back="Aptitude Mantle"}
    sets.Reive = {neck="Ygnas's Resolve +1"}

end


-------------------------------------------------------------------------------------------------------------------
-- Job-specific hooks for standard casting events.
-------------------------------------------------------------------------------------------------------------------

-- Set eventArgs.handled to true if we don't want any automatic gear equipping to be done.
-- Set eventArgs.useMidcastGear to true if we want midcast gear equipped on precast.
function job_precast(spell, action, spellMap, eventArgs)
    -- Check that proper ammo is available if we're using ranged attacks or similar.
    if spell.action_type == 'Ranged Attack' or spell.type == 'WeaponSkill' or spell.type == 'CorsairShot' then
        do_bullet_checks(spell, spellMap, eventArgs)
    end

    -- Gear
    if (spell.type == 'CorsairRoll' or spell.english == "Double-Up") then
        if player.status ~= 'Engaged' then
            equip(sets.precast.CorsairRoll.Gun)
        end
        if state.LuzafRing.value then
            equip(sets.precast.LuzafRing)
        end
    elseif spell.type == 'CorsairShot' and state.CastingMode.value == 'Resistant' then
        classes.CustomClass = 'Acc'
    end
    
    if spell.english == 'Fold' and buffactive['Bust'] == 2 then
        if sets.precast.FoldDoubleBust then
            equip(sets.precast.FoldDoubleBust)
            eventArgs.handled = true
        end
    end
    if spellMap == 'Utsusemi' then
        if buffactive['Copy Image (3)'] or buffactive['Copy Image (4+)'] then
            cancel_spell()
            add_to_chat(123, '**!! '..spell.english..' Canceled: [3+ IMAGES] !!**')
            eventArgs.handled = true
            return
        elseif buffactive['Copy Image'] or buffactive['Copy Image (2)'] then
            send_command('cancel 66; cancel 444; cancel Copy Image; cancel Copy Image (2)')
        end
    end
end

function job_post_precast(spell, action, spellMap, eventArgs)
    if (spell.type == 'CorsairRoll' or spell.english == "Double-Up") then
        if player.status ~= 'Engaged' then
            equip(sets.precast.CorsairRoll.Gun)
        end
    elseif spell.action_type == 'Ranged Attack' then
        if flurry == 2 then
            equip(sets.precast.RA.Flurry2)
        elseif flurry == 1 then
            equip(sets.precast.RA.Flurry1)
        end
    -- Equip obi if weather/day matches for WS.
    elseif spell.type == 'WeaponSkill' then
        if spell.english == 'Leaden Salute' then
            if world.weather_element == 'Dark' or world.day_element == 'Dark' then
                equip(sets.Obi)
            end
            if player.tp > 2900 then
                equip(sets.precast.WS['Leaden Salute'].FullTP)
            end    
        elseif spell.english == 'Wildfire' and (world.weather_element == 'Fire' or world.day_element == 'Fire') then
            equip(sets.Obi)
        end
    end
end

function job_post_midcast(spell, action, spellMap, eventArgs)
    -- Equip obi if weather/day matches for Quick Draw.
    if spell.type == 'CorsairShot' then
        if (spell.element == world.day_element or spell.element == world.weather_element) and 
        (spell.english ~= 'Light Shot' and spell.english ~= 'Dark Shot') then
            equip(sets.Obi)
        end
        if state.QDMode.value == 'Magic Enhance' then
            equip(sets.midcast.CorsairShot.Enhance)
        elseif state.QDMode.value == 'STP' then
            equip(sets.midcast.CorsairShot.STP)
        end	
		elseif spell.action_type == 'Ranged Attack' then 
			if buffactive['Triple Shot'] and buffactive['Aftermath: Lv.3'] then
			equip(sets.midcast.RA.TripleShotAM3)
			elseif buffactive['Aftermath: Lv.3'] then
			equip(sets.midcast.RA.Critical)
			elseif buffactive['Triple Shot'] then
			equip(sets.midcast.RA.TripleShot)
		end
	end
end

-- Set eventArgs.handled to true if we don't want any automatic gear equipping to be done.
function job_aftercast(spell, action, spellMap, eventArgs)
    if spell.type == 'CorsairRoll' and not spell.interrupted then
        display_roll_info(spell)
    end
    if spell.english == "Light Shot" then
        send_command('@timers c "Light Shot ['..spell.target.name..']" 60 down abilities/00195.png')
    end
end

function job_buff_change(buff,gain)
    -- If we gain or lose any haste buffs, adjust gear.
    if S{'haste', 'march', 'mighty guard', 'embrava', 'haste samba', 'geo-haste', 'indi-haste'}:contains(buff:lower()) then
        determine_haste_group()
        customize_melee_set()
        if not gain then
            haste = nil
            --add_to_chat(122, "Haste Status: Cleared")
        end
        if not midaction() then
            handle_equipping_gear(player.status)
        end
    end

-- If we gain or lose any flurry buffs, adjust gear.
    if S{'flurry'}:contains(buff:lower()) then
        if not gain then
            flurry = nil
            --add_to_chat(122, "Flurry status cleared.")
        end
        if not midaction() then
            handle_equipping_gear(player.status)
        end
    end

--    if buffactive['Reive Mark'] then
--        if gain then           
--            equip(sets.Reive)
--            disable('neck')
--        else
--            enable('neck')
--        end
--    end

    if buff == "doom" then
        if gain then           
            equip(sets.buff.Doom)
            send_command('@input /p Doomed.')
            disable('ring1','ring2','waist')
        else
            enable('ring1','ring2','waist')
            handle_equipping_gear(player.status)
        end
    end

end

-- Handle notifications of general user state change.
function job_state_change(stateField, newValue, oldValue)
    if state.WeaponLock.value == true then
        disable('ranged')
    else
        enable('ranged')
    end
end

-------------------------------------------------------------------------------------------------------------------
-- User code that supplements standard library decisions.
-------------------------------------------------------------------------------------------------------------------

-- Called by the 'update' self-command, for common needs.
-- Set eventArgs.handled to true if we don't want automatic equipping of gear.
function job_update(cmdParams, eventArgs)
    update_offense_mode()
    determine_haste_group()
end

-- Modify the default idle set after it was constructed.
function customize_idle_set(idleSet)
    if state.Gun.current == 'Death Penalty' then
        equip({ranged="Death Penalty"})
    elseif state.Gun.current == 'Fomalhaut' then
        equip({ranged="Fomalhaut"})
    elseif state.Gun.current == 'Ataktos' then
        equip({ranged="Ataktos"})
    elseif state.Gun.current == 'Armageddon' then
        equip({ranged="Armageddon"})
    end

    if state.CP.current == 'on' then
        equip(sets.CP)
        disable('back')
    else
        enable('back')
    end
    return idleSet
end

-- Modify the default melee set after it was constructed.
function customize_melee_set(meleeSet)
    if state.DualWield.value == true and player.sub_job == 'NIN' then
        meleeSet = set_combine(meleeSet, sets.LessDualWield)
    end

    return meleeSet
end

-- Handle auto-targetting based on local setup.
function job_auto_change_target(spell, action, spellMap, eventArgs)
    if spell.type == 'CorsairShot' then
        if state.IgnoreTargetting.value == true then
            state.IgnoreTargetting:reset()
            eventArgs.handled = true
        end
        
        eventArgs.SelectNPCTargets = state.SelectqdTarget.value
    end
end

-- Set eventArgs.handled to true if we don't want the automatic display to be run.
function display_current_job_state(eventArgs)
    local msg = ''
    
    msg = msg .. '[ Offense/Ranged: '..state.OffenseMode.current
    
    if state.HybridMode.value ~= 'Normal' then
        msg = msg .. '/' .. state.HybridMode.value
    end
    
    msg = msg .. '/' ..state.RangedMode.current .. ' ]'

    if state.WeaponskillMode.value ~= 'Normal' then
        msg = msg .. '[ WS: '..state.WeaponskillMode.current .. ' ]'
    end

    if state.DefenseMode.value ~= 'None' then
        msg = msg .. '[ Defense: ' .. state.DefenseMode.value .. state[state.DefenseMode.value .. 'DefenseMode'].value .. ' ]'
    end
    
    if state.Kiting.value then
        msg = msg .. '[ Kiting Mode: ON ]'
    end

    msg = msg .. '[ *'..state.Mainqd.current

    if state.UseAltqd.value == true then
        msg = msg .. '/'..state.Altqd.current
    end
    
    msg = msg .. ' ('

    if state.QDMode.value then
        msg = msg .. state.QDMode.current .. ') '
    end    

    msg = msg .. ']'
    
    add_to_chat(060, msg)

    eventArgs.handled = true
end

-------------------------------------------------------------------------------------------------------------------
-- User self-commands.
-------------------------------------------------------------------------------------------------------------------

-- Called for custom player commands.
function job_self_command(cmdParams, eventArgs)
    if cmdParams[1] == 'qd' then
        if cmdParams[2] == 't' then
            state.IgnoreTargetting:set()
        end

        local doqd = ''
        if state.UseAltqd.value == true then
            doqd = state[state.Currentqd.current..'qd'].current
            state.Currentqd:cycle()
        else
            doqd = state.Mainqd.current
        end        
        
        send_command('@input /ja "'..doqd..'" <t>')
    end
end


-------------------------------------------------------------------------------------------------------------------
-- Utility functions specific to this job.
-------------------------------------------------------------------------------------------------------------------

--Read incoming packet to differentiate between Haste/Flurry I and II
windower.register_event('action', 
    function(act)
        --check if you are a target of spell
        local actionTargets = act.targets
        playerId = windower.ffxi.get_player().id
        isTarget = false
        for _, target in ipairs(actionTargets) do
            if playerId == target.id then
                isTarget = true
            end
        end
        if isTarget == true then
            if act.category == 4 then
                local param = act.param
                if param == 845 and flurry ~= 2 then
                    --add_to_chat(122, 'Flurry Status: Flurry I')
                    flurry = 1
                elseif param == 846 then
                    --add_to_chat(122, 'Flurry Status: Flurry II')
                    flurry = 2				
                elseif param == 57 and haste ~=2 then
                    --add_to_chat(122, 'Haste Status: Haste I (Haste)')
                    haste = 1
                elseif param == 511 then
                    --add_to_chat(122, 'Haste Status: Haste II (Haste II)')
                    haste = 2
                end
            elseif act.category == 5 then
                if act.param == 5389 then
                    --add_to_chat(122, 'Haste Status: Haste II (Spy Drink)')
                    haste = 2
                end
            elseif act.category == 13 then
                local param = act.param
                --595 haste 1 -602 hastega 2
                if param == 595 and haste ~=2 then 
                    --add_to_chat(122, 'Haste Status: Haste I (Hastega)')
                    haste = 1
                elseif param == 602 then
                    --add_to_chat(122, 'Haste Status: Haste II (Hastega2)')
                    haste = 2
                end
            end
        end
    end)

function determine_haste_group()

    -- Assuming the following values:

    -- Haste - 15%
    -- Haste II - 30%
    -- Haste Samba - 5%
    -- Honor March - 15%
    -- Victory March - 25%
    -- Advancing March - 15%
    -- Embrava - 25%
    -- Mighty Guard (buffactive[604]) - 15%
    -- Geo-Haste (buffactive[580]) - 30%

    classes.CustomMeleeGroups:clear()

    if state.CombatForm.value == 'DW' then

        if (haste == 2 and (buffactive[580] or buffactive.march or buffactive.embrava or buffactive[604])) or
            (haste == 1 and (buffactive[580] or buffactive.march == 2 or (buffactive.embrava and buffactive['haste samba']) or (buffactive.march and buffactive[604]))) or
            (buffactive[580] and (buffactive.march or buffactive.embrava or buffactive[604])) or
            (buffactive.march == 2 and (buffactive.embrava or buffactive[604])) or
            (buffactive.march and (buffactive.embrava and buffactive['haste samba'])) then
            --add_to_chat(122, 'Magic Haste Level: 43%')
            classes.CustomMeleeGroups:append('MaxHaste')
            state.DualWield:set()
        elseif ((haste == 2 or buffactive[580] or buffactive.march == 2) and buffactive['haste samba']) or
            (haste == 1 and buffactive['haste samba'] and (buffactive.march or buffactive[604])) or
            (buffactive.march and buffactive['haste samba'] and buffactive[604]) then
            --add_to_chat(122, 'Magic Haste Level: 35%')
            classes.CustomMeleeGroups:append('HighHaste')
            state.DualWield:set()
        elseif (haste == 2 or buffactive[580] or buffactive.march == 2 or (buffactive.embrava and buffactive['haste samba']) or
            (haste == 1 and (buffactive.march or buffactive[604])) or (buffactive.march and buffactive[604])) then
            --add_to_chat(122, 'Magic Haste Level: 30%')
            classes.CustomMeleeGroups:append('MidHaste')
            state.DualWield:set()
        elseif (haste == 1 or buffactive.march or buffactive[604] or buffactive.embrava) then
            --add_to_chat(122, 'Magic Haste Level: 15%')
            classes.CustomMeleeGroups:append('LowHaste')
            state.DualWield:set()
        else
            state.DualWield:set(false)
        end
    end
end


function define_roll_values()
    rolls = {
        ["Corsair's Roll"] =    {lucky=5, unlucky=9, bonus="Experience Points"},
        ["Ninja Roll"] =        {lucky=4, unlucky=8, bonus="Evasion"},
        ["Hunter's Roll"] =     {lucky=4, unlucky=8, bonus="Accuracy"},
        ["Chaos Roll"] =        {lucky=4, unlucky=8, bonus="Attack"},
        ["Magus's Roll"] =      {lucky=2, unlucky=6, bonus="Magic Defense"},
        ["Healer's Roll"] =     {lucky=3, unlucky=7, bonus="Cure Potency Received"},
        ["Drachen Roll"] =      {lucky=4, unlucky=8, bonus="Pet Magic Accuracy/Attack"},
        ["Choral Roll"] =       {lucky=2, unlucky=6, bonus="Spell Interruption Rate"},
        ["Monk's Roll"] =       {lucky=3, unlucky=7, bonus="Subtle Blow"},
        ["Beast Roll"] =        {lucky=4, unlucky=8, bonus="Pet Attack"},
        ["Samurai Roll"] =      {lucky=2, unlucky=6, bonus="Store TP"},
        ["Evoker's Roll"] =     {lucky=5, unlucky=9, bonus="Refresh"},
        ["Rogue's Roll"] =      {lucky=5, unlucky=9, bonus="Critical Hit Rate"},
        ["Warlock's Roll"] =    {lucky=4, unlucky=8, bonus="Magic Accuracy"},
        ["Fighter's Roll"] =    {lucky=5, unlucky=9, bonus="Double Attack Rate"},
        ["Puppet Roll"] =       {lucky=3, unlucky=7, bonus="Pet Magic Attack/Accuracy"},
        ["Gallant's Roll"] =    {lucky=3, unlucky=7, bonus="Defense"},
        ["Wizard's Roll"] =     {lucky=5, unlucky=9, bonus="Magic Attack"},
        ["Dancer's Roll"] =     {lucky=3, unlucky=7, bonus="Regen"},
        ["Scholar's Roll"] =    {lucky=2, unlucky=6, bonus="Conserve MP"},
        ["Naturalist's Roll"] = {lucky=3, unlucky=7, bonus="Enh. Magic Duration"},
        ["Runeist's Roll"] =    {lucky=4, unlucky=8, bonus="Magic Evasion"},
        ["Bolter's Roll"] =     {lucky=3, unlucky=9, bonus="Movement Speed"},
        ["Caster's Roll"] =     {lucky=2, unlucky=7, bonus="Fast Cast"},
        ["Courser's Roll"] =    {lucky=3, unlucky=9, bonus="Snapshot"},
        ["Blitzer's Roll"] =    {lucky=4, unlucky=9, bonus="Attack Delay"},
        ["Tactician's Roll"] =  {lucky=5, unlucky=8, bonus="Regain"},
        ["Allies' Roll"] =      {lucky=3, unlucky=10, bonus="Skillchain Damage"},
        ["Miser's Roll"] =      {lucky=5, unlucky=7, bonus="Save TP"},
        ["Companion's Roll"] =  {lucky=2, unlucky=10, bonus="Pet Regain and Regen"},
        ["Avenger's Roll"] =    {lucky=4, unlucky=8, bonus="Counter Rate"},
    }
end

function display_roll_info(spell)
    rollinfo = rolls[spell.english]
    local rollsize = (state.LuzafRing.value and 'Large') or 'Small'

    if rollinfo then
        add_to_chat(104, '[ Lucky: '..tostring(rollinfo.lucky)..' / Unlucky: '..tostring(rollinfo.unlucky)..' ] '..spell.english..': '..rollinfo.bonus..' ('..rollsize..') ')
    end
end


-- Determine whether we have sufficient ammo for the action being attempted.
function do_bullet_checks(spell, spellMap, eventArgs)
    local bullet_name
    local bullet_min_count = 1
    
    if spell.type == 'WeaponSkill' then
        if spell.skill == "Marksmanship" then
            if spell.english == 'Wildfire' or spell.english == 'Leaden Salute' then
                -- magical weaponskills
                bullet_name = gear.MAbullet
            else
                -- physical weaponskills
                bullet_name = gear.WSbullet
            end
        else
            -- Ignore non-ranged weaponskills
            return
        end
    elseif spell.type == 'CorsairShot' then
        bullet_name = gear.QDbullet
    elseif spell.action_type == 'Ranged Attack' then
        bullet_name = gear.RAbullet
        if buffactive['Triple Shot'] then
            bullet_min_count = 3
        end
    end
    
    local available_bullets = player.inventory[bullet_name] or player.wardrobe[bullet_name]
    
    -- If no ammo is available, give appropriate warning and end.
    if not available_bullets then
        if spell.type == 'CorsairShot' and player.equipment.ammo ~= 'empty' then
            add_to_chat(104, 'No Quick Draw ammo left.  Using what\'s currently equipped ('..player.equipment.ammo..').')
            return
        elseif spell.type == 'WeaponSkill' and player.equipment.ammo == gear.RAbullet then
            add_to_chat(104, 'No weaponskill ammo left.  Using what\'s currently equipped (standard ranged bullets: '..player.equipment.ammo..').')
            return
        else
            add_to_chat(104, 'No ammo ('..tostring(bullet_name)..') available for that action.')
            eventArgs.cancel = true
            return
        end
    end
    
    -- Don't allow shooting or weaponskilling with ammo reserved for quick draw.
    if spell.type ~= 'CorsairShot' and bullet_name == gear.QDbullet and available_bullets.count <= bullet_min_count then
        add_to_chat(104, 'No ammo will be left for Quick Draw.  Cancelling.')
        eventArgs.cancel = true
        return
    end
    
    -- Low ammo warning.
    if spell.type ~= 'CorsairShot' and state.warned.value == false
        and available_bullets.count > 1 and available_bullets.count <= options.ammo_warning_limit then
        local msg = '*****  LOW AMMO WARNING: '..bullet_name..' *****'
        --local border = string.repeat("*", #msg)
        local border = ""
        for i = 1, #msg do
            border = border .. "*"
        end
        
        add_to_chat(104, border)
        add_to_chat(104, msg)
        add_to_chat(104, border)

        state.warned:set()
    elseif available_bullets.count > options.ammo_warning_limit and state.warned then
        state.warned:reset()
    end
end

function update_offense_mode()  
    if player.sub_job == 'NIN' or player.sub_job == 'DNC' then
        state.CombatForm:set('DW')
    else
        state.CombatForm:reset()
    end
end

-- Select default macro book on initial load or subjob change.
function select_default_macro_book()
    if player.sub_job == 'DNC' then
        set_macro_page(1, 7)
    else
        set_macro_page(1, 7)
    end
end

function set_lockstyle()
    send_command('wait 2; input /lockstyleset ' .. lockstyleset)
end
Offline
Posts: 32
By darsinger 2026-08-12 14:19:07
Link | Citer | R
 
Cursory glance: Not all of your various .RA sets have an ammo included - particularly Critical, Triple Shot, and Triple Shot AM3. Presumably that's when you're most often using ranged attacks. Also, while I don't think it *should* matter much, your bullets aren't capitalized as seen in inventory but as on the description text. I'd capitalize "Bullet" and put an ammo in each of those .RA sets and retest.

Edit: Including the precast.RA set
[+]
 Asura.Lunafreya
Offline
Serveur: Asura
Game: FFXI
User: Lunafreya
Posts: 870
By Asura.Lunafreya 2026-08-12 15:13:04
Link | Citer | R
 
Adding gear.RABullet into every RA set (pre and mid) did the trick it seems. Thanks!
First Page 2 3 ... 189 190