Who tricked me into playing FFXI again?

I’ve been slowly coming out the other side of a FFXI bender.

It’s still fun. I like numbers-go-up. But it’s too demanding. This is always the problem I run into with games. I look at ways of optimizing progress, and it turns into me managing a half a dozen or more characters.

It was 8 characters this time. I had the idea a couple months in that I should get them all full inventory upgrades so I could hold more stuff. I didn’t need to hold more stuff. Actually, about 2 months ago, I found an addon that automatically throws stuff away called treasury, and it is awesome. Once I got inventory upgraded, it was such a convenience because I had so much more space to dump the stuff from my main 2 characters (Chihemihe or Chi, and Kitiaramatar). Then I realized they were all getting to the point where they could participate in some exclusive content that required the character to be 45 days old and level 99. Well, then I wanted to get them all to level 99. That meant unlocking a ton of areas and story content and breaking limit quests and unlocking subjobs and leveling those subjobs. I like these things in all games–unlocking access to activities–so I had a lot of fun.

Around this time there were 2 events that made this really easy to accomplish.

One event was the 2019 Adventurer Appreciation Campaign that gave everybody a crazy XP bonus ring you could use every 2 hours for a 30k XP bonus. You could buy one directly, then get a coupon for another. I realized I could send them to myself or other characters on my account, so they each got 2-3 rings, and I rotated them through the inbox (they were rare/exclusive, which meant each character could only hold one across all inventory containers; however, some rare/exclusive items could be mailed to characters on the same account, and the inbox did not count against this limit). This meant I could use one, send it, get the other, and run out to the XP camp and have 2 back-to-back ring bonuses. On each character. And all the time, because I had 7 characters that needed XP (main was 99 on everything years ago).

The second event was the Alter Ego Extravaganza, from which you could get the Shantotto II trust. Shantotto is pretty broken. She only uses tier 1 black mage spells, but she has an insane magic attack bonus. I’d use the Tenzen trust at the same time, who would close skillchains (SCs) pretty consistently. We’d make a chain, and Shantotto would do back-to-back tier 1 magic bursts (MBs) for insane damage. Pretty much if I could get TP fast enough, and Tenzen was ready, my damage didn’t matter at all. It would be dead. So I got 99 fairly quickly, then thought, why not keep going? I had leveled Samurai on all but one character, which only had Rune Fencer. (RUN IS a super powerful job, but I generally don’t care for tanks, and the damage didn’t compare to SAM/DRG/WAR as a fresh 99, so this char wasn’t as useful as the others in solo play.)

Before these events, I had been grinding Ambuscade for points to get the Shining One (polearm) on Chi and the Gotekai (katana) on Kitiaramatar. Both were super cool. I had been dragging along a mule to each one to get points on those characters as well. But I was tired of the dead weight, and discovered that SAM + NIN make a really strong team for darkness SCs, and Ambu got a little easier, so I wanted to gear up all the mules as Samurai. This took some time since my attention was split 6 ways, and I kept them pretty much even. Eventually I got the level 3 or 4 great katana from Ambuscade on each mule and we were tearing it up. But I struggled on some fights, because Samurai was too squishy compared to Ninja. So then I leveled Ninja on all the characters. This was really fun, since NIN is probably my favorite all-around job. High evasion, decent damage, fast attacks, shadows (up to 7! And Utsu San is super fast to cast!), high movement speed, elemental damage, debuffs, Daken (auto-ranged; all of my characters have capped throwing skill now). This was fine but still only let me take on lower level Ambu content.

Windower scripting using Lua

Voidwatch scripting

Around this time I also learned how to script with Lua, and built several addons (I prefixed everything with ‘my’ because addons all live in a flat directory and I wanted an easy way to get to just my addons.)

Lua scripting probably kept me in the game 2 months longer than I would have played otherwise. Once I figured out how to parse game text and enter commands and send messages, I had all I needed (inputs and outputs) to write useful scripts.

