INTRODUCTION
This guide originally appeared on the Supernova Wiki, and was written by player Rotha.
It has been migrated to this site and is now maintained by Supernova Staff
This guide is designed to help you create GearSwap files in a step-by-step manner. It will 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.
Contents
- Gearswap Basics
- Intermediate-Level Gearswap
- Resources
- GearSwap Global Variables
- GearSwap Functions
- Sample GearSwap lua Files, by Wren
- Windower Commands
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.
*Editorial note: naming a file [job].lua will allow Gearswap to apply it to all characters on your account. If you want it to only apply to a certain character, you will need to name the file [charactername_job].lua (i.e., tristamgreen_blm.lua).
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.
Conclusion
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-tablessets.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 operatorsto 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.”
Conclusion
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. If you are interested in further advancing your Gearswap knowledge, check out Enedin’s Gearswap Page!
Resources
Sample GearSwap lua Files, by Wren
Default FFXI resource data file path: C:\Program Files (x86)\Windower4\res\
You must be logged in to post a comment.