Supernova FFXI Wiki
Advertisement

This guide is designed to help you create GearSwap files in a step-by-step manner. It'll start with the very basic, and will progress to more advanced techniques as this page gets updated. Although the example codes are designed for Black Mages, the techniques involved will work for all jobs.

Before you begin, make sure you have Notepad++ installed on your PC. It makes reading and writing code so much easier than normal notepad. Also, turn on the GearSwap addon in Windower if you have not already.

The Basics[]

Now for the fun part. Here we will learn how to layout the script, set equipment, and create basic conditions on when to activate the different functions of the script. The tutorial below will use, as an example, a Black Mage casting the spell "Flare".

Layout[]

All GearSwap users files should be stored in C:\Program Files (x86)\Windower4\addons\GearSwap\data\

Any time you log in, or change jobs, GearSwap will look there for file that correspond to your current job. For example, if you change job to Black Mage, it will look for a blm.lua file and automatically load it if one exist.

In Notepad++, create a new file, choose a job to name it, and save it as a Lua Source Type. This will make it so the file extension is .lua. For this tutorial, we'll be using Black Mage as our example. So, we'll go ahead and create a blm.lua file and save it in the data folder.

Now that we have blm.lua created, open it and enter the following lines:

function get_sets()

--This function prepares your equipment sets.

end

-----------------------------------------------------------------------------------

function precast(spell)

--This function performs right before the action is sent to the server.

end

-----------------------------------------------------------------------------------

function midcast(spell)

--This function performs after precast but before the action is sent to the server.

end

-----------------------------------------------------------------------------------

function aftercast(spell)

--This function performs after the action has taken place

end

-----------------------------------------------------------------------------------

Equipment Sets[]

Now lets look at function get_sets(). Below it, you'll write out all of the possible equipment sets you'll be swapping. But for now, let's just work with a couple of equipment pieces. In the function, edit it so that it looks like:

function get_sets()

	sets.precast = {}

	sets.midcast = {}

	sets.aftercast = {}

end

Now lets start filling in equipment. For our example, we'll equip gear as if we're about to cast the spell "Flare"

function get_sets()

	sets.precast = {sub="Vivid Strap +1",feet="Rostrum Pumps"}

	sets.midcast = {main="Vulcan's Staff",sub="Fire Grip"}

	sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"}

end

Looking at this, right before the we cast "Flare", precast will equip "Vivid Strap +1" and "Rostrum pumps" for their "Fast Cast" traits. For a mage, precast is mainly used in trying to activate "Fast Cast". For melee, precast is used for preparing beneficial traits for weaponskills.

Right before "Flare" activates, midcast then equip gear that will benefit its fire element

After Flare is casted, aftercast will equip "Terra's Staff" and "Herald's Gaiters" for their defensive traits.

Remember, we've so far only made our equipment sets. The codes won't work until we fill in the rest of the functions.

Precast[]

Let's look at function precast(spell). This function is called right before your spell/ability/weaponskill is activated.

function precast(spell)

	equip(sets.precast)

end

By putting in equip(sets.precast), any time you're about to perform any spell/ability/weaponskill, your equipment will be changed based on the sets.precast = {} table. If you want to specify conditions on when it should activate, you'll have to use if statements. We'll go ahead and use them for the next function.

Midcast & Conditional Statements[]

Now it's time for function midcast(spell). This function comes after precast but before the spell/ability/weaponskill takes place. Since our example is what to equip when casting "Flare", we'll have to make a conditional statement so that it will only activate when "Flare" is casted.

function midcast(spell)

	if spell.english == "Flare" then
		equip(sets.midcast)
	end

end

This above example will look at the action you took, and check its English name. It will compare it to the term "Flare". If they match, then it will equip gear based on sets.midcast = {}. If it does not match, then it will ignore, and not do anything else in the function.

Aftercast[]

And finally, we have function aftercast(spell). This function is called after performing your spell/ability/weaponskill. You'll want to use this function to go back to your default gear.

function aftercast(spell)

	equip(sets.aftercast)

end

