Lua Scripting in Final Fantasy XI
Yes, that FFXI, the one that came out in 2003
Why talk about this?
- This game is 17 years old
- I just find the history and progression of how the game and community evolved utterly fascinating
- FFXI is a beautiful mess of a game
- don't actually play it
- stare at it like you'd stare at a car crash, transfixed by the rising flames and smoke
- In hindsight it seems like it's this collaborative game design/development process between devs and players
this game was made in 2003 why am i talking about this
Disclaimer:
- None of this is allowed in the EULA
- For various reasons, Square Enix turns a blind eye to innocuous uses of scripting
- Botting will get you banned
- Position hacking will get you banned
- This talk isn't about any of that
3rd party support
- Game came out on PS2 and PC in 2002 (Japan) and 2003 (US)
- A lot of issues stem from its PS2 DNA
- PC version would not let you alt-tab or resize the game window
- People made a wrapper to put the client in to allow for this basic functionality
- This wrapper program was known as Windower
-
Later versions of Windower allowed for addon support
- Initially written in C and compiled to .dlls
- Most recent version implemented Lua scripting
This game is still running
- It's difficult for the official dev team to allocate resources to update the game's client
- at least up to recently, they need PS2 dev kits to build both client and server, and there are like six of those left in the world that work
- It's easy for players to modify the client
- SE has recognized this and lets most of it slide
tyler none of this has been lua yet
- i'm getting there
GearSwap
- GearSwap is a lua-based addon for Windower 4
- You can define sets of gear and under what conditions you'll automatically swap to that gear
- This is a vital part of FFXI
Horizontal Progression
- FFXI's progression system isn't entirely vertical
- Other games typically make upgrades easy to reason about
- WoW's gear score
- FFXIV's item level
- etc. bigger stats = better
Horizontal Progression
- Most other games don't let you change gear mid-fight
- FFXI ... does, and the design accounts for it
- There's an in-game macro system!
- very limited though, few lines
Equipment slots
16 slots for equipment
In-game macro system has six lines, maximum
Can only change five pieces of gear at once without spilling into other macros
Horizontal progression
- Pieces of gear have niche uses
- Progression is about how wide your armory is, not how strong your strongest sword is
- You don't need to choose between which of these to wear!
- But you do need to juggle them with macros or gearswap
finally an example
- GearSwap reads incoming and outgoing packets
- Define sets at the start of the file
-
Ability use has three phases:
- precast
- midcast
- aftercast
- because FFXI checks different parameters at different times of ability use
Some sets
sets.Idle =
{
ammo="Staunch tathlum"
head="Rawhide mask",
neck="Sanctity necklace",
ear1="Ethereal earring",
ear2="Brachyura earring",
body="Jhakri robe +2",
hands="Herculean gloves",
ring1="Karieyh ring",
ring2="Defending ring",
back="Rosmerta's cape",
waist="Flume belt",
legs="Carmine cuisses +1",
feet="Ayanmo gambieras +2"
}
sets.TP =
{
ammo="Ginsen"
head="Adhemar bonnet +1",
neck="Mirage stole +1",
ear1="Suppanomimi",
ear2="Cessance earring",
body="Adhemar jacket +1",
hands="Adhemar wristbands +1",
ring1="Epona's ring",
ring2="Petrov ring",
back="Rosmerta's cape",
waist="Windbuffet belt +1",
legs="Samnuha tights",
feet="Herculean boots"
}
sets.ChantDuCygne =
{
ammo="Jukukik feather"
head="Adhemar bonnet +1",
neck="Mirage stole +1",
ear1="Moonshade earring",
ear2="Brutal earring",
body="Ayanmo corazza +2",
hands="Adhemar wristbands +1",
ring1="Epona's ring",
ring2="Begrudging ring",
back="Rosmerta's cape",
waist="Fotia belt",
legs="Samnuha tights",
feet="Herculean boots"
}
Function hooks
- Now with sets defined, override the precast, midcast, and aftercast hooks
function precast(spell)
if spell.english == 'Chant du Cygne' then
equip(sets.ChantDuCygne)
end
end
function midcast(spell)
end
function aftercast(spell)
if player.status == 'Engaged' then
equip(sets.TP)
else
equip(sets.Idle)
end
end
well that doesn't seem so bad
- just map some equipment to abilities and you're good to go right?
- weeeeeell it's not always that easy
how was anyone supposed to use the macro system to juggle any of this
- Left: a piece of gear known as the "weather belt"
- Right: a generically good piece of gear for casting spells in
Let's talk about the weather
- There are eight weather effects in the game
- Each of them correspond to one of eight elements
- If you cast a spell that matches the element of the current weather, there is a 1/3 chance for the spell to be upgraded in power
- 10% power upgrade for one icon, 25% for two
this belt
- this belt, if matching weather is active, beats the pants off of anything else in that slot
- It forces the 1/3 chance for a weather proc to occur 100% of the time.
- if matching weather is not active, it's completely useless
Conditionals
- one of the big draws of gearswap is to handle special cases like this and add conditional logic
- macro system has nothing like this
- Assume we have a general black magic midcast set, and in our midcast function hook, we do this:
if world.weather_element == spell.element then
equip( set_combine( sets.BlackMagicMidcast, { waist="Hachirin-no-Obi" } ) )
end
Now, all we have to think about is just when to use our abilities, and it'll automatically swap out the belt only when it's relevant
in conclusion
- don't actually play FFXI unless you're in for doing a lot of programming yourself to make the game even functional or fun
- maybe that's your thing! i mean, it's mine
- i have no idea if this made sense to anyone
Lua scripting in Final Fantasy XI
By tdhoward
Lua scripting in Final Fantasy XI
- 470