Quick Field Debug New Game - pret/pokecrystal GitHub Wiki

This ports some of the features from the Field Debug option that is present on the Japanese G/S debug ROMs. It allows you to skip the whole intro sequence, warping directly to the player's room. It also includes a fast walk option that ignores all collisions and events by holding down B.

Contents

  1. Adding the main menu option
  2. Adding Debug New Game functions
  3. Fixing overworld movement
  4. (Optional) Add comments
  5. Adding more features

1. Adding the main menu option

First edit engine/menus/main_menu.asm, replacing NEW GAME with NEW GAME DEBUG in the debug build.

.Strings:
; entries correspond to MAINMENUITEM_* constants
	db "CONTINUE@"
+ if DEF(_DEBUG)
+	db "NEW GAME DEBUG@"
+ else
	db "NEW GAME@"
+ endc
	db "OPTION@"
	db "MYSTERY GIFT@"
	db "MOBILE@"
	db "MOBILE STUDIUM@"
if DEF(_DEBUG)
	db "DEBUG ROOM@"
endc

.Jumptable:
; entries correspond to MAINMENUITEM_* constants
	dw MainMenu_Continue
+ if DEF(_DEBUG)
+	dw MainMenu_NewGameDebug
+ else
	dw MainMenu_NewGame
+ endc
	dw MainMenu_Option
	dw MainMenu_MysteryGift
	dw MainMenu_Mobile
	dw MainMenu_MobileStudium
MainMenu_NewGame:
	farcall NewGame
	ret

+ if DEF(_DEBUG)
+ MainMenu_NewGameDebug:
+	farcall NewGameDebug
+	ret
+ endc

MainMenu_Option:
	farcall Option
	ret

2. Adding Debug New Game functions

Add this code at the end of engine/menus/intro_menu.asm:

+ if DEF(_DEBUG)
+ NewGameDebug:
+	ld hl, wDebugFlags
+	set DEBUG_FIELD_F, [hl]
+	call ResetWRAM
+	farcall InitNewGameDebug
+	call ClearTilemapEtc
+	call InitializeWorld
+
+	ld a, SPAWN_HOME
+	ld [wDefaultSpawnpoint], a
+
+	ld a, MAPSETUP_WARP
+	ldh [hMapEntryMethod], a
+	jp FinishContinueFunction
+ endc

Create a new file engine/debug/new_game_debug.asm and paste the following code:

InitNewGameDebug:
	call InitRandomDebugName

; give yourself max money & coins
	ld a, HIGH(MAX_MONEY >> 8)
	ld [wMoney], a
	ld a, HIGH(MAX_MONEY) ; mid
	ld [wMoney + 1], a
	ld a, LOW(MAX_MONEY)
	ld [wMoney + 2], a
	ld a, HIGH(MAX_COINS)
	ld [wCoins], a
	ld a, LOW(MAX_COINS)
	ld [wCoins + 1], a

	call InitDebugStarter

	ld de, DebugItems
	call GetDebugItems

; pokedex
	ld hl, wPokedexCaught
	call SetDexFlags
	ld hl, wPokedexSeen
	call SetDexFlags
	ld hl, wUnownDex
	ld [hl], 1
	ld hl, wFirstUnownSeen
	ld [hl], 7

	call SetPokegearFlags

; disable Mom's Pokegear speech
	ld a, SCENE_PLAYERSHOUSE1F_NOOP
	ld [wPlayersHouse1FSceneID], a
; setting this event enables trade and link battles
	ld de, EVENT_GAVE_MYSTERY_EGG_TO_ELM
	ld b, SET_FLAG
	jp EventFlagAction

	farcall SetAllDecorationFlags

	farcall InitRoamMons
	ld a, $0c
	ld [wStringBuffer2 + 1], a
	ld a, $22
	ld [wStringBuffer2 + 2], a
	call InitTimeOfDay
	call Random
	ld [wLuckyIDNumber], a
	call Random
	ld [wLuckyIDNumber + 1], a
	ret

InitRandomDebugName:
; pick a random name from the trainer list
	call Random
	cp NUM_TRAINER_CLASSES
	jr nc, InitRandomDebugName
	ld c, a
	ld b, 0
	ld hl, TrainerGroups
	add hl, bc
	add hl, bc
	ld a, BANK(TrainerGroups)
	call GetFarWord
	ld de, wPlayerName
	ld bc, NAME_LENGTH
	ld a, BANK(Trainers)
	call FarCopyBytes
	ld hl, .RivalName
	ld de, wRivalName
	ld bc, NAME_LENGTH
	call CopyBytes
	ret

.RivalName:
	db "RED@"

InitDebugStarter:
; add a random evolved starter at Lvl 80
	call Random
	and %11
	jr z, InitDebugStarter
	dec a
	ld b, a
	add a
	add b
	add MEGANIUM
	ld b, 80
	call .AddToParty
	ret

.AddToParty:
	ld [wCurPartySpecies], a
	ld a, b
	ld [wCurPartyLevel], a
	predef TryAddMonToParty
	ret

GetDebugItems:
	ld hl, wNumItems
.loop
	ld a, [de]
	cp -1
	ret z
	ld [wCurItem], a
	inc de
	ld a, [de]
	inc de
	ld [wItemQuantityChange], a
	call ReceiveItem
	jr .loop

DebugItems:
	db BICYCLE,      1
	db OLD_ROD,      1
	db GOOD_ROD,     1
	db SUPER_ROD,    1
	db COIN_CASE,    1
	db ITEMFINDER,   1
	db FLOWER_MAIL,  6
	db MASTER_BALL, 99
	db ULTRA_BALL,  99
	db POKE_BALL,   99
	db HEAVY_BALL,  99
	db LEVEL_BALL,  99
	db LURE_BALL,   99
	db FAST_BALL,   99
	db POTION,      30
	db RARE_CANDY,  20
	db FULL_HEAL,   99
	db -1