This will equip your gear based on sets.aftercast = {} after your actions has taken place.

Putting it together[]

Now that we have a complete set, let's have a look at it as a whole.

function get_sets()

	sets.precast = {sub="Vivid Strap +1",feet="Rostrum Pumps"}

	sets.midcast = {main="Vulcan's Staff",sub="Fire Grip"}

	sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"}

end

-----------------------------------------------------------------------------------

function precast(spell)

	equip(sets.precast)

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.english == "Flare" then
		equip(sets.midcast)
	end

end

-----------------------------------------------------------------------------------

function aftercast(spell)

	equip(sets.aftercast)

end

-----------------------------------------------------------------------------------

Go ahead and try it! You'll see that it work. However, there's one small problem. You'll definitely want more than just a "Flare" script. You have hundreds of other spells and abilities! So, instead of occupying the main tables (sets.precast, sets.midcast, sets.aftercast), you'll want to make your own. We call these sub-tables.

Sub-tables[]

function get_sets()

	sets.precast = {}
	sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"}

	sets.midcast = {}
	sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip"}
	sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip"}

	sets.aftercast = {main="Terra's Staff",feet="Herald's Gaiters"}

end

-----------------------------------------------------------------------------------

  function precast(spell)

	if spell.type:contains('Magic') then
		equip(sets.precast.fc)
	end

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.english == "Flare" then
		equip(sets.midcast.flare)
	end
	if spell.english == "Quake" then
		equip(sets.midcast.quake)
	end

end

-----------------------------------------------------------------------------------

function aftercast(spell)

	equip(sets.aftercast)

end

-----------------------------------------------------------------------------------

Above in bold are the changes made to accommodate future actions and equipment swaps. sets.precast = {} and sets.midcast = {} were left blank so that those main tables exist. Without them, their sub-tables will not work at all.

sets.precast.fc is a sub-table that was made for "Fast Cast". You could've named it sets.precast.anything. fc was easy enough to remember for "Fast Cast". If you decide to name it something else, just remember to call it correctly in your precast function.

sets.midcast.flare was created specifically for the spell "Flare". You can add more spells by creating more subtables with unique names below it and creating their respective equipment sets. (example sets.midcast.quake)

In function precast(spell), you'll notice a new condition. What is happening here is the function is looking at your action, and checking its type. It'll find either JobAbility, Weaponskill, WhiteMagic, BlackMagic, BardSong, or something else. It will compare what it finds with the term "Magic". If the type it finds contains "Magic" whether its BlackMagic or WhiteMagic, it will return as true and work the rest of the command equip(sets.precast.fc). If the type it finds does not contain the term "Magic", then it will ignore and no action will take place in this function.

In function midcast(spell), when conditions are met, it will now call upon either sets.midcast.flare or sets.midcast.quake and equip the appropriate gear.

The Basics Concluded[]

So far, we've learned how to create the basic layout of a GearSwap file, make equipment sets, and formulate conditions on when gear swapping should take place. With this basic understanding, you can create rudimentary gearswap files for any spell, or ability.

Intermediate[]

The basics are fine for creating equipment sets, but it lacks the control you sometimes need for more complex situations. In this tutorial, we'll practice with more conditional statements and learn more about the different functions and variables available in GearSwap.

Post Aftercast and More Conditional Statements[]

When we last left off, aftercast didn't really do much. It simply equip gear assigned to it after each and every spell or ability. But not every post-action situation calls for the same equipment. Let's alter our last example a bit:

function get_sets()

	sets.precast = {}
	sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"}

	sets.midcast = {}
	sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip"}
	sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip"}

	sets.aftercast = {}
	sets.aftercast.idle = {main="Terra's Staff", feet="Herald's Gaiters"}
	sets.aftercast.rest = {main="Chatoyant Staff"}
	sets.aftercast.engaged = {waist="Life Belt"}

end

-----------------------------------------------------------------------------------

function precast(spell)

	if spell.type:contains('Magic') then
		equip(sets.precast.fc)
	end

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.english == "Flare" then
		equip(sets.midcast.flare)
	end
	if spell.english == "Quake" then
		equip(sets.midcast.quake)
	end

