Adventures in Hacking
My interest in ROM hacking is less about making a fan game and more about exploring what's going on under the hood in the Pokemon games, going places you're not supposed to go, and making minor quality of life tweaks. This is a place to document my discoveries and silly experiments.
pokeemerald
Behind The Daycare Center
Have you ever wondered what was going on in the daycare center? Did the grass have Pokemon in it or was it just aesthetic? What if you could talk to the Pokemon, would the game crash? If you remove the gates, you can just walk in. You can indeed encounter wild Pokemon in the grass, and it's the same as elsewhere on the route. As for the Pokemon sprites, you cannot interact with them; some of them just twirl around and others stay static. Additionally, if you walk to the top, you can see that the area looks 'unfinished' with half trees. The developers clearly expected that the viewport would never cover that area (and in normal gameplay, it never would), so they didn't bother cleaning it up.


Infinite TMs
If you are using the pokeemerald build, you can prevent TMs from disappearing after use. Go to party_menu.c
and comment out the code after AdjustFriendship.
static void Task_LearnedMove(u8 taskId) { struct Pokemon *mon = &gPlayerParty[gPartyMenu.slotId]; s16 *move = &gPartyMenu.data1; u16 item = gSpecialVar_ItemId; if (move[1] == 0) { AdjustFriendship(mon, FRIENDSHIP_EVENT_LEARN_TMHM); // if (item < ITEM_HM01_CUT) // RemoveBagItem(item, 1); } GetMonNickname(mon, gStringVar1); StringCopy(gStringVar2, gMoveNames[move[0]]); StringExpandPlaceholders(gStringVar4, gText_PkmnLearnedMove3); DisplayPartyMenuMessage(gStringVar4, TRUE); ScheduleBgCopyTilemapToVram(2); gTasks[taskId].func = Task_DoLearnedMoveFanfareAfterText; }
Change Starters
Go to starter_choose.c
and find the code below. Replace the starters with whichever Pokemon you want, prefixed by SPECIES_. For example, I replaced Mudkip with SPECIES_MAGNEMITE
.
static const u16 sStarterMon[STARTER_MON_COUNT] = { SPECIES_TREECKO, SPECIES_TORCHIC, SPECIES_MUDKIP, };
Stop the old lady from healing you too much
On Route 111, there is an old lady in a house who will heal your Pokemon. Normally when you talk to her, after she heals you once, she then offers to heal you again. If you mindlessly press A, you can end up continuing to heal. This is pretty funny, but it can be a little annoying. Commenting out the following in Route111_OldLadysRestStop.inc
will skip this:
Route111_OldLadysRestStop_EventScript_Rest:: msgbox Route111_OldLadysRestStop_Text_TakeYourTimeRestUp, MSGBOX_DEFAULT closemessage call Common_EventScript_OutOfCenterPartyHeal // msgbox Route111_OldLadysRestStop_Text_StillTiredTakeAnotherRest, MSGBOX_YESNO // goto_if_eq VAR_RESULT, YES, Route111_OldLadysRestStop_EventScript_Rest // goto_if_eq VAR_RESULT, NO, Route111_OldLadysRestStop_EventScript_DeclineRest end
Bike indoors
Tired of not being able to bike indoors? Get rid of that pesky code that checks if you're indoors or not. Go to item_use.c
.
void ItemUseOutOfBattle_Bike(u8 taskId) { s16* data = gTasks[taskId].data; s16 coordsY; s16 coordsX; u8 behavior; PlayerGetDestCoords(&coordsX, &coordsY); behavior = MapGridGetMetatileBehaviorAt(coordsX, coordsY); if (FlagGet(FLAG_SYS_CYCLING_ROAD) == TRUE || MetatileBehavior_IsVerticalRail(behavior) == TRUE || MetatileBehavior_IsHorizontalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedVerticalRail(behavior) == TRUE || MetatileBehavior_IsIsolatedHorizontalRail(behavior) == TRUE) DisplayCannotDismountBikeMessage(taskId, tUsingRegisteredKeyItem); else { // only comment out the Overworld check. Commenting out 'isBikingDisallowedByPlayer' will cause you to bike while surfing - interesting but it messes with the surf code and prevents you from dismounting from surf. if (/*Overworld_IsBikingAllowed() == TRUE &&*/ IsBikingDisallowedByPlayer() == 0) { sItemUseOnFieldCB = ItemUseOnFieldCB_Bike; SetUpItemUseOnFieldCallback(taskId); } else DisplayDadsAdviceCannotUseItemMessage(taskId, tUsingRegisteredKeyItem); } }
Also alter the code in overworld.c
so that entering a building does not force you to dismount:
static u8 GetAdjustedInitialTransitionFlags(struct InitialPlayerAvatarState *playerStruct, u16 metatileBehavior, u8 mapType) { if (mapType != MAP_TYPE_INDOOR && FlagGet(FLAG_SYS_CRUISE_MODE)) return PLAYER_AVATAR_FLAG_ON_FOOT; else if (mapType == MAP_TYPE_UNDERWATER) return PLAYER_AVATAR_FLAG_UNDERWATER; else if (MetatileBehavior_IsSurfableWaterOrUnderwater(metatileBehavior) == TRUE) return PLAYER_AVATAR_FLAG_SURFING; // else if (Overworld_IsBikingAllowed() != TRUE) // return PLAYER_AVATAR_FLAG_ON_FOOT; else if (playerStruct->transitionFlags == PLAYER_AVATAR_FLAG_MACH_BIKE) return PLAYER_AVATAR_FLAG_MACH_BIKE; else if (playerStruct->transitionFlags != PLAYER_AVATAR_FLAG_ACRO_BIKE) return PLAYER_AVATAR_FLAG_ON_FOOT; else return PLAYER_AVATAR_FLAG_ACRO_BIKE; }
Crystal
Tile Size
I had always believed that tiles were small - about the size of the door or the player character. However, they are actually 4 times as large, as you can see in the map editor below. This large tile size explains certain design choices, such as the weirdly empty gate near the exit to the town.
