Like I said on Monday, I spent the weekend dicking around with Final Fantasy X and Cheat Engine. I learned a few fun things, a few annoying things, and a few curious things. So let’s talk about it…
For those who don’t know, Cheat Engine allows you to rummage around in the memory of a running program and change values at will. If you can find the memory location where the game stores (say) your hitpoints, then you can edit that value to be whatever you like, at any time.
You’re just changing single numbers in memory, which may or may not be helpful. It all depends on how the game was coded. If I just change my character level but I don’t change my hitpoints, strength, weapon damage, or other related values, then maybe I’ll be exactly as strong as I was before. Or perhaps I change my hitpoints from 300 to 1,000,000. Then someone hits me with a healing spell, which adds 50 hitpoints to my total, and in doing so the game ends up executing some code that pulls my hitpoints back down to where they belong. Maybe a boss fight is balanced so that the bad guy always has $MY_HITPOINTS × 2.25, so by giving myself a million hitpoints I’ve actually made myself weaker in a relative sense. So then maybe I change the HP of the boss to zero, and then the game does a calculation like $SOME_VALUE / $BOSS_HITPOINTS, which causes a divide by zero error and crashes the game.
Some changes will have no effect. Some changes will have an effect but it may be undone at any moment. Other changes my have a huge effect but may also have unpredictable negative side-effects. And some changes might crash the game, corrupt your save, or cause inexplicable glitches. It all depends. Some games take these instantaneous modifications in stride and some malfunction.
Final Fantasy X
Anyway. I played Final Fantasy X while using Cheat Engine. I gave myself rare gear, crafted impossible items, changed the contents of the sphere grid, and otherwise did a bunch of crazy stuff just to see what would happen. I will say that FFX is surprisingly resilient and took my tomfoolery in stride.
There are several moments in the game where you’re supposed to fail at something in battle so that another character can explain how the mechanics work. This is particularly true in the early game. For example, some creatures have hard armored shells. You’re supposed to take a swing at them with main character Tidus, do some pathetic damage, and then one of your companions will explain that you’re supposed to use the character Auron to deal with these creatures. If you cheat Tidus up to end-game power levels, then you’ll get this:
*Tidus smacks the monster for 99,999 damage. The monster only has 325 HP, so this is massive overkill. It falls over dead.)
(Makes a disappointed / confused sound, as if his attack did nothing.)
Let Sir Auron handle those creatures.
Oh okay. Got it!
(There’s an awkward pause where our heroes stare at the empty battlefield for a few seconds and then the victory music plays and the battle ends.)
I’ve run into several variations of this problem at different times. When you first arrive at Sanubia Sands, there’s a scripted battle where you’re supposed to be outmatched by a large bird and then Auron and Lulu show up to bail you out. This bit also gets a little weird if you can solo the bird before they show up.
Despite all this, the game never got stuck. It never crashed. I never got softlocked in a battle that wouldn’t end. The worst that would happen was that the dialog would be inappropriate, or there would be an awkward pause.
When you meet the character Kimarhi, he’s supposed to attack Tidus for a short one-on-one bttle. Then once he’s given Tidus a bit of a thrashing, the rest of the group jumps in and tells him to back off. After this, he becomes a member of the party.
But if you’ve leveled Tidus up to the point where he can one-shot Kimarhi, then the game doesn’t know what to do. There’s an awkward silence like someone forgot their lines. Then the battle just ends, but Kimarhi doesn’t join your party. At first I thought this meant that I was going to miss out on Kimarhi this game. But then after a short boat ride we arrived at the next island and he simply appeared in the party roster without comment.
You can tell this is a console port by the odd way everything is packed into memory. In your inventory, item stacks are limited to 99, so you can never have more than 99 of any item. This is because the item stacks are stored as a single byte value. I suppose this means that the game could technically allow stack sizes of 255, but I guess someone decided a value of 99 would feel more natural. (Also, limiting stacks to two digits lets you make the numbers larger, which makes it easier to read on your blurry low-res late-90s CRT screen.)
If I was programming an inventory system, I’d probably store items and stack sizes together. Like, two bytes would store the ID of the item, and then a third byte would store how many of them I owned.Actually, I’d be lazy and decadently spend four bytes on each variable. It’s 2021. Worrying about the memory footprint of the player’s inventory these days is like trying to lose weight by trimming your fingernails. But in FFX these things are stored in two separate blocks. I’m reasonably sure your inventory is designed to take up a fixed amount of space in memory, regardless of how much or how little you might be carrying.
So you have a block of item IDs, all packed together. Each ID is two bytes. Then after the list is a gap, which pads out your inventory to a fixed size.
I don’t know how many different items are in the game, but for the sake of argument let’s say there are 200.To be clear, we’re talking about your inventory of consumables here. Potions, remedies, megalixirs, grenades, power spheres, etc. Your inventory of weapons and armor is stored elsewhere, and uses a completely different system. And let’s also say that the player currently has 15 different items. So we would end up with 15 item IDs, then 185 items worth of blank space.
After the item IDs is a list of the stack sizes for each of those items.
This probably seems like a weird way to store stuff. Certainly a human writing on paper would store item names and item counts together. If you were taking inventory you’d write “10 Apples, 2 Pears, 1 Bananas, 9 Kiwi”. You wouldn’t write “Apple Pear Banana Kiwi” on one piece of paper and then “10, 2, 1, 9” on another. But as strange as this seems, this sort of thing is pretty common in programming.
So why pad out the list? This is handy for severely memory-constrained environments. Having fixed sizes for everything is really helpful. Yes, maybe it seems a little wasteful to reserve space for 200 items if we only need 15. But the important feature here is that no matter what happens, we’ll never wind up with more than 200. We don’t need to worry about some strange bug creating space for 10,000 items and trying to save it to the user’s memory card.
Hey, have you ever noticed how big Skyrim save files are? I don’t know why I brought that up. It just popped into my mind just now.
There are several blocks to your save data. One is your inventory, as discussed above. Another block keeps the counts for how many monsters you’ve captured of each type for the monster arena. Another block is your blitzball team, and another is your character stats. And so on. Yes, you could design it so that a block isn’t created until it’s needed. It could leave out the blitzball stuff until you play your first game and it could leave out the monster capture stuff until you capture your first monster. But then the save file would be variable size. By making sure the save file is always maximum size, you also ensure that there will never be some strange circumstances that takes it above some hard limit. “Oh, we didn’t realize if you do these sidequests in this order and hoard all these items and then collect these rare items that the save file will get bigger and take an extra block on the memory card.”
During my diatribe on Blitzball, some people theorized that the outcomes of certain interactions were pre-rolled, and that the AI was able to peek at these outcomes. At the time this sounded kind of implausible, but after cheating my way through a Blitzball game I have to say it makes a lot of sense.
See, Blitzball is a mostly turn-based game. Let’s say you’ve got the ball, and you get pulled into an encounter with 3 defenders. While the defenders are all spread out in front of you visually, for gameplay purposes they form 3 concentric rings around you. You must somehow get past all three people, regardless of what you plan to do or which way you go. Even if you want to pass to someone behind you, the game will act like these three guys are stacked up in a conga line between you and your goal.
Let’s say the three defenders are named Abe, Betty, and Carl. You will need to deal with them in this specific order. You can push past Abe, and then throw the ball. Betty will have a chance to grab it. If she doesn’t, then Carl will have a chance. Or you can push past Abe, then push past Betty, and then throw it and Carl will try to grab it.
So you have a choice: How much do you want to rely on your ability to overpower people, and how much do you want to rely on your throwing arm? If you’re controlling a real bruiser of a character then maybe you’ll push past everyone and just swim away with the ball. If you’re controlling a good passer then maybe you’ll skip the fisticuffs and try to throw the ball past them.
If you choose to throw, then it’s your Passing ability vs. the Blocking ability of everyone else. Like, you have a pass of 20, then the ball leaves your hand with 20 “hitpoints”. Abe has a block of 10, so he knocks 10HP off the ball. Betty has a block of 8, so she knocks another 8 off the ball. Then Carl has a block of 5. The ball runs out of HP and therefore Carl grabs it.
These values are all randomized a bit for each encounter. So someone with a block of 10 might roll a value between 8 and 12.
So if you’ve got a pass value of 20 and the three defenders have a combined block value of 26, then it’s technically possible to throw past them if you roll well and they all roll poorly. The odds are strongly against you, but it can happen.
The thing is, the AI will sometimes make long-odds moves like this and have it work out. It will roll high, you’ll roll poorly, and the ball gets through.To be clear, you can’t really see these dice rolls. You just have to intuit what’s going on by watching the action play out. That alone wouldn’t be particularly suspicious. Ask any X-Com player and they’ll tell you: Lots of unlikely things can happen over a large number of encounters. It’s not suspicious that the dice favor the AI once in a while. What is suspicious is that the AI seems to know when a long bet will pay off. I don’t observe the AI taking crazy gambles most of the time. It usually plays very conservatively. But when it does go for an unlikely play, it pays off.
The accusation isn’t that it cheats when rolling the dice, it’s that the dice get pre-rolled and the AI is able to choose an action based on what the dice rolls WILL be.
What I Observed
Note: I didn’t record this match and I don’t remember the exact details, so I’m going to make up all the numbers and pick names at random.
So my guy Datto gets near the enemy goal, and defender Bickson stops him. I’m close enough to shoot. However, my Shoot skill is 8. Bickson has a Block skill of 5. The goalie has a block skill of 5. If I shoot from here, then Bickson will get a hand on the ball as it goes by, reducing it to 3. Then the goalie will be able to stop it.
So I jump over to Cheat Engine and rummage around in memory for Datto’s Shoot skill. This search requires a bit of detective work. Datto has several numbers that describe his properties. It’s probably safe to assume that all of his data is stored together. So I’m looking for this particular collection of numbers, all next to each other. I have to make some assumptions about how the programmer might have arranged these variables, and how many bytes of space each variable might get. And it helps if you can read hexadecimal numbers, which I sort of can.
Anyway, after many searches, I find the blitzball players in memory, and then find Datto among them.It would be SO nice if the name was stored along with the data, but alas no. You have to recognize people by their numbers. So then I reach in and change Datto’s 8 to a 90.
I jump back to FFX. Success! Datto’s shot ability is now a godlike 90.
From here, you’d expect that taking the shot would result in Bickson touching the ball and knocking 5HP off. Then the goalie will knock another 5HP off. Then the ball will land in the goal with 80HP to spare.
Instead, I take the shot. It leaves my hand with 90HP, and then Bickson touches it and the ball’s HP drops all the way to 3. The goalie catches it easily. That’s exactly what I would have expected if I’d thrown the ball with my original Shoot skill of 8.
However, sometime later Datto gets the ball again, and I once again wind up in front of the opposing goal with some defenders in my face. Datto’s Shoot score is still 90, so I don’t need to do any editing this time. I can just take the shot.
And this time it works. All the defenders touch the ball as it glides by, but their tiny block skill is no match for Datto’s superhuman Shoot of 90.
What this tells me is that when an encounter is created – when the defenders pull your player into their pocket dimension and the menu appears – the game looks at the options in front of you and rolls the dice for each choice ahead of time. Once the encounter has begun, you’re choosing which of the three predetermined outcomes you want, because the dice have already been rolled for each of them.
Imagine you’re playing D&D. There’s a monster in front of you. You can swing your sword, or you can cast a spell. The GM rolls the dice for each option and then he asks you, “Do you want this sword-stroke where you’ll roll a natural 20, or do you want this spell attempt where you roll a 3?”
That’s what the game seems to be doing. However, it’s only telling the AI what the outcomes will be. The human player has to choose blind.
I want to be clear that my little experiment doesn’t PROVE that the game pre-rolls encounter outcomes. You could devise other explanations for the odd behavior I observed. But on the whole I find this explanation the most plausible because…
AI is Hard
As a programmer, this makes some sense to me. If I’m trying to write an AI, it’s not that hard to write something that can judge between 3 known outcomes. But it’s a huge pain in the ass to write an AI that can properly balance risk vs. reward when dealing with possibility space that looks like this:
PUSH PAST DEFENDERS:
- Likely outcome of a small setback.
- Slightly unlikely outcome of an extremely serious setback.
- Very unlikely outcome of an incredible advantage.
PASS THE BALL:
- 90% chance of small setback.
- 10% chance of a large advantage.
Stuff like this is conceptually simple for humans to wrap their heads around, but it’s really hard to write code that can handle this sort of decision-making. Heck, just quantifying ideas like “Very unlikely” and “small setback” is really hard, much less coming up with code to choose between them. And that’s before you take into account the fact that the AI needs to make decisions on a sliding scale. It should be fairly conservative if it’s ahead or if the game just started, but it ought to be willing to take big chances if it finds itself losing in the late-game.
Having the outcomes of decisions pre-rolled would make it easier to code the AI. It doesn’t help you make the AI smarter, but it does reduce the risk of the AI doing something that is obviously stupid.
Now, if this was a AAA sports game then this AI shortcut would be completely outrageous. But in an optional minigame for a JRPG? Yeah, I can totally see someone cutting this corner. Particularly since I doubt anyone on the development team has expertise in this field. For the most part, the “AI” in a JRPG is incredibly simple stuff like:
- Cycle through attacks A, B, C
- When the boss health first drops below 50%, unleash attack D
- When health is below 25%, switch to rotating through attacks E, F, G.
Or whatever. The system is usually so simple that players can reverse-engineer the logic just by playing the game and observing the AI behavior. That’s fine. In the context of a turn-based game the predictability of the clockwork AI is a feature, not a flaw. A boss fight is supposed to be more of a puzzle than a chess match.
So then someone decides to put a sports game into the latest Final Fantasy, and you figure it’ll be easy because it’s built around on turn-based encounters. Conceptually, that sounds a lot like the normal encounter AI the team is used to making. And then months later someone sits down to write this code and they realize, “Oh hang on. This decision-making is super fucking difficult and I’m not sure where to start. Shit! We budgeted three weeks for this, and I don’t think that’s enough time for me to do the reading required to write the spec for this. And then I’d have to devise unit tests to judge if the AI is doing the right thing, and I don’t know how you detect it doing the wrong thing short of writing another entire AI.”
I have no proof this is what happened. I’m just saying as a programmer with very limited AI experience, I find this scenario to be extremely plausible. AI is hard, and it’s the sort of difficulty you don’t anticipate at first because the problem in question is often conceptually trivial for a human being to solve with the meat computer between their ears. It only becomes difficult when you have to express it in code. I can say “Make a cautious decision” to another human being. But then I realize I need to explain to the computer what I mean by “cautious” and I realize that word contains a tremendous amount of complexity.
Each character has an “overdrive” gauge. It fills gradually as you fight and defeat monsters. When it’s full, you’re able to unleash a powerful super-attack. Each character has their own signature overdrive.
The thing is, you never see the number that drives this gauge. I can look at the bottom of the screen and see that I’ve got exactly 2,384 hitpoints, but when I look at the overdrive meter all I can tell is that it’s “about halfway full, maybe a little less than that”. So I was curious how the programmer handled this. The problem is that it’s really hard to find something if you don’t have exact values to look for.
- You could store this value in a single byte as a simple percentage value. So the number would be 0 when empty and 100 when full.
- You could store this value in a single byte, but use all of the possible values. This would mean that empty is 0 and full is 255.
- You could store this value in 2 bytes. 0 is empty, full is 65,535.
- If you’re crazy, you could store this in a signed 2 byte value, so empty is -32768 and full is +32767. I don’t know why you’d do this, but you could. There might even be a good reason to do this, depending on the PlayStation 2 hardware and development tools.
- You could use a 4-byte floating point value, in which case empty is 0 and full is anyone’s guess. I feel like this is a bit unlikely given how frugal the rest of the code is with regards to memory usage.
I hunted for a long time for this overdrive gauge. I searched using all sorts of assumptions regarding byte size and scale, but I never found anything that worked. I did find a pair of identical values that went up as the gauge filled, but the game would overwrite any changes I made to them, correcting them back to their proper value. So the data was coming from somewhere else, and the data I found was just a placeholder or temporary value.For example, if you’re doing to draw the pixels for the gauge itself, you might derive some number of pixels to use for the bar width. This number would have no effect on gameplay, and it would be get re-calculated whenever the bar is drawn. So changing it would be pointless.
But while I was digging around for that I stumbled on an interesting bit of trivia.
The character Tidus has a number of overdrives. He starts with “Spiral Cut”, where he does a front-flip and slams his sword down on a single target. At some later point (it’s not clear to the player what causes this) he will unlock “Slice and Dice”, where he runs around the battlefield and hits foes at random. Then eventually you’ll somehow unlock “Energy Rain”, where Tidus will leap up into the air and shoot(?) lasers(?) out of his sword onto foes below. And finally, if you stick around for the long-haul, ultra-completionist 120 hour marathon playthough, you might reach the point where Tidus unlocks “Blitz Ace” where he slashes a single foe nine times with his sword, then plants his sword in the ground and uses it to launch himself into the air, then someone tosses him a blitzball and he Bicycle Kicks it into the monster’s head and no I’m not kidding all of that really happens.
So guides like this one will tell you that to unlock these overdrives, you need to use them. Using Spiral Cut 10 times will unlock Slice & Dice, using Slice & Dice 30 times will unlock Energy Rain, and using Energy Rain 80 times will unlock Blitz Ace if it doesn’t drain your will to live.
This doesn’t seem to be the case. Indeed, it can’t be the case. The game does not keep track of which overdrives you use. Those numbers aren’t stored anywhere. Instead, there is a single counter that goes up whenever you perform an overdrive. This is good news! If you believe the guides, then you need to perform 10+30+80 overdrives to unlock Blitz Ace. But no. You just need to perform 80 total overdrives. This means you don’t need to do as many, and it also means you get to use whatever overdrive suits you. You can use the awesome six-hit Slice & Dice, and you’re not obligated to use the underwhelming one-hit Energy Rain. (Number of hits becomes important in the late-late-late game when you run up against the damage cap. Yes, the game has a damage cap.)
Maybe this detail was changed for the Steam release of the game, and that’s why the online guides are wrong. I don’t know.
So that’s what I learned from cheating at Final Fantasy X. I hope you found some of that interesting. Sadly, I couldn’t find any cheats to do anything about Seymour’s hair.
 Actually, I’d be lazy and decadently spend four bytes on each variable. It’s 2021. Worrying about the memory footprint of the player’s inventory these days is like trying to lose weight by trimming your fingernails.
 To be clear, we’re talking about your inventory of consumables here. Potions, remedies, megalixirs, grenades, power spheres, etc. Your inventory of weapons and armor is stored elsewhere, and uses a completely different system.
 To be clear, you can’t really see these dice rolls. You just have to intuit what’s going on by watching the action play out.
 It would be SO nice if the name was stored along with the data, but alas no. You have to recognize people by their numbers.
 For example, if you’re doing to draw the pixels for the gauge itself, you might derive some number of pixels to use for the bar width. This number would have no effect on gameplay, and it would be get re-calculated whenever the bar is drawn. So changing it would be pointless.
I Was Wrong About Borderlands 3
I really thought one thing, but then something else. There's a bunch more to it, but you'll have to read the article.
Revisiting a Dead Engine
I wanted to take the file format of a late 90s shooter and read it in modern-day Unity. This is the result.
Push the Button!
Scenes from Half-Life 2:Episode 2, showing Gordon Freeman being a jerk.
The true story of three strange days in 1989, when the last months of my adolescence ran out and the first few sparks of adulthood appeared.
The Best of 2017
My picks for what was important, awesome, or worth talking about in 2017.