end

-----------------------------------------------------------------------------------

function aftercast(spell)

	if player.status == "Engaged" then
		equip(sets.aftercast.engaged)
	elseif player.status == "Idle" then
		equip(sets.aftercast.idle)
	end

end

-----------------------------------------------------------------------------------

function status_change(new,old)

	if new == 'Idle' then
		equip(sets.aftercast.idle)
	elseif new == 'Resting' then
		equip(sets.aftercast.rest)
	elseif new == 'Engaged' then
		equip(sets.aftercast.engaged)
	end

end

-----------------------------------------------------------------------------------

In bold are the new changes. As you can see, we did quite a lot. We made an empty sets.aftercast table so that it exists for the sub-tables sets.aftercast.idle, sets.aftercast.rest, and sets.aftercast.engaged.

In function aftercast(spell) we called upon a the variable player.status and see if the player was engaged with a mob or not. If it is, then it will call sets.aftercast.engaged and equip melee suitable gear.

Below that is a new function called status_change(new,old). This function is called every time a player's status changes (Engaged, Idle, Resting, Dead). It will pass on the new status to the variable new and old status to the variable old.

In the example, the status_change function checks the new status and sees if you're idle, resting, or engaged, and it will equip the appropriate gear set. The reason why we use this function, is so your gear changes any time your status change. aftercast will only check those conditions after performing a spell or ability.

Functions[]

So far, we've already encounterd a handful of functions: get.sets, precast, midcast, aftercast, and most recently status_change. However, there are a few more that needs to be addressed.

pet_aftercast(spell) Passes the resources line for the spell with a few modifications. Occurs when the readies action packet is received for your pet.
pet_aftercast(spell) Passes the resources line for the spell with a few modifications. Occurs when the result action packet is received for your pet.
pet_status_change(new,old) Passes the new and old statuses of your pet.

buff_change(name,gain)

Passes the new buff name and a boolean that indicates whether it was gained true or lost false. Does not fire if your buff bar does not change. For instance, overwriting a March with another March will not trigger this event.

send_command(command) Sends a command to console. Be aware that this will (probably?) be picked up by Shortcuts and thus may be picked up again by Gearswap. Don't make an infinite loop. Also, forces the command to be prefixed by @.

There are many more built-in functions, but we'll only look at these for now. Similar to the normal midcast and aftercast functions, pet_midcast, and pet_aftercast will activate when your pet performs an action.

buff_change is a neat function. The name of the buff/debuff is passed onto the variable name, while the gain variable will be passed the values of True or False. True if the buff was added to your buff status bar, or False if the buff was removed from your status bar. Let's create an example and then analyze it.

function get_sets()

	sets.buff = {}
	sets.buff.sleep {neck = "Opo-opo Necklace"}

end

-----------------------------------------------------------------------------------

function buff_change(name,gain)

	if name == "sleep" and gain =="True" then
		equip(sets.buff.sleep)
	end
end

-----------------------------------------------------------------------------------

Here we created a table called sets.buff and the sub-table sets.buff.sleep. Below that we set the buff_change function to check on whether or not your character have been put to sleep. If you have been put to sleep, then the function will equip the "Opo-opo Necklace" to gain TP while you sleep.

send_command is also useful. It allows you to send commands directly to Windower's console. You must prefix a console command with @. Lets look at another example.

function buff_change(name,gain)

	if name == "silence" and gain =="True" then
		send_command('@input /item "Echo Drops" <me>')
	end

end

Here we have a standalone function that checks on whether or not your character is silenced. If true, send_command will issue a command to Windower's console, in this instance the input command. input is a windower command that sends text to the game server. In our example, input sends the text command to use "Echo Drops" on yourself.

Spell Variables[]

Earlier in The Basics, you learned about the spell.english and spell.type variables. These are just a few of the many variables you'll encounter to make more flexible scripts. Below are a few more.