SetDexFlags:
IF NUM_POKEMON > 7
	ld b, NUM_POKEMON / 8 ; 251 / 8 == 31
	ld a, %11111111
.loop
	ld [hli], a
	dec b
	jr nz, .loop
ENDC
IF NUM_POKEMON % 8
	ld [hl], (1 << (NUM_POKEMON % 8)) - 1 ; (1 << 251 % 8)) - 1 == %00000111
ENDC
	ret

SetPokegearFlags:
	ld hl, wStatusFlags
	set STATUSFLAGS_POKEDEX_F, [hl]

	ld hl, wPokegearFlags
	set POKEGEAR_OBTAINED_F, [hl]
	ld hl, wPokegearFlags
	set POKEGEAR_RADIO_CARD_F, [hl]
	ld hl, wPokegearFlags
	set POKEGEAR_PHONE_CARD_F, [hl]
	ld hl, wPokegearFlags
	set POKEGEAR_MAP_CARD_F, [hl]
	ret

Edit main.asm and include the new file:

SECTION "Debug Room", ROMX

if DEF(_DEBUG)
INCLUDE "engine/debug/debug_room.asm"
endc


+ SECTION "New Game Debug", ROMX
+
+ if DEF(_DEBUG)
+ INCLUDE "engine/debug/new_game_debug.asm"
+ endc


SECTION "Battle Tower Text", ROMX

INCLUDE "data/battle_tower/trainer_text.asm"

3. Fixing overworld movement

Edit the following files:

engine/events/overworld.asm:

CheckEngineFlag:
; Check engine flag de
; Return carry if flag is not set
+ if DEF(_DEBUG)
+	call CheckFieldDebug
+	jr nz, .isset
+ endc
	ld b, CHECK_FLAG
	farcall EngineFlagAction
	ld a, c
	and a
	jr nz, .isset

engine/overworld/events.asm:

CheckTrainerEvent:
	nop
	nop
+ if DEF(_DEBUG)
+	call CheckBPressedDebug
+	jr nz, .nope
+ endc
	call CheckTrainerBattle
	jr nc, .nope

	ld a, PLAYEREVENT_SEENBYTRAINER
	scf
	ret

.nope
	xor a
	ret

CheckTileEvent:
; Check for warps, coord events, or wild battles.

	call CheckWarpConnectionsEnabled
	jr z, .connections_disabled

	farcall CheckMovingOffEdgeOfMap
	jr c, .map_connection

	call CheckWarpTile
	jr c, .warp_tile

.connections_disabled
+ if DEF(_DEBUG)
+	call CheckBPressedDebug
+	jr nz, .ok
+ endc
	call CheckCoordEventsEnabled
	jr z, .coord_events_disabled

	call CheckCurrentMapCoordEvents
	jr c, .coord_event

engine/overworld/player_movement.asm:

.Normal:
+ if DEF(_DEBUG)
+	call .DebugMovement
+	ret c
+ endc
	call .CheckForced
	call .GetAction
	call .CheckTile
	ret c
	call .CheckTurning
	ret c
	call .TryStep
	ret c
	call .TryJump
	ret c
	call .CheckWarp
	ret c
	jr .NotMoving

.Surf:
+ if DEF(_DEBUG)
+	call .DebugMovement
+	ret c
+ endc
	call .CheckForced
	call .GetAction
	call .CheckTile
	ret c
	call .CheckTurning
	ret c
	call .TrySurf
	ret c
	jr .NotMoving

.Ice:
+ if DEF(_DEBUG)
+	call .DebugMovement
+	ret c
+ endc
	call .CheckForced
	call .GetAction
	call .CheckTile
.Standing:
	call .StandInPlace
	xor a
	ret

+ if DEF(_DEBUG)
+ .DebugMovement:
+	call CheckBPressedDebug
+	jr z, .Regular
+	call .GetAction
+	ld a, [wWalkingDirection]
+	cp STANDING
+	jr z, .DebugStanding
+	ld a, [wWalkingTileCollision]
+	cp COLL_FF
+	jr z, .DebugStanding
+	ld a, STEP_BIKE
+	call .DoStep
+	scf
+	ret
+
+ .DebugStanding:
+	call .DebugStandInPlace
+	scf
+	ret
+
+ .Regular:
+	xor a
+	ret
+ endc

.CheckTile:
.FinishFacing:
	db $80 | DOWN
	db $80 | UP
	db $80 | LEFT
	db $80 | RIGHT

.StandInPlace:
	ld a, 0
	ld [wPlayerTurningDirection], a
+ if DEF(_DEBUG)
+ .DebugStandInPlace:
+ endc
	ld a, movement_step_sleep
	ld [wMovementAnimation], a
	xor a
	ret

At this point it's done, you can build and test! Keep reading if you want to add optional contents.

4. (Optional) Add comments

Enabling debug features uses previously unreferenced functions. You may want to include a warning for your future self, in case you're running short on space some day and decide to trim unused contents. Alternatively, you can wrap the functions with if DEF(_DEBUG) code.

engine/overworld/decorations.asm:

SetAllDecorationFlags: ; unreferenced except in _DEBUG builds

home/flag.asm:

CheckBPressedDebug:: ; unreferenced except in _DEBUG builds
CheckFieldDebug:: ; unreferenced except in _DEBUG builds

5. Adding more features

Essential Debug Tools adds some more functions at game start, by using the Radio as a script hub.