The first lua script I built was for an event for Voidwatch which granted all lights to maximum level without having to proc. This meant you could just spam weapon skills and even oneshot the monster if you were strong enough, and get max possible loot chance. During this event I ground out out over 1000 heavy metal plates for the Bard harp I never used (though this is probably what will bring me back later; I put a ton of effort into it and it is really cool, I just gave up too fast trying to get gearswap to handle it properly; I’ll probably have to build a custom script, which I didn’t know how to do at the time).

There was an addon on GitHub called voidwatch that would handle trades of weakening items, spawning, loot grabbing, loot relinquishing, etc.. Everyone in the party would run it, and the leader’s script would handle the spawning. This meant everyone could basically stand around, wait for the monster, attack, wait around, repeat, and get rich. I called the event inventorywatch because the only thing I was doing manually was managing my inventory.

I also wrote a custom script called myvoidwatch that was not very sophisticated which hooked into yet another addon called SetTarget, which would take an id and switch your target to it. My script handled the job abilities, weapon skilling, and item usage for my character. I ran it next to the voidwatch script, so that I could basically just have to be sure I was pointing in the right direction. Then I realized I could move my character with the script by comparing the world position vectors between my character and my target and using relative 3D positioning to make sure my character was facing the right way. I never got far enough to make it handle distance, just facing. At this point the event ended and I was so burned out I abandoned voidwatch altogether and went back to leveling my mules.

Skillchain scripting

While I was leveling, I realized there was an optimal moment to use my weapon skills so Tenzen and Shantotto can do their thing to maximum effectiveness. I wrote another script called mytenzen that watched certain trusts’ TP levels. When the optimal conditions (these took a while to nail down) were present, my character would use their weapon skill, an SC and MB would happen, and the mob would be dead. I spent a lot of time on this script and had a TON of fun with it. When it was good enough, I was able to level 2 characters simultaneously in different parties/zones at different levels by switching back and forth between windower instances and just making sure they always had a target.

The script did a few main things: it read the characters in my party and checked against a list of names it cared about, and what levels their TP would be for optimal execution, what level the monster’s hp would be to make using the chain worthwhile, then used a weapon skill when those conditions were met.

I was constantly reloading it to tweak things, and this got tedious fast. I realized that if I wanted to run it in two instances I couldn’t hardcode the the weapon skill names. Hardcoding would be fine with one instance because even with different jobs I could set the script params and reload it once per session. So I had to learn how to parse inputs.

Parsing inputs really was the spark that let me accelerate my scripting library.

Windower has an event trigger called ‘incoming text’ which you then parse the results of and act on conditionals. This allowed the script to be entirely event triggered, and I could do away with the dangerous recursion (a recursive loop would eventually leak all the memory and crash the windower instance because I didn’t know what the heck I was doing; I had to build a timer in that would reload the script at intervals to avoid this, and I’m not even sure that was that effective because I’d still get crashes). (Also, accidental infinite loops with no delay are fun; the client wouldn’t exactly freeze, but you’d get one frame update every 5 or so seconds.)

The other component was similar to incoming text parsing, but it parsed console inputs instead. If you prefixed the command with the addon commands you had registered, you could control the running script. So if mytenzen’s command was ten, your in-game command input would be //ten watchedcommand, where watchedcommand was a string you’re parsing for. The parser would split the string on however many spaces you wanted, then combine the rest into a single string. This is a lot like unix inputs, which give you space-separated variables accessible through $1, $2, etc. I added subcommands to set weapon skill, read weapon skill, set monster hp threshold levels, set trust TP threshold levels, execute stop, run, and test commands, and execute a special command to set a flag to ignore several conditions, which would cause the character to just spam its weapon skill whenever it had enough TP. At later levels, for skilling up, and for weapon trials, I primarily used this mode, which I called ‘fast’.