spell.name string Spell name in the language of your client
spell.targets table Table of Booleans keyed to Self, Player, Party, Ally, NPC, Enemy, and Corpse. True means that it's valid for that target.
spell.type string String indicating the type of spell without spaces. So “JobAbility” for Provoke, “WhiteMagic” for Cure, “BardSong” for Marches, etc. Obtained from resources.
spell.skill string String form of the skill a spell is based on, or “Ability” for abilities. So “Healing Magic” for Cure, “Ability” for Provoke, “Singing” for Marches, etc. Obtained from resources.
spell.mp_cost number Number representing the base MP cost of a spell. Obtained from resources.
spell.tp_cost number Number representing the base TP cost of a spell. Obtained from resources.
spell.element string String form of the element name. Obtained from resources.
spell.interrupted boolean True if the spell (or job ability) failed to execute. Only valid in the aftercast/pet_aftercast phase.

In the table above, you'll notice that information about these variables can be "Obtained from resources." The resource it refers to can be found in C:\Program Files (x86)\Windower4\res\. Use these file as a guide to help you. (Note that these files are based on FFXI's retail data. Information such as mp cost may or may not match SuperNova's classic data)

In our example in The Basics we use a couple of ways to read data coming from these variables.

The direct comparison route uses math operators to check whether the data is true or not (==, >, >=, <, <=) example: spell.skill == 'Ability' (This checks if the user action was an "Ability", and sends a True or False statement.

The search routes looks for data within the variable and sends a True or False based on what it finds.You can achieve this method by appending the variable with :startswith('data'), :contains('data'), or :endswith('data'). example: spell.skill:startswith('Healing') (This checks if the user action is an ability that depends on a skill starting with the term "Healing", and sends a True or False statement)

Let's create an example script

function aftercast(spell)

	if spell.english:startswith('Thunder') and spell.interrupted then
		if spell.english:endswith('IV') then
			send_command('@input /ma "Thunder III" <t>')
		elseif spell.english:endswith('III') then
			send_command('@input /ma "Thunder II" <t>')
		elseif spell.english:endswith('II') then
			send_command('@input /ma "Thunder" <t>')
		end
	end

end

Now we must decipher this nested condition statement. This function attempts to cast a Thunder spell, and if it fails to do so, will pick the next lower tier. Assuming the user failed to cast "Thunder IV", the script will then attempt to cast "Thunder III". If it can do so, then this function will no longer act. If however, that also fails, the scrip will then attempt to cast "Thunder II", and "Thunder" if need be. (This is not the ideal way of achieving this task. However, it's the best we have with what we've learned so far).

Player Variables[]

In addition to the data from spells and abilities, you can also collect data from yourself or your pet. The main variables are player and pet. By attaching them to one of the keys below, you can gather any information about yourself or your pet. example: player.max_hp

Keys Valid Entities Type Description
Player Pet
name Yes Yes string Name of the entity.
status Yes Yes string String indicating an Entities status.
hp Yes ? number Entity's current HP.
hpp ? Yes number Number from 0 to 100 indicating the current HP% of the Entity.
max_hp Yes ? number Entity's current max HP.
mp Yes No number Entity's current MP.
mpp ? No number Number from 0 to 100 indicating the current MP% of the Entity.
max_mp Yes No number Entity's current max MP.
tp Yes Yes number Entity's current TP.
isvalid No Yes boolean Boolean that indicates whether or not the Entity exists.
element No Yes string Fire, Water, Thunder, etc. for Avatars.

And here is the example script

function get_sets()

	sets.midcast = {}
	sets.midcast.ring = {ring1="Sorcerer's Ring"}

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.skill == "Elemental Magic" and player.hpp < 76 and player.tp < 100 then
		equip(sets.midcast.ring)
	end

end

-----------------------------------------------------------------------------------

In this example, we've set a condition that would equip the "Sorcerer's Ring" if the user action has the skill type of "Elemental Magic" and if the player HP is less than 76% and if the player's TP is less than 100% (eq to 1000 tp). Only when these conditions are met will equip(sets.midcast.ring) be called.

Putting it together[]

Below is an example of everything learned so far. This time, the equipment list is complete and formated for readibility

function get_sets()

	sets.precast = {}
	
	sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"}
-----------------------
	sets.midcast = {}
	
	sets.midcast.ring = {ring1="Sorcerer's Ring"}	
	
	sets.midcast.flare = {main="Vulcan's Staff",sub="Fire Grip",ammo="Hedgehog Bomb",
	head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring",
	body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring",
	back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"}
		
	sets.midcast.quake = {main="Terra's Staff",sub="Earth Grip",ammo="Hedgehog Bomb",
	head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring",
	body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring",
	back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"}

-----------------------
	sets.aftercast = {}
        sets.aftercast.engaged = {}

	sets.aftercast.idle = {main="Terra's Staff",
	head="Walahra Turban",
	body="Dalmatica +1",
	waist="Headlong Belt", feet="Herald's Gaiters"}

	sets.aftercast.rest = {main="Chatoyant Staff",sub="Staff Strap",ammo="Hedgehog Bomb",
	head="Cobra Hat",neck="Beak Necklace +1",ear1="Rapture Earring",ear2="Antivenom Earring",
	body="Mahatma Hpl.",hands="Genie Gages",ring1="Celestial Ring",ring2="Celestial Ring",
	back="Invigorating Cape",waist="Hierarch Belt",legs="Mahatma Slops",feet="Arborist Nails"}

end

-----------------------------------------------------------------------------------

function precast(spell)

	if spell.type:contains('Magic') then
		equip(sets.precast.fc)
	end

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.english == "Flare" then
		equip(sets.midcast.flare)
	end
	
	if spell.english == "Quake" then
		equip(sets.midcast.quake)
	end
	
	if spell.skill == "Elemental Magic" and player.hpp < 76 and player.tp < 100 then
		equip(sets.midcast.ring)
	end

end

-----------------------------------------------------------------------------------

function aftercast(spell)

	if player.status == "Engaged" then
		equip(sets.aftercast.engaged)
	elseif player.status == "Idle" then
		equip(sets.aftercast.idle)
	end

end

-----------------------------------------------------------------------------------

function status_change(new,old)

	if new == 'Idle' then
		equip(sets.aftercast.idle)
	elseif new == 'Resting' then
		equip(sets.aftercast.rest)
	end

end

-----------------------------------------------------------------------------------

function buff_change(name,gain)

	if name == "silence" and gain =="True" then
		send_command('@input /item "Echo Drops" <me>')
	end

end

-----------------------------------------------------------------------------------

In the midcast(spell) function above, you'll notice that I have the sets.midcast.ring condition come last. This is due to the fact that condition statements are done in order. And with it being last, there's no chance for other equip sets to override the ring's slot placement.

You'll also notice that it's getting pretty crowded in the get_sets() function. And this is with only two spells listed! For the sake of not having to edit for each and every spell, ability, and weaponskill, we'll have to shrink it down as much as possible, without having to sacrifice any gear.

Shrink it![]

As with any good code, the smaller the better. This allows for faster edits in the long run. Plus, it looks nicer. The following may have more or less lines that the previous code. However, this version is consice enough to parse all elemental nukes, instead of just the two "Flare" and "Quake" spells.

function get_sets()

	sets.precast = {}
	
	sets.precast.fc = {sub="Vivid Strap +1",feet="Rostrum Pumps"}
-----------------------
	sets.midcast = {}
	
	sets.midcast.ring = {ring1="Sorcerer's Ring"}	
	
	sets.midcast.earth = {main="Terra's Staff",sub="Earth Grip"}
	sets.midcast.water = {main="Neptune's Staff",sub="Water Grip"}
	sets.midcast.wind = {main="Auster's Staff",sub="Wind Grip"}
	sets.midcast.fire = {main="Vulcan's Staff",sub="Fire Grip"}
	sets.midcast.ice = {main="Aquilo's Staff",sub="Ice Grip"}
	sets.midcast.thunder = {main="Jupiter's Staff",sub="Thunder Grip"}
	sets.midcast.dark = {main="Pluto's Staff",sub="Dark Grip"}
	sets.midcast.light = {main="Chatoyant's Staff",sub="Light Grip"}
	
	sets.midcast.nuke ={ammo="Hedgehog Bomb",
	head="Demon Helm +1",neck="Caract Choker",ear1="Moldavite Earring",ear2="Crapaud Earring",
	body="Genie Weskit",hands="Genie Manillas",ring1="Snow Ring",ring2="Snow Ring",
	back="Hecate's Cape",waist="Witch Sash",legs="Mahatma Slops",feet="Mahant Sandals"}
-----------------------
	sets.aftercast = {}
        sets.aftercast.engaged = {}

	sets.aftercast.idle = {main="Terra's Staff",
	head="Walahra Turban",
	body="Dalmatica +1",
	waist="Headlong Belt", feet="Herald's Gaiters"}

	sets.aftercast.rest = {main="Chatoyant Staff",sub="Staff Strap",ammo="Hedgehog Bomb",
	head="Cobra Hat",neck="Beak Necklace +1",ear1="Rapture Earring",ear2="Antivenom Earring",
	body="Mahatma Hpl.",hands="Genie Gages",ring1="Celestial Ring",ring2="Celestial Ring",
	back="Invigorating Cape",waist="Hierarch Belt",legs="Mahatma Slops",feet="Arborist Nails"}

end

-----------------------------------------------------------------------------------

function precast(spell)

	if spell.type:contains('Magic') then
		equip(sets.precast.fc)
	end

end

-----------------------------------------------------------------------------------

function midcast(spell)

	if spell.element == "Earth" then
		equip(sets.midcast.earth)
	elseif spell.element == "Water" then
		equip(sets.midcast.water)
	elseif spell.element == "Wind" then
		equip(sets.midcast.wind)
	elseif spell.element == "Fire" then
		equip(sets.midcast.fire)
	elseif spell.element == "Ice" then
		equip(sets.midcast.ice)
	elseif spell.element == "Thunder" then
		equip(sets.midcast.thunder)
	elseif spell.element == "Dark" then
		equip(sets.midcast.dark)
	elseif spell.element == "Light" then
		equip(sets.midcast.light)
	end
	
	
	if spell.skill == "Elemental Magic" then
		equip(sets.midcast.nuke)
		if player.hpp < 76 and player.tp < 100 then
			equip(sets.midcast.ring)
		end
	end

end

-----------------------------------------------------------------------------------

function aftercast(spell)

	if player.status == "Engaged" then
		equip(sets.aftercast.engaged)
	elseif player.status == "Idle" then
		equip(sets.aftercast.idle)
	end

end

-----------------------------------------------------------------------------------

function status_change(new,old)

	if new == 'Idle' then
		equip(sets.aftercast.idle)
	elseif new == 'Resting' then
		equip(sets.aftercast.rest)
	elseif new == 'Engaged' then
		equip(sets.aftercast.engaged)
	end

end

-----------------------------------------------------------------------------------

function buff_change(name,gain)

	if name == "silence" and gain =="True" then
		send_command('@input /item "Echo Drops" <me>')
	end

end

-----------------------------------------------------------------------------------

As you can see, I took out the common equipment from the "Flare" and "Quake" (which were mostly MAB, and INT gear) and place them in their own set called set.midcast.nuke. I then made an equip set for each element type.

As for the midcast function, I created a condition nest checking for the element type and equipping the correct elemental staff and grip. Then it checks the action's skill type and equip the nuke gear if it was "Elemental Magic". Further into that same condition scipt, it checks for player's MP and TP in case it needed to equip "Sorcerer's Ring."

Intermediate Concluded[]

In this lesson, you've learned about nested conditions, functions, and built in variables. Also you have some resource files you can look up to better aid your script making. I will include more the locations again in the postscript. Hopefully, you've learned enough here to teach yourself new tricks and shortcuts for building better scripts. Next up, is Advanced Mode!

Resources[]

GearSwap Global Variables

GearSwap Functions

Windower Commands

FFXI resource data files: C:\Program Files (x86)\Windower4\res\

Advertisement