pokecrystal-board/docs/develop/index.md

16 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.

Changes

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. Initialized when entering a level (in StartMap), and updated accordingly throughout the level. Includes:

    • wCurLevel: this one is not initialized in StartMap, but in LevelSelectionMenu (where it is also used), and stays static during the level.
    • wCurTurn
    • wCurSpace
    • wCurLevelCoins
    • wCurLevelExp
    • wCurSpaceStruct:
      • wCurSpaceXCoord
      • wCurSpaceYCoord
      • wCurSpaceEffect for non-branch spaces, or wCurSpaceBranchStructPtr (two bytes) for branch spaces
      • wCurSpaceNextSpace for non-branch spaces
  • Addresses within wPlayerData ~ wPlayerDataEnd: preserved on save. Includes:

    • wUnlockedLevels: flag array that tracks progression regarding which levels have been unlocked.
    • wClearedLevelsStage: flag array that tracks progression regarding which levels have been cleared. Each level can have up to four clearable endings (N).
    • wUnlockedTechniques: flag array that tracks progression regarding which techniques have been unlocked.
    • wCurOverworldMiscPal
  • 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, wBeforeViewMapDirection: Temporary scope during a Vew Map mode session. Used to preserve player state before entering View Map mode.
  • Additional addresses for View Map mode, that share memory region with wCurBattleMon and wCurMoveNum, which are not used outside of battle:

    • wPlayerMockYCoord, wPlayerMockXCoord: Used to handle the player mock sprite through map connections during View Map mode.
  • Addresses for talker events:

    • wSeenTrainer* addresses have been repurposed as wSeenTrainerOrTalker*
    • wSeenTrainerOrTalkerIsTalker: added right before wSeenTrainerOrTalker*.
    • wTempTalker ~ wTempTalkerEnd: allocated to the same address space as wTempTrainer. Same scope as wTempTrainer, but for talker events.
  • Address spaces for backing up the map state (disabled spaces and map objects). Located outside of WRAM banks 0 and 1.

    • wDisabledSpacesBackups: preserved on save to sDisabledSpacesBackups.
    • wMapObjectsBackups: preserved on save to sMapObjectsBackups.
  • Other WRAM 0 addresses (not preserved on save):

    • wText2bpp
    • wWhichHUD
    • wExitOverworldReason

Overworld workflow

  1. OverworldLoop is called from GameMenu_WorldMap with either hMapEntryMethod = MAPSETUP_ENTERLEVEL or hMapEntryMethod = MAPSETUP_CONTINUE.
  2. StartMap resets wCurTurn and wCurSpace if MAPSETUP_ENTERLEVEL. StartMap sets hCurBoardEvent to BOARDEVENT_DISPLAY_MENU. wScriptFlags2 is cleared. wMapStatus is set to MAPSTATUS_HANDLE causing HandleMap to be called.
  3. MapEvents (from HandleMap) calls PlayerEvents. CheckBoardEvent queues BoardMenuScript which is executed by ScriptEvents.
  4. BoardMenuScript.Upkeep saves the game, clears wTurnData[], increases wCurTurn, and loads current space to wCurSpaceStruct[].
    • If player exits, the exitoverworld script sets wMapStatus to MAPSTATUS_DONE. This causes OverworldLoop to return back to the game menu. Exit this workflow.
  5. Player rolls die and the animation plays. After the animation, wDisplaySecondarySprites.SECONDARYSPRITES_SPACES_LEFT_F is set and hCurBoardEvent is set to BOARDEVENT_HANDLE_BOARD. At the end of this HandleMap iteration, CheckPlayerState sets wMapEventStatus to MAPEVENTS_ON (wScriptFlags2 is not touched so it remains cleared).
  6. In the next HandleMap iteration, CheckBoardEvent from PlayerEvents jumps to .board and then to .no_space_effect due to wScriptFlags2[4] not being set.
  7. Execution continues in PlayerEvents; OWPlayerInput is eventually called, and thus DoPlayerMovement. Here, StepTowardsNextSpace computes based on wCurSpaceNextSpace what direction key to write to wCurInput, causing the player to begin a movement in that direction.
  8. The player may need to turn to a different direction through the ChangeDirectionScript (when DoPlayerMovement returns with PLAYERMOVEMENT_TURN). Otherwise or after that, CheckPlayerState sets wMapEventStatus to MAPEVENTS_OFF,
  9. When the step finishes (i.e. PLAYERSTEP_STOP_F becomes set) in some HandleMap iteration, CheckPlayerState sets wScriptFlags2 to $ff and wMapEventStatus to MAPEVENTS_ON.
  10. In the next HandleMap iteration, CheckBoardEvent.board is called with wScriptFlags2[4] set.
    • If wCurSpaceNextSpace matches NEXT_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 current HandleMap iteration. wScriptFlags2[4] is reset. Continue to 11.
  11. The space script loads the value of wCurSpaceNextSpace into wCurSpace, and loads the new space data to wCurSpaceStruct[]. 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 sets wMapStatus to MAPSTATUS_DONE. This causes OverworldLoop to return back to the game menu. Exit this workflow.
  12. If wSpacesLeft is non-0, go back to 6.
  13. The script code specific to the space type of the landed-on space is executed.
    • If player whites out in battle, Script_BattleWhiteout executes exitoverworld. Exit this workflow.
  14. The landed-on space is disabled by executing a block change that converts it into a Grey Space. hCurBoardEvent is set to BOARDEVENT_END_TURN. CheckBoardEvent does nothing in this state. In the first subsequent HandleMap iteration where no other kind of event triggers causing PlayerEvents to return early, hCurBoardEvent is set to BOARDEVENT_DISPLAY_MENU.
  15. Go back to 3

View Map mode workflow

  1. Pressing SELECT in the board menu triggers View Map mode. hCurBoardEvent is set to BOARDEVENT_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 last wMapObject and, in the background, to the first wObjectStruct is available.
  2. 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 single reloadmapafterviewmapmode) to exit from View Map mode is queued to be executed by ScriptEvents. Otherwise, DoPlayerMovement.ViewMapMode handles movement input in this mode.
  3. When requested exit of View Map mode via B button, reloadmapafterviewmapmode sets hMapEntryMethod to MAPSETUP_EXITVIEWMAP, hMapEntryMethod to SPAWN_FROM_RAM (required by the map setup command EnterMapSpawnPoint to restore the backed up player state), loads MAPSTATUS_ENTER tp wMapStatus, and resets wPlayerFlags[INVISIBLE_F] (the mocked player object naturally disappears when the map reloads).
  4. Then: a) If View Map mode was entered from the board menu, BOARDEVENT_REDISPLAY_MENU is loaded. It is the same as BOARDEVENT_DISPLAY_MENU but skips BoardMenuScript.Upkeep. b) If View Map mode was entered from the branch menu, instead BOARDEVENT_RESUME_BRANCH is loaded, using wPlayerSpriteSetupFlags[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 calling BranchSpaceScript_PromptPlayer directly and avoiding the recomputation of the branch struct that would cause corruption. BOARDEVENT_HANDLE_BOARD is loaded immediately by BOARDEVENT_RESUME_BRANCH.
  • In View Map mode, regular collisions except for COLL_OUT_OF_BOUNDS are ignored whereas going off-limits (i.e. outside of the map limits in a direction where there is no connected map) 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 to InitSecondarySprites (e.g. wTileDown=COLL_OUT_OF_BOUNDS 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.