Wednesday, August 31, 2011

Bringing a Knife to a Pudding Feed

Results of trial run: TPK.

Details: The borg got into a fight it thought it was supposed to win in the Tower of Babil. This might have been fine, but Rydia was set to defend instead of summon, and we got into a fight with three of those white marshmallow things that are essentially immune to physical attacks. Lost at the end of a long, embarrassing fight.



The real problem here was that the borg thought it was supposed to fight in the first place. It had just entered a room with a monster-in-a-box treasure chest. The convention up to this point has been: Walk into a room with a monster-in-a-box, switch from running to fighting, open the chest and fight, switch from fighting to running. Most of the time this works, even though it picks up the occasional extra fight on the way to the chest. But if we get into one of these fiddly fights that require a specific strategy, that could put us in trouble.

Solution: Our GetLoot:[Item Name] and GetAccessibleLoot commands now switches to fighting mode when opening a treasure chest, and back to whatever our strife specibus was before after the treasure chest is open. Not only does this avoid trying to win unnecessary fights, but it also cleans up our command queue in a few places.

Tuesday, August 30, 2011

Couldn't You Just ... You Know ...

Results of Trial Run: Battle state bug.

Details: We were fighting one of the Behemoths on the way to Bahamut, and Rosa ran out of arrows. Her default command was still Aim, and we don't know how to cancel out of trying to use disabled menu options, so we just sat there while Rosa fiddled with her bow trying to figure out how to Aim with no arrows.

Solution: I don't feel like solving the disabled menu option problem; we're already avoiding it when a caster is unable to cast spells. Just changed Rosa's default command to Defend in this section.

Sleeping Under the Stars

Results of trial run: Inventory management problem.

Details: We had no tents left when we went to use one after the first Scarmiglione fight. I have no idea how this happened, but it's easy to fix; we're buying two tents earlier on now.

Really More of a Taupe Elf

Results of trial run: TPK.

Details: Lost to the Dark Elf. Tellah's first Tornado in the second stage failed. The second Tornado connected, but again, we were too busy using Phoenix Downs to deliver the final blow. We really need someone dedicated to striking during the second stage.

Solution: Cecil no longer casts Cure on Tellah during the second stage of the fight. Since we're still Covering him, this should work okay.

Der Dunkelelfen

Results of trial run: TPK.

Details: Lost to the Dark Elf.


Everything goes great during the first stage. Then he turns into a dragon and hits Tellah for more than his maximum HP. We do eventually get him alive long enough to deliver a Tornado, but then everyone is too busy using Phoenix Downs to poke the Dark Elf once in the ribs, and we get Dark Breathed down.

Tellah going down in one hit made me really sit back and reconsider what needs to happen to make this a reliable fight. I still really, really don't want to have to add another level grind before the the Golbeze fight.

Solution: So what else can we do? Well, maybe we can increase his armor rating. I added some commands back in Baron to buy him a Kenpou and Bandanna; that raises his armor a little bit, but not by a whole lot. However, there's another solution that I don't normally consider; Cecil's Cover command. Firing that off once at the beginning of the fight makes Tellah very, very hard to kill in stage two, assuming he isn't near dead from a Tornado in stage one.


A Journey of a Thousand Miles Often Ends Very, Very Badly

Result of trial run: TPK.

Details: Made it all the way to Zeromus and lost.


We simply got Big Banged more than the party can handle. No, stop it, this is serious. The real problem was that I thought I could cut down on MP usage by having Rosa default to Cure 3 and use Cure 4 if anyone is even moderately injured. This is insufficient; without a human behind the wheel or writing some code to estimate when the next Big Bang is coming, we need it to be Cure 4 all the time.
Solution: Rosa's default command is to use Cure 4 on everyone, and the conditional Cure 4 command is gone.

Slow and Steady Wins a Brace

Results of Trial Run: TPK.

Details: Lost against the Giant CPU.


