19 — Playing My Own Game

A dedicated play session turned up a list of things to fix.


The Bug Report

The last few sessions were heavy on infrastructure — CI tests, offset verification, code audits. Good work, but not the kind where you sit down and actually play through the game. So this session was reserved for that. Start screen, new game, walked around, triggered battles, opened menus. Within ten minutes I had a list.

The first item on the list: the Town Portal crashed the game. Not a soft crash. Hard. The debug warp worked fine — that path calls SetMainCallback2(CB2_LoadMap) before fading. The EMBER submenu portal skipped that call entirely. A one-liner fix, but the kind that only shows up when you actually use the feature.

Second item: I ran into a level 13 Meowth as my second wild encounter out of Pallet Town. Treasure Pokémon — a 5% chance encounter with an Epic+ gear drop — were spawning immediately, before the player has any business fighting a level 13 anything. The fix was simple: require at least 2 badges before Treasure Pokémon can appear. Now they show up around Vermilion, which is about right.

Third item: the EMBER stats panel was cluttered. STREAK, GEAR, and a 0/3 QUESTS counter were visible from the very first step out of the lab. None of those mean anything until deep into the game. STREAK needs battles to exist. GEAR needs items to find. QUESTS shouldn’t show a counter when you have no quests. Cleaned up the display logic so each element only appears when it’s relevant.

Launching the Wiki

The site has had a devlog since day one, but nothing explaining how the game actually works. A new player (or my own future self) would have no idea what gear rarities exist, how corrupted zones work, or what the Altar of Recrafting does.

I wrote 9 wiki articles covering the core systems: gear, relics, shards, combat mechanics, the loot economy, corrupted zones, quests, merchants, and the Rift. Combined them with the devlog under a single site with a unified header nav. Both sections are now at the same URL with tab-switching between them.

The wiki doesn’t need to stay in sync with every commit — it’s a snapshot, not live documentation. I’ll update it when systems meaningfully change.

Getting Out of the Bedroom

The vanilla FireRed opening is a seven-minute cinematic: wake up, watch TV, walk down stairs, trigger Oak on Route 1, get stopped, walk back, sit through a four-person dialogue about choosing starters. Every single time you start a new game.

I cut all of it. New game now starts in Oak’s Lab, directly in front of the three Poké Balls. One custom dialogue box — “Ancient Ember awaits” — then you pick your starter. The bedroom, the Route 1 trigger, the lab walk-in animation, Oak’s four-box speech, the rival’s interruption: all gone.

This required some careful flag surgery. The EventScript_ResetAllMapFlags call that fires on new game sets FLAG_HIDE_OAK_IN_HIS_LAB, so Oak would be invisible without an explicit FlagClear immediately after. The outdoor Oak coord events needed to be removed from map.json (source of truth, not the generated .inc file). The starter scene had two paths — the cinematic one we removed, and the national dex scene used in post-game. Those shared some movement scripts, so the national dex path needed to be preserved even while gutting the intro.

222 lines removed.

No Tutorial Battle

The first rival battle in Oak’s Lab has a special mode: BATTLE_TYPE_FIRST_BATTLE. When set, Oak narrates the fight with voiceover prompts (“Inflicting damage is key!”), crits are suppressed, accuracy checks auto-pass, and running is blocked with a Birch speech. It’s a full tutorial harness bolted onto the battle engine.

I removed it. The rival battle is now just a normal trainer battle. You fight, you win or lose, life goes on.

Removing the flag cleanly required touching eight files — battle_setup.c, battle_controller_player.c, battle_controller_opponent.c, battle_controllers.c, battle_main.c, battle_script_commands.c, battle_bg.c, and a battle script. The dead branches in battle_controller_oak_old_man.c came down in a follow-up audit.

The Dead Code Audit

With the tutorial gone and BAG moved out of the start menu, I did a comprehensive sweep of everything that was now unreachable.

From the BAG removal: STARTMENU_BAG enum entry, its action table row, StartMenuBagCallback, the help text string, the extern declaration. All gone.

From the tutorial removal: BATTLE_TYPE_FIRST_BATTLE branches across battle_controller_oak_old_man.c (9 dead conditionals). Then the functions those branches called: OakOldManHandleInputChooseMove, three PrintOakText_* functions, BtlCtrl_OakOldMan_TestState2Flag/SetState2Flag. Then the party menu tutorial chain: 10 Task_FirstBattleEnterParty_* functions, their helper functions, the Oak voiceover window template, two Oak speech strings. Then the declarations, the flag defines, the bit definition itself.

529 lines removed in a single commit. The BATTLE_TYPE_FIRST_BATTLE bit is now vacant — a gap between bit 3 (TRAINER) and bit 5 (LINK_IN_BATTLE).

Hold to Scroll

Every list UI in the game — gear bag, forge, altar, merchant, chest, portal, Pokédex — required a separate button press per row. On a 40-item gear bag that’s exhausting.

GBA’s gMain.newAndRepeatedKeys fires on fresh press, then again after a 40-frame delay (≈0.7s), then every 5 frames (≈83ms) while held. All I had to do was replace JOY_NEW(DPAD_UP/DOWN) with a JOY_REPEAT macro across 8 files. Eight sed commands.

BAG in the EMBER Menu

The start menu had both BAG and EMBER sitting next to each other. BAG opened the item bag. EMBER opened a submenu with gear-specific tools. It made more sense to put BAG inside EMBER — one fewer top-level menu item, and the two bag options live together.

EMBER submenu now has five items: GEAR BAG, BAG, CODEX, PORTAL, DEBUG — all caps, consistent with GBA menu convention. The submenu window grew from 8 tiles tall to 10 to fit the extra item, and the stats panel’s VRAM baseBlock was shifted from 0x26D to 0x281 to avoid overlap.


By the Numbers

Metric Value
Commits 16
Copilot requests 18
Tool executions 537
Sub-agents spawned 3

Good session. Now I need to play it some more.

Back to README