Around this time I wrote several other helper scripts: mytrader, myspellskill, myjumphelper, myweapontrial (superseded by changes to mytenzen that made it obsolete), and myalerter.

Ideas for more addons

  • myahcheck
    • Use a requests-like library (if one exists) to check and parse ffixah.com pages
  • myambu
    • Take action sets saved by character name and job that would be executed by the player at the start of an ambu instance, such as food items, buffs, targeting/following, etc.
  • mydomain
    • Detect/engage with a domain invasion target and keep critical trusts summoned
  • mysongs
    • Manage bard song rotation based on sets so that a single macro would be triggered and it would cast the next song in the cycle based on player’s and party members’ current buffs and their times (not sure you can get target party member’s timers; you’d probably have to make some assumptions about timing)
  • myspelltracker
    • Track currently-needed spells across all characters similar to how findall stores and reports inventory states from/to any character

My actively developed addons

  • mytrader
    • Trades an item to a target, which I primarily used to trade gobbie keys and later enhanced to store and reuse the current target so the only necessary input was the item name.
  • myspellskill
    • Takes a table of spells and their targets and loop through them infinitely to skill up.
    • This was later enhanced with text parsing to handle the timing rather than a static integer delay which made the loop less dangerous.
    • I also built in a fail scenario where if too many spell casts in a row were detected, the loop would terminate.
  • myjumphelper
    • Dragoon is awesome but having 4 different macros for jumps and having to constantly check those timers is not.
    • The addon had 2 tables, one for standard jumps (jump and spirit jump) and one for enmity-reducing jumps (high jump and soul jump). Standard and enmity-reducing jump commands were each given a macro. The script has the ability to check the character’s job abilities and their timers. When either macro was triggered, the first jump in the list of that type that was ready would be used. If there wasn’t one, nothing would happen. After each jump attempt a series of messages containing name and recast for each jump skill would display in the log. If a jump was ready, it would show READY, otherwise it would show how many seconds until ready.
    • This was super useful. Now I only needed 2 macros instead of 4, and got rapid feedback on timers.
    • I had other ideas to expand this for other jobs, but I never worked on it. I would have called it mybuffs.
  • myweapontrial
    • Send a weapon skill command when the player had enough TP and a target, which mytenzen was later able to handle.
  • mytenzen
    • Covered above.

Fading out

All this time I was doing dual-box Ambuscade runs nearly every day; I was tired of doing one round at a time for 200-900 points (900 if on Chi and lucky and had a seal active), so I decided to level Bard and White Mage for all of my mules in order to group with others for runs. I leveled WHM for all characters exclusively through power leveling with the opposite account on Escha Ru’Aun aerns and xzomits during the bonus XP campaign. This went fairly fast, but was ultimately the last grindy thing that made me want to stop playing.

What really got me in the end was the compulsion to grind based on the campaign schedules and the feeling that I was losing opportunities constantly because there were too many events happening simultaneously.

I also kept thinking, as is what usually happens, that if I just got this one last accomplishment, I wouldn’t have to grind as much any more, but then would realize that the thing I was preparing for is also grinding, and so would lose motivation/interest. When I was actively gaining points, I was fine, but when I was in between, managing inventories and planning skill progressions, I would get this feeling of pointlessness.

This feeling was especially strong last weekend when I spent several sessions just clearing out and organizing the inventories of all 8 characters. If I played again I’d only have one account for as long as I could stand it, and on that account I’d only have a max of 2 characters, one for handling sales and offloading junk to, the other for actually progressing. I’d also try harder to be helpful to other players and build team activities into my play schedule/goals. I can count on my hands the number of times I actually grouped with someone this time through the FFXI cycle, and only one time where I actually needed that group to clear the target we were working on (Omen).

Closing

I must say that even though this may not have been the best use of my time, and I did a poor job managing my life and sleep schedule, I am glad I had the motivation to learn Lua. Who knows if I’ll ever use it, but that journey of learning a new useful tool is always pretty satisfying.