Our strategy up to this point has been for Rydia to spam Bahamut, Cecil and Edge to attack, and Rosa and Fusoya to provide healing. Everyone is on Phoenix Down duty, and Cecil is in charge of using Ethers when casters get low on MP. Most of the time, this works just fine for this fight. The problem comes if the CPU chooses Rosa and Fusoya for its insta-kill attack before bringing it's bits back. If that happens, then we get into a situation where we bring Rosa and Fusoya back just in time to get lasered down by the Attack System, and the rest of the party withers away waiting for a healing spell that will never come.

Solution: After some deliberation, I decided to rewrite the strategy for this fight to the much more boring but much more reliable track: kill just the Defense System and then peck away at the CPU with melee, periodically healing from laser damage. It's boring, but it means the CPU never uses its insta-kill attacks because we never kill the Attack System until the end of the fight.

Packrat

Results of trial run: Inventory management failure.

Details: We tried to buy a Kotetsu for Edge at the Summonville weapon shop, but our inventory was full. Looks like we just got a little bit junk on this run than we normally do.

Solution: Added a SellGarbage command and a SortItems command before buying anything in Summonville. Also, it looks like we weren't loading the mid-game garbage list during the Summonville milestone, so I added that as well.

Monday, August 29, 2011

Traffic Jams

Results of trial run: Pathing/routing failure.

Details: This is where the borg got stuck:


The obvious problem is that our party is trying to walk North, and we've managed to pin an NPC between us and the stairway to the North. However, to really understand everything that's going on here, you're going to need to know more about how FF4 maps and mobile NPCs work.

Every map in FF4 that isn't an overworld map has a byte of layer information for each tile of the map. This layer info helps the game know which tiles you can walk on and when. To help visualize this, here's a picture of the save room in the Antlion's Den:


