29 KiB
Executable File
Functions
Apply VRAM/OAM
- SafeUpdateSprites: Set BG map mode to 0 (disabled) and disable OAM update + UpdateSprites + enable OAM update + DelayFrame + restore original state of BG map mode and OAM update
- UpdateSprites: Compute state of overworld sprites to wShadowOAM. Disable OAM update while editing wShadowOAM, and restore its original state when finished
- ApplyPals: Copy wBGPals1 into wBGPals2 and wOBPals1 into wOBPals2. Does not request pal update during vblank by itself
- ApplyAttrmap: Set BG map mode to 2 (pals) and delay 4 frames, and finally restore original state BG map mode. If LCD disabled instead copy all pals at once immediately
- ApplyTilemap: Set BG map mode to 1 (tiles) and delay 4 frames. If wSpriteUpdatesEnabled is non-0, instead call CopyTilemapAtOnce to do it all in one frame. This delays the next vblank to LY ~$7f
Load font
- LoadFont_NoOAMUpdate: LoadFrame + Hide Window + LoadStandardFont with OAM update disabled
- LoadOverworldFont_NoOAMUpdate: LoadOverworldFontAndFrame + hide Window with OAM update disabled
Textboxes
- Textbox1bpp: TextboxBorder + TextboxAttributes1bpp
- Textbox2bpp: _OverworldTextbox + TextboxAttributes2bpp
- SpeechTextbox1bpp: Textbox1bpp with speech location and dimensions
- SpeechTextbox2bpp: Textbox2bpp with speech location and dimensions
- ClearTextbox: Clear the inside of a speech textbox (fill with " ")
- PrintTextboxText: Print text in speech textbox coordinates with letter delay
- PrintText1bpp, FarPrintText1bpp: SpeechTextbox1bpp + UpdateSprites + ApplyTilemap + ClearTextbox + PrintTextboxText
- PrintText2bpp: SpeechTextbox2bpp + UpdateSprites + ApplyTilemap + ClearTextbox + PrintTextboxText
- MapTextbox: ClearTextbox + redraw tile behind cursor + SafeUpdateSprites + disable OAM update + ApplyTilemap + PrintTextboxText + enable OAM update
- MenuBox: Calls Textbox1bpp or Textbox2bpp, depending on the value of wText2bpp, with menu location and dimensions.
Overworld map scrolling
- LoadScreenTilemap: From the metatile-based 24x20 map in wSurroundingTiles, load the corresponding 20x18 tiles to wTilemap. Later, BackupBGMap* from ScrollMap* copies new row/column from wTilemap to wBGMapBuffer. _ScrollBGMapPalettes populates wBGMapPalBuffer based on the tiles at wBGMapBuffer. These are read during vblank by UpdateBGMapBuffer.
- LoadScreenAttrmapPals: Load wAttrmap palette numbers based on the tileset palettes of the current map. Called only by LoadScreenTilemapAndAttrmapPals.
- LoadScreenTilemapAndAttrmapPals: LoadScreenTilemap + LoadScreenAttrmapPals. Often used to reload screen after closing a text box.
Overworld map anchoring
- ReanchorBGMap_NoOAMUpdate: LoadScreenTilemapAndAttrmapPals + HDMATransferTilemapAndAttrmap_OpenAndCloseMenu, then fill BG map with all black while Window is displayed, finally anchor map and objects. Shall by followed by CopyTilemapAtOnce or by a HDMATransferTilemapAndAttrmap_* to redraw the screen.
- OpenText1bpp, OpenText2bpp: ClearMenuAndWindowData + ReanchorBGMap_NoOAMUpdate + SpeechTextbox1bpp + HDMATransferTilemapAndAttrmap_OpenAndCloseMenu + hide Window
- OpenText1bpp: Loads 1bpp font (LoadFont_NoOAMUpdate)
- OpenText2bpp: Doesn't load 2bpp font
- RefreshScreen: Same as OpenText functions but doesn't call any SpeechTextbox
VRAM transfer
- Request1bpp, Request2bpp: Copy 1bpp or 2bpp tiles at a rate of TILES_PER_CYCLE (8) per frame during vblank. Wait until complete
- Copy1bpp, Copy2bpp: Copy 1bpp or 2bpp tiles immediately
- Get1bpp, Get2bpp: Call Copy1bpp or Copy2bpp if LCD disabled. Request1bpp or Request2bpp otherwise
- HDMATransfer1bpp: Copy 1bpp tiles via HDMA. Maximum 16 tiles per frame
- HDMATransfer2bpp: Copy 2bpp tiles via HDMA. No hardcoded limit. Timing considers 1 tile per hblank
- Get1bppViaHDMA, Get2bppViaHDMA: Call Copy1bpp or Copy2bpp if LCD disabled. HDMATransfer1bpp or HDMATransfer2bpp otherwise
- HDMATransferTilemapAndAttrmap_OpenAndCloseMenu, HDMATransferTilemapAndAttrmap_OverworldEffect: Similar, but with slightly different scanline timing. So they're essentially like RefreshScreen minus the anchoring part.
HUD
- EnableWindowHUD: Configure LCD interrupt in LYC=LY mode with corresponding LYC.
- DisableWindowHUD: Configure LCD interrupt in hblank mode
- LoadHUD: Load the HUD at wWhichHUD to the top of wTilemap and wAttrmap
- LoadWindowHUD: Like LoadHUD, but for HUDs that require a Window overlay. Only does anything if hWindowHUDLY is non-0
- ConstructOverworldHUDTilemap: Draw the overworld HUD's tilemap into wOverworldHUDTiles
- TransferOverworldHUDToBGMap: Transfer overworld HUD to vBGMap1/vBGMap3 during v/hblank(s). Tilemap is read from wOverworldHUDTiles, attrmap is all PAL_BG_TEXT | PRIORITY.
- RefreshOverworldHUD: ConstructOverworldHUDTilemap + TransferOverworldHUDToBGMap
Scripts
- refreshscreen: RefreshScreen
- reloadmappart: LoadScreenTilemapAndAttrmapPals + GetMovementPermissions + HDMATransferTilemapAndAttrmap_OverworldEffect + UpdateSprites. Similar to refreshscreen, but does not reanchor. On the other hand, it refreshes movement permissions. Often used after a block change or field move, which can affect collisions.
Overworld loop (pokecrystal)
<f>Primary functions</f> are denoted in red and using indentation
<j>*[j<num>]*</j> means jumping ahead
<k>*r<num>_<ret_value>*</k> means break/return from current function with a return value
Horizontal line means end of loop
Bold denotes not documented yet
<c>This denotes a comment</c>
wMapStatus == MAPSTATUS_START:
$$wMapStatus ~ wMapStatusEnd <= 0$wScriptRunning <= 0
$
wMapStatus == MAPSTATUS_START or wMapStatus == MAPSTATUS_ENTER:
$$hMapEntryMethod == MAPSETUP_CONNECTION:$RunMapSetupScript
$
$~~~~~~~~$wScriptFlags2 <= $ff
$$wMapStatus <= MAPSTATUS_HANDLE$hMapEntryMethod <= 0
$
wMapStatus == MAPSTATUS_DONE:
$~~~~$Exit overworld loop
wMapStatus == MAPSTATUS_HANDLE: the remainder of the code goes at this level
hOverworldDelay <= 2 2 is MaxOverworldDelay
wMapEventStatus == MAPEVENTS_ON:
$$Refresh pals$Get joypad update hJoyDown, hJoyReleased, hJoyPressed
$
HandleCmdQueue runs cmds queued by callbacks of type MAPCALLBACK_CMDQUEUE that execute the writecmdqueue script. Used only for stone tables, where any boulder from that table that is on a pit tile is made to disappear.
MapEvents (wMapEventStatus == MAPEVENTS_ON):
PlayerEvents (wScriptRunning == FALSE): wScriptRunning check not to interrupt a running script command with wait/delay mode like applymovement and deactivatefacing
CheckTrainerBattle:
if seen by trainer (if any visible sprite is a trainer not yet beaten facing the player within line of sight):
$$load trainer data to wTempTrainer ~ wTempTrainerEnd$update wSeenTrainerDistance, wSeenTrainerDirection, wSeenTrainerBank, hLastTalked
$
$~~~~$[j1(PLAYEREVENT_SEENBYTRAINER)]
CheckTileEvent:
if warp, coord event, step event, or wild encounter:
$$may also CallScript(<coord_event_script> / Script_ReceivePhoneCall / RepelWoreOffScript / Script_MonFaintedToPoison / WildBattleScript / BugCatchingContestBattleScript)$[j1(PLAYEREVENT_CONNECTION / PLAYEREVENT_FALL / PLAYEREVENT_WARP / PLAYEREVENT_MAPSCRIPT / PLAYEREVENT_HATCH)] step events include: special phone call, repel, poison, happiness, egg, daycare, bike
$
RunMemScript:
if any script at wMapReentryScript: [j1] used for phone scripts
RunSceneScript:
if scene event (wCurMapSceneScriptCount): [j1(PLAYEREVENT_MAPSCRIPT)]
CheckTimeEvents:
if any time event: [j1] used for bug contest, daily events
OWPlayerInput:
PlayerMovement:
DoPlayerMovement:
wCurInput <= hJoyDown if BIKEFLAGS_DOWNHILL_F and hJoyDown & D_PAD == 0, instead load D_DOWN
wMovementAnimation <= movement_step_sleep
wWalkingIntoEdgeWarp <= FALSE
Tile collision checks below consist on reading the current tile wPlayerTile and comparing it to a COLL_ constant or a range of COLL_ constants.
Tile permission checks below consist on reading the permissions of the tile that the player is walking into: wTilePermissions (applies only to COLL_WALLs) and wWalkingTile (LAND_TILE, WATER_TILE, or WALL_TILE for the tile in the walking direction; WALL_TILE permission is not the same as a COLL_WALL collision).
wPlayerState == PLAYER_NORMAL or wPlayerState = PLAYER_BIKE:
$$update wWalkingDirection, wFacingDirection, wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction$if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button
$
$$if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE$if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN
$
$$if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN$if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE
$
$$if ledge tile: play sfx, DoStep(STEP_LEDGE), and r1_player_movement = PLAYERMOVEMENT_JUMP$if no bump (land tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)
$$if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER$if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH
$
$
$$wWalkingDirection == STANDING: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep$if carpet warp tile matching wWalkingDirection: wWalkingIntoEdgeWarp <= TRUE
$~~~~~~~~$if directions at wWalkingDirection and wPlayerDirection are the same: load warp data, wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep, and r1_player_movement = PLAYERMOVEMENT_WARP
$
$~~~~$wWalkingDirection != STANDING: if wWalkingIntoEdgeWarp == FALSE, play bump sound, wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_bump
wPlayerState == PLAYER_SURF:
$$update wWalkingDirection, wFacingDirection: wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction$if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button
$
$$if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE$if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN
$
$$if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN$if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE
$
$$wWalkingDirection == STANDING: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep$if no bump (water tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)
$$if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER$if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH
$
$
$~~~~$wWalkingDirection != STANDING: if wWalkingIntoEdgeWarp == FALSE, play bump sound, wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_bump
wPlayerNextMovement <= wMovementAnimation
r1_player_movement = PLAYERMOVEMENT_NORMAL
r1_player_movement == PLAYERMOVEMENT_NORMAL or r1_player_movement == PLAYERMOVEMENT_JUMP or r1_player_movement == PLAYERMOVEMENT_FINISH: r2_player_event = 0
r1_player_movement == PLAYERMOVEMENT_WARP: r2_player_event = PLAYEREVENT_WARP
r1_player_movement == PLAYERMOVEMENT_TURN: r2_player_event = PLAYEREVENT_JOYCHANGEFACING
r1_player_movement == PLAYERMOVEMENT_FORCE_TURN: CallScript(Script_ForcedMovement), r2_player_event = PLAYEREVENT_MAPSCRIPT CallScript returns PLAYEREVENT_MAPSCRIPT always
r1_player_movement == PLAYERMOVEMENT_CONTINUE or r1_player_movement == PLAYERMOVEMENT_EXIT_WATER: r2_player_event = -1
r2_player_event == -1: r3_player_event = 0 in this case, apart from r2_player_event = -1, PlayerMovement has also returned nc
r2_player_event == 0: in this case, apart from r2_player_event = 0, PlayerMovement has also returned nc
$$if A_BUTTON in hJoyPressed:$if on ice tile and wPlayerTurningDirection != 0: [j2]
$
$$if bg event (signpost) in current coords and facing, and event's flag set if any: CallScript(<event's script> / HiddenItemScript) and r3_player_event = PLAYEREVENT_MAPSCRIPT$if facing to object event: CallScript(<object's script>) and r3_player_event = PLAYEREVENT_MAPSCRIPT / r3_player_event = PLAYEREVENT_ITEMBALL / load trainer data and r3_player_event = PLAYEREVENT_TALKTOTRAINER includes rock and boulder objects (PLAYEREVENT_MAPSCRIPT case)
$
$$CallScript(SelectMenuScript) and r3_player_event = PLAYEREVENT_MAPSCRIPT$if facing to collision event (use cut, whirlpool, waterfall, headbutt, surf): call TryXOW, which returns with CallScript(AskXOW / CantXOW) and thus r3_player_event = PLAYEREVENT_MAPSCRIPT
$~~~~$hJoyPressed[SELECT_F] == TRUE:
$
$~~~~$hJoyPressed[START_F] == TRUE:
$~~~~~~~~$CallScript(StartMenuScript) and r3_player_event = PLAYEREVENT_MAPSCRIPT
r3_player_event = r2_player_event in these instances is where PlayerMovement returned carry, so OWPlayerInput returns early
r3_player_event == 0: [j2]
[j1]
wScriptMode <= SCRIPT_READ
wScriptRunning <= loaded script from whatever jumped straight to [j1] OR r3_player_event
DoPlayerEvent (wScriptRunning == TRUE and wScriptRunning != PLAYEREVENT_MAPSCRIPT): if there is a non-PLAYEREVENT_MAPSCRIPT script requested during this loop iteration, DoPlayerEvent pushes it to make it be executed by ScriptEvents. So the code up to [j2] below here is actually executed by ScriptEvents and NOT right now.
All scripts below finish with the end script unless otherwise stated (e.g. by the endall script)
wScriptRunning == PLAYEREVENT_SEENBYTRAINER:
$~~~~$SeenByTrainerScript + StartBattleWithMapTrainerScript
wScriptRunning == PLAYEREVENT_TALKTOTRAINER:
$~~~~$TalkToTrainerScript + StartBattleWithMapTrainerScript
wScriptRunning == PLAYEREVENT_ITEMBALL:
$~~~~$FindItemInBallScript
wScriptRunning == PLAYEREVENT_CONNECTION:
$$wMapStatus <= MAPSTATUS_ENTER$hMapEntryMethod <= MAPSETUP_CONNECTION
$
$~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE
wScriptRunning == PLAYEREVENT_WARP:
$$hMapEntryMethod <= MAPSETUP_DOOR$play warp sound
$
$$wScriptFlags[SCRIPT_RUNNING] = FALSE this write is exactly what the 'end' script also does$wMapStatus <= MAPSTATUS_ENTER
$
wScriptRunning == PLAYEREVENT_FALL:
$$wMapStatus <= MAPSTATUS_ENTER$hMapEntryMethod <= MAPSETUP_FALL
$
$$play fall sound 1$wScriptFlags[SCRIPT_RUNNING] = FALSE
$
$$play fall sound 2$apply fall movement
$
wScriptRunning == PLAYEREVENT_WHITEOUT:
$~~~~$OverworldWhiteoutScript + Script_Whiteout ends with hMapEntryMethod <= MAPSETUP_WARP + wMapStatus <= MAPSTATUS_ENTER + endall
wScriptRunning == PLAYEREVENT_HATCH:
$~~~~$OverworldHatchEgg
wScriptRunning == PLAYEREVENT_JOYCHANGEFACING:
$$wScriptMode <= SCRIPT_WAIT$wScriptDelay <= 3
$
$$wScriptFlags2[4] == TRUE enable wild encounters$wScriptFlags[SCRIPT_RUNNING] = FALSE
$
[j2]
wScriptFlags2 <= 0
ScriptEvents: executes scripts requested this loop by CallScript (PLAYEREVENT_MAPSCRIPT)
wScriptFlags[SCRIPT_RUNNING] = TRUE
while wScriptFlags[SCRIPT_RUNNING] == TRUE: breaks after end or similar script command
$~~~~$wScriptMode == SCRIPT_OFF:
$~~~~~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE
$~~~~$wScriptMode == SCRIPT_READ:
$~~~~~~~~$(...)
$~~~~$wScriptMode == SCRIPT_WAIT_MOVEMENT:
$~~~~~~~~$(...)
$~~~~$wScriptMode == SCRIPT_WAIT:
$~~~~~~~~$(...)
wMapStatus != MAPSTATUS_HANDLE: [j3] jump if any script during this iteration changed wMapStatus (some warp ocurred)
HandleMapObjects:
HandleNPCStep Includes player object! At the beginning of each object, clears wPlayerStepVectorX, wPlayerStepVectorY, and wPlayerStepFlags, and sets wPlayerStepDirection to STANDING. HandleObjectStep is called for each visible object. This calls HandleStepType, which processes StepTypesJumptable by STEP_TYPE_. These functions manipulate wPlayerStepFlags among other things.
_HandlePlayerStep (wPlayerStepFlags != 0):
wPlayerStepFlags(PLAYERSTEP_START_F) == TRUE:
$$Scroll map in the direction at wPlayerStepDirection$wHandlePlayerStep <= 4
$
$$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX$wHandlePlayerStep <= wHandlePlayerStep - 1 $
$$Increase or decrease wYCoord or wXCoord according to wPlayerStepDirection$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY
else wPlayerStepFlags(PLAYERSTEP_STOP_F) == TRUE:
$
$$wHandlePlayerStep == 1: BufferScreen$wHandlePlayerStep <= wHandlePlayerStep - 1
$
$$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX$wHandlePlayerStep == 0: GetMovementPermissions Update wPlayerTile, wTilePermissions, wTileDown, wTileUp, wTileLeft, and/or wTileRight
$
$$wHandlePlayerStep <= wHandlePlayerStep - 1$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY
else wPlayerStepFlags(PLAYERSTEP_CONTINUE_F) == TRUE: same as PLAYERSTEP_STOP_F case except don't update wYCoord or wXCoord
$
$$wHandlePlayerStep == 0: GetMovementPermissions Update wPlayerTile, wTilePermissions, wTileDown, wTileUp, wTileLeft, and/or wTileRight$wHandlePlayerStep == 1: BufferScreen
$
$$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX
$
CheckObjectEnteringVisibleRange (wPlayerStepFlags[PLAYERSTEP_STOP_F] == TRUE)
DelayFrames(hOverworldDelay)
HandleMapBackground UpdateActiveSprites + ScrollScreen
CheckPlayerState:
wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == FALSE:
$$wMapEventStatus <= MAPEVENTS_OFF$wMapEventStatus <= MAPEVENTS_ON
wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == TRUE and (wPlayerStepFlags[PLAYERSTEP_STOP_F] == FALSE or wPlayerStepFlags[PLAYERSTEP_MIDAIR_F] == TRUE):
$
else:
$$wMapEventStatus <= MAPEVENTS_ON$wScriptFlags2 <= $ff
$
[j3]
End of overworld loop. The remainder are intermediate functions
Every script executed by ScriptEvents finishes with the some form of the end command. It returns (by updating wScriptPos and wScriptBank) to a parent script if any, and otherwise:
wScriptRunning <= FALSE
wScriptMode <= SCRIPT_OFF
wScriptFlags[SCRIPT_RUNNING] = FALSE
The endall command is like end, but also finishes parent scripts regardless.
DoStep:
wWalkingDirection == STANDING:
$$wMovementAnimation <= movement_step_sleep$wPlayerTurningDirection <= 0
$
else:
$$wPlayerTurningDirection <= <direction> | 1 << 7$wMovementAnimation <= <step (type, direction)>
$
$~~~~$then always returns PLAYERMOVEMENT_FINISH but often is overwritten by caller
Board behavior
RAM addresses
-
hCurBoardEvent: holds a BOARDEVENT_ value.
-
wTurnData ~ wTurnDataEnd: not preserved on save, and cleared at the beginning of BoardMenuScript (i.e. on turn begin). It's part of wMapStatus ~ wMapStatusEnd, so it's also cleared by StartMap. Includes:
- wDieRoll
- wSpacesLeft
-
Addresses within wCurMapData ~ wCurMapDataEnd: preserved on save. Includes:
- wCurTurn
- wCurSpace
- wCurSpaceStruct:
- wCurSpaceXCoord
- wCurSpaceYCoord
- wCurSpaceEffect for non-branch spaces, or wCurSpaceBranchStructPtr (two bytes) for branch spaces
- wCurSpaceNextSpace for non-branch spaces
-
These addresses share memory region with string buffers from wStringBuffer3 onwards. They are placed in memory in the following order.
-
wTempSpaceStruct: Temporary scope. Same structure as wCurSpaceStruct
-
wTempSpaceBranchStruct: Temporary scope. The structure is four bytes for next space for each direction (R/L/U/D; -1 if unavailable direction) followed by four bytes for required techniques for each direction (R/L/U/D)
-
wViewMapModeRange, wViewMapModeDisplacementY, wViewMapModeDisplacementX: Temporary scope during a Vew Map mode session.
-
wBeforeViewMapYCoord, wBeforeViewMapXCoord, wBeforeViewMapMapGroup, wBeforeViewMapMapNumber: Temporary scope during a Vew Map mode session. Used to preserve previous player state.
Overworld workflow
OverworldLoop
is called fromGameMenu_WorldMap
with eitherhMapEntryMethod
=MAPSETUP_ENTERLEVEL
orhMapEntryMethod
=MAPSETUP_CONTINUE
.StartMap
resetswCurTurn
andwCurSpace
ifMAPSETUP_ENTERLEVEL
.StartMap
setshCurBoardEvent
toBOARDEVENT_DISPLAY_MENU
.wScriptFlags2
is cleared.wMapStatus
is set toMAPSTATUS_HANDLE
causingHandleMap
to be called.MapEvents
(fromHandleMap
) callsPlayerEvents
.CheckBoardEvent
queuesBoardMenuScript
which is executed byScriptEvents
.BoardMenuScript.Upkeep
saves the game, clearswTurnData[]
, increaseswCurTurn
, and loads current space towCurSpaceStruct[]
.- If player exits, the
exitoverworld
script setswMapStatus
toMAPSTATUS_DONE
. This causesOverworldLoop
to return back to the game menu. Exit this workflow.
- If player exits, the
- Player rolls die and the animation plays. After the animation,
wDisplaySecondarySprites.SECONDARYSPRITES_SPACES_LEFT_F
is set andhCurBoardEvent
is set toBOARDEVENT_HANDLE_BOARD
. At the end of thisHandleMap
iteration,CheckPlayerState
setswMapEventStatus
toMAPEVENTS_ON
(wScriptFlags2
is not touched so it remains cleared). - In the next
HandleMap
iteration,CheckBoardEvent
fromPlayerEvents
jumps to.board
and then to.no_space_effect
due towScriptFlags2[4]
not being set. - Execution continues in
PlayerEvents
;OWPlayerInput
is eventually called, and thusDoPlayerMovement
. Here,StepTowardsNextSpace
computes based onwCurSpaceNextSpace
what direction key to write towCurInput
, causing the player to begin a movement in that direction. - The player may need to turn to a different direction through the
ChangeDirectionScript
(whenDoPlayerMovement
returns withPLAYERMOVEMENT_TURN
). Otherwise or after that,CheckPlayerState
setswMapEventStatus
toMAPEVENTS_OFF
, - When the step finishes (i.e.
PLAYERSTEP_STOP_F
becomes set) in someHandleMap
iteration,CheckPlayerState
setswScriptFlags2
to $ff andwMapEventStatus
toMAPEVENTS_ON
. - In the next
HandleMap
iteration,CheckBoardEvent.board
is called withwScriptFlags2[4]
set.- If
wCurSpaceNextSpace
matchesNEXT_SPACE_IS_ANCHOR_POINT
: If player is at a tile with an anchor event,wCurSpaceNextSpace
is updated with the next space byte of salid anchor event.wScriptFlags2[4]
is reset. Go back to 7. - If player is not above a tile (
wPlayerTile
) with a space collision:wScriptFlags2[4]
is reset. Go back to 7. - If player is above a tile, the corresponding space script is queued to be executed by
ScriptEvents
in the currentHandleMap
iteration.wScriptFlags2[4]
is reset. Continue to 11.
- If
- The space script loads the value of
wCurSpaceNextSpace
intowCurSpace
, and loads the new space data towCurSpaceStruct[]
. Unless the space is a Branch Space or a Union Space,wSpacesLeft
is decreased.- If the space is a Branch Space, the branch data is loaded to
wTempSpaceBranchStruct
. Then the player is prompted to choose a valid direction.wCurSpaceNextSpace
is populated with the next space that corresponds to the chosen direction. Go back to 6. - If the space is an End Space, a fading out animation plays and then the
exitoverworld
script setswMapStatus
toMAPSTATUS_DONE
. This causesOverworldLoop
to return back to the game menu. Exit this workflow.
- If the space is a Branch Space, the branch data is loaded to
- If
wSpacesLeft
is non-0, go back to 6. - The script code specific to the space type of the landed-on space is executed.
- If player whites out in battle,
Script_BattleWhiteout
executesexitoverworld
. Exit this workflow.
- If player whites out in battle,
- The landed-on space is disabled by executing a block change that converts it into a Grey Space.
hCurBoardEvent
is set toBOARDEVENT_END_TURN
.CheckBoardEvent
does nothing in this state. In the first subsequentHandleMap
iteration where no other kind of event triggers causingPlayerEvents
to return early,hCurBoardEvent
is set toBOARDEVENT_DISPLAY_MENU
. - Go back to 3
View Map mode workflow
- Pressing SELECT in the board menu triggers View Map mode.
hCurBoardEvent
is set toBOARDEVENT_VIEW_MAP_MODE
, player state (coordinates as well as current map in order to support connected maps) is backed up,wPlayerFlags[INVISIBLE_F]
is set, and a static mockup of the player object is loaded to the lastwMapObject
and, in the background, to the firstwObjectStruct
is available. - The board event handler in
CheckBoardEvent
listens for the B button being pressed (except when a DPAD key is simultaneously held). When B is pressed, a script (a singlereloadmapafterviewmapmode
) to exit from View Map mode is queued to be executed byScriptEvents
. Otherwise,DoPlayerMovement.ViewMapMode
handles movement input in this mode. - When requested exit of View Map mode via B button,
reloadmapafterviewmapmode
setshMapEntryMethod
toMAPSETUP_EXITVIEWMAP
,hMapEntryMethod
toSPAWN_FROM_RAM
(required by the map setup commandEnterMapSpawnPoint
to restore the backed up player state), loadsMAPSTATUS_ENTER
tpwMapStatus
, and resetswPlayerFlags[INVISIBLE_F]
(the mocked player object naturally disappears when the map reloads). - Then:
a) If View Map mode was entered from the board menu,
BOARDEVENT_REDISPLAY_MENU
is loaded. It is the same asBOARDEVENT_DISPLAY_MENU
but skipsBoardMenuScript.Upkeep
. b) If View Map mode was entered from the branch menu, insteadBOARDEVENT_RESUME_BRANCH
is loaded, usingwPlayerSpriteSetupFlags[PLAYERSPRITESETUP_CUSTOM_FACING_F]
to maintain the facing direction according to the direction (SPRITEMOVEDATA_*
) of the mocked player object.BOARDEVENT_RESUME_BRANCH
makes sure to shortcut the branch space script by callingBranchSpaceScript_PromptPlayer
directly and avoiding the recomputation of the branch struct that would cause corruption.BOARDEVENT_HANDLE_BOARD
is loaded immediately byBOARDEVENT_RESUME_BRANCH
.
- In View Map mode, regular collisions are ignored whereas going off-limits (based on map dimensions and connected maps) or off-range is accounted for.
- Events other than warpless connections are ignored in View Map mode (as well as button actions, like while in
BOARDEVENT_HANDLE_BOARD
). wTileDown
,wTileUp
, etc., otherwise unused, are borrowed by in order to signal valid directions toInitSecondarySprites
(e.g.wTileDown=$ff
means that DOWN direction is not valid).- In View Map mode, the overworld delay is 1 rather than 2.
UpdatePlayerCoords
tracks the displacement during View Map mode in the X and Y axes in order to monitor the allowed range.