And here's an ASCII representation of the movement layers of that map:
                                 
   ###                           
  #,,,T#                         
 T,,__,_#                        
 #,,##_#                         
 #,##._.#                        
 #,.....T                        
  #.#.#.#                        
  #..S..#                        
  #.#.#.#                        
  #.....#                        
   ##.##                         
     +                           
                                 
  • Pound signs (#) are layer 0 - obstacles. These are never passable under any circumstances. The capital Ts are actually layer 0 as well, but I've marked them differently because they contain treasures.
  • Periods (.) and commas (,) are layers 1 and 2 respectively. Both can be walked on, but you can't step directly from layer 1 to layer 2 and vise versa. To get between them, you need to step onto layer 3, which is represented here by underscores (_). Layer 3 acts as a connecting layer - you can always step on and off of it.
  • Save points (S) are layer 11, but they are essentially always accessible.
  • Layers 17 and 19 represent transition squares - if you step onto one of these, you'll end up on a different map. I've chosen to mark these with plus signs (+) and greater than signs (>) respectively. Layer 17 is only accessible from layer 1. Layer 19 can be reached from anything.
  • There's one other layer, layer 5, that acts as a bridge layer. You can always step on a bridge layer from layer 1 or 2, but when you leave the bridge you have to step off onto the same layer you entered on. This allows bridges that can be walked over or under, with different rules for where you can walk for each.
So that's how the movement rules work.  Except that that's only how they work for the player, which is where our movement bug comes in.

When the borg chooses a path to a destination and starts moving down it, at every step it checks for NPCs in the way. If someone's in the way, it checks to see if the NPC would get pinned in the players path if we took the next step. If so, it politely waits until the NPC moves out of the way before moving forward. Without this politeness, all too often the borg would get itself into situations like this:


Our destination is the square the NPC is standing on, they have no way to get out of the way, and the borg doesn't know how to solve the situation. The borg eventually gives up and panics.

The problem the borg ran into in this last run is that NPCs don't have the same movement rules as the player does. NPCs are restricted to either layer 1 or layer 2; they can't transition to any layer other than the one they started on, including layer 3. So when you have a map like the top floor of Summonville, whose movement layers look like this:

             ########                  
        #####........#                 
       #.......#####.##                
      T........#   #...#               
    ##..######>#   #...##              
   #...#     #.#######...#             
  #....#     #.......#...#             
  #...#       ######.###..##           
   #.#              T  #....#    
   #_#                 #....#    
   #.T####              ##.#           
   #......#####          #_#           
    #..........#     ####T.#           
    #..........#    #......#           
     ###....>..#   ##......#           
        #......####>#......#           
         ##.####....##.####            
          #_####....##_#               
          #.............#              
           ###.........#               
             #........#                
              ####T###              


...there's a few opportunities scattered about for the borg to pin an NPC in a place that it believes the NPC can escape.

Solution: The borg method that looks for a way for an NPC to escape the player's path, pathToAvoidPlayer(), now starts with all layer 3 tiles on the current map blacklisted. This gets us 99% of the truth for NPC mobility, and should help us avoid any more pinned NPCs.

Mute Shenanigans

Results of trial run: TPK.

Details: Lost the Golbeze fight. Rosa had Silence carried over from the Calcabrena fight, and even though we had purchased 10 Echo Herbs right before this, there were none in our inventory.

Problems with the Calcabrena/Golbeze fights are a bit harder to debug. With most fights, I record a save state right as the fight begins, so if there's a problem and we lose, I can replay with the current strategy and see exactly what happened. This one, however, is a two-part fight, and the real cause of the problems is almost always in the Calcabrena fight, which gets trampled over when the Golbeze fight starts. This situation is also unusual because the Golbeze fight is one of those exceptions where the borg generally fares better than a normal player. It's actually possible to have all 4 party members back on their feet, and have Yang get in a strike before Rydia steps into the battle, all because the borg is able to input commands so quickly. So if the borg loses here, it's because we ended the Calcabrena fight in a rotten situation.

The root of the problem lies in how status flags are handled in FF4. Some status ailments are wiped when a character dies. Others, it turns out, are not, and Silence is one of those. As far as I can tell, two things were happening:
  • When Rosa would get killed in the fight and then brought back with a Phoenix Down, she still had the Silence status and couldn't heal party members.
  • In the strategy for these fights, our conditional battle command to use an Echo Herb on anyone with the Silence status comes before the command to use a Phoenix Down on dead party members. I can imagine Cecil, Kain, and Yang all huddled around Rosa's lifeless body, urgently mashing Echo Herbs into her mouth and manually moving her jaw to make chewing motions, all the while whispering: "Please. Please heal us." All with a horrifying, 12-foot tall animated doll standing behind them. Unfortunately, using an Echo Herb on a dead character doesn't remove Silence from them, but it does consume the item.
Solution: The AllyWithStatus and AllyWithoutStatus targets now only look at live characters.

No One to Blame But the Toroians

Results of trial run: TPK.

Details: Lost the Magus Sisters fight. Don't have any single dominant cause for the loss. We ran out of Hi-Potions. Tellah's reflect casting killed a lot of allies. Things just didn't go very well.

There's a few different ways we could solve this:
  • Teach Tellah/Cecil to cast healing spells on injured party members that don't have Reflect at the moment.
  • Level grind before the fight.
  • Come up with a source of more Hi-Potions.
I really, really want to avoid level grinding for the mid-game boss streak. They're all beatable without it. I'd also like to avoid commands in battle that take more than one condition; I'm sure I'll want them eventually, but I'd like to see how far I can get just allowing one condition. And finally, Hi-Potions can't be purchased at this stage in the game, so I'm stuck with the supply I find in treasure chests or from enemy drops. Farming them would essentially amount to level grinding.

Solution: After reviewing the atlas for sources of Hi-Potions, I made a discovery; we were never actually looting the room in Toroia with like 16 treasure chests, and it has 2 more Hi-Potions. Added that to the command queue after beating the Dark Elf. That should give us a bit more survivability for that fight.

Sunday, August 28, 2011

L'elfe Noir

Results of trial run: TPK.

Details: Lost to the Dark Elf. Random seeds lined up to create a beautiful test case for the current strategy; the elf almost exclusively hammers Tellah throughout the fight, and Tellah's first casting of Tornado failed in the second stage. Couldn't pull it together after that.

Solution: Cecil now has commands to cast Cure on Tellah during the second stage. It works for this iteration, but I'm not convinced this will be enough for this fight.

Furiously scrabbling for a save point

Results of trial run: Shameful TPK while trying to run from a fight.

Details: Party died out trying to run their way to the save point right before the Magus Sisters. I didn't have any Recovery commands between the Flame Dog fight and the save point.

Solution: I don't feel like adding a Recovery interrupt right now. Just sprinkled some Recovery:0.6 in the navigator commands to help make sure we survive to the save point.

Saturday, August 27, 2011

It Burns

Results of trial run: TPK.

Details: Lost the Flame Dog monster-in-a-box fight. Tellah didn't have enough juice to cast Ice 3 or heal party members, and everything went to hell in a handbasket. The real problem was that he blew his MP casting Cure 4 twice right before the fight.

Solution: This seemed like a good time to teach the Recovery state when to cast Cure X on an individual and when to cast it on the whole party. The rule is now: If more than one party member is below the HP threshold, cast the given healing spell on everybody. If only one is below the threshold, just cast it on them. We could still be smarter about it and not always use the most expensive Cure spell available to the caster, but this will still make a big difference, and in most parts of the game, it won't really matter that much.

Can't Cure Cowards

Results of trial run: Battle state bug.

Details: Young Rydia saw that Gilbert was very, very low on HP during our Damycam level grind, but he managed to go into hiding before she got her command off. The borg had been sitting there furiously trying to move the cursor to Gilbert's position for a few hundred thousand frames when I came to check on it.

It surprised me that this bug hadn't come up before for Gilbert; his cowardice is almost as legendary as his impotence as a fighter. I certainly had run into a similar problem with Kain a while ago and adjusted targeting to compensate. However, after some thought I decided this really would be a rare occurrence with our current game strategy; Gilbert has a low chance of being in critical condition during the level grind, he just defends during the Antlion fight, and I think after his fateful solo fight in Kaipo he doesn't automatically hide anymore.

Solution: I already had taught the borg that anyone with the Jump flag isn't targetable (just Kain in this game). Adding Hide to that logic was pretty trivial.

Birds, Pursuing of

Results of trial run: Pathing/routing bug.

Details: So I come back to check how the borg is doing this time around, and I'm greeting with this:



This bird is just sitting there staring at me, as if to say, "What now, asshole?"

It turns out that we managed to catch a regular Chocobo instead of a White Chocobo right at the end of the Mount Ordeals level grind. Early on in development I expected this to happen a lot, but this is the first time we've actually talked to the wrong bird.

Solution: Refactored the movement state a bit. Commands to bump in a certain direction now have a much shorter cooldown than normal movement commands. In the process of refactoring, I also discovered a long-present bug with cooldowns that was probably responsible for jumping the gun on movement between commands. To test this, I set up commands to walk into a Chocobo forest and run laps between talking to the White Chocobo and touching a point in the corner of the clearing. We're much more successful at catching fast moving birds now; before we would often have to follow it around a few squares before managing to talk while it's still in front of us.

Dreaded whitespace

Results of trial run: Game crashed.

Details: Game consistently crashed right after getting to the cutscene where the Red Wings bomb Damycam. After poking around for a while, I finally discovered the problem; there was a trailing space after the filename for the Damycam command queue. Up to this point, my command queue parser hadn't been stripping white space from the end of commands, and hadn't been verifying file handles before trying to use them. I ran into the problem a few times before, but usually caught it pretty early.

Solution: Finally broke down and wrote code to strip whitespace from the ends of commands. Also, checking to see if we were actually able to open the target file of LoadGoals, and panicing if we can't.

Can't get to Chocobo forest from there

Results of trial run: Pathing/routing failure.

Details: The borg made it to the Underworld level grind, and then tried to find a path to the Mount Ordeals Chocobo Forest. Apparently, I failed to call ClearGrindRecovery after the last level grind. Added that in, and reviewed the other level grinds to make sure they clear their recovery loop when they're done.