From 93dad5959f5b37e73848612e3a1b75999dc3ca90 Mon Sep 17 00:00:00 2001 From: xCrystal Date: Tue, 28 Nov 2023 10:20:07 +0100 Subject: [PATCH] Documentation: move pokecrystal overworld loop documentation to a separate file --- docs/develop/index.md | 263 ----------------------------------------- docs/overworld_loop.md | 262 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+), 263 deletions(-) create mode 100755 docs/overworld_loop.md diff --git a/docs/develop/index.md b/docs/develop/index.md index b7dc33285..0c613680a 100755 --- a/docs/develop/index.md +++ b/docs/develop/index.md @@ -72,269 +72,6 @@ - **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) - -``` -Primary functions are denoted in red and using indentation -*[j]* means jumping ahead -*r_* means break/return from current function with a return value -Horizontal line means end of loop -Bold denotes not documented yet -This denotes a comment -``` - -wMapStatus == MAPSTATUS_START:\ -$~~~~$wScriptRunning <= 0\ -$~~~~$wMapStatus ~ wMapStatusEnd <= 0 - -wMapStatus == MAPSTATUS_START or wMapStatus == MAPSTATUS_ENTER:\ -$~~~~$**RunMapSetupScript**\ -$~~~~$hMapEntryMethod == MAPSETUP_CONNECTION:\ -$~~~~~~~~$wScriptFlags2 <= \$ff\ -$~~~~$hMapEntryMethod <= 0\ -$~~~~$wMapStatus <= MAPSTATUS_HANDLE - ---- - -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:\ ->$~~~~$*Get joypad* update hJoyDown, hJoyReleased, hJoyPressed\ ->$~~~~$*Refresh pals* - -> 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)*:\ ->>>$~~~~$*update wSeenTrainerDistance, wSeenTrainerDirection, wSeenTrainerBank, hLastTalked*\ ->>>$~~~~$*load trainer data to wTempTrainer ~ wTempTrainerEnd*\ ->>>$~~~~$[j1(PLAYEREVENT_SEENBYTRAINER)] - ->>> CheckTileEvent:\ ->>> *if warp, coord event, step event, or wild encounter*:\ ->>> $~~~~$[j1(PLAYEREVENT_CONNECTION / PLAYEREVENT_FALL / PLAYEREVENT_WARP / PLAYEREVENT_MAPSCRIPT / PLAYEREVENT_HATCH)] step events include: special phone call, repel, poison, happiness, egg, daycare, bike\ ->>> $~~~~$*may also* CallScript( / Script_ReceivePhoneCall / RepelWoreOffScript / Script_MonFaintedToPoison / WildBattleScript / BugCatchingContestBattleScript) - ->>> **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_WALL*s) 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:\ ->>>>> $~~~~$*if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button*\ ->>>>> $~~~~$*update wWalkingDirection, wFacingDirection, wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction*\ ->>>>> $~~~~$*if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN*\ ->>>>> $~~~~$*if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ ->>>>> $~~~~$*if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ ->>>>> $~~~~$*if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN*\ ->>>>> $~~~~$*if no bump (land tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)*\ ->>>>> $~~~~~~~~$*if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH*\ ->>>>> $~~~~~~~~$*if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER*\ ->>>>> $~~~~$*if ledge tile: play sfx, DoStep(STEP_LEDGE), and r1_player_movement = PLAYERMOVEMENT_JUMP*\ ->>>>> $~~~~$*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: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep\ ->>>>> $~~~~$wWalkingDirection != STANDING: if wWalkingIntoEdgeWarp == FALSE, *play bump sound*, wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_bump - ->>>>> wPlayerState == PLAYER_SURF:\ ->>>>> $~~~~$*if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button*\ ->>>>> $~~~~$*update wWalkingDirection, wFacingDirection: wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction*\ ->>>>> $~~~~$*if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN*\ ->>>>> $~~~~$*if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ ->>>>> $~~~~$*if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ ->>>>> $~~~~$*if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN*\ ->>>>> $~~~~$*if no bump (water tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)*\ ->>>>> $~~~~~~~~$*if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH*\ ->>>>> $~~~~~~~~$*if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER*\ ->>>>> $~~~~$wWalkingDirection == STANDING: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep\ ->>>>> $~~~~$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 on ice tile and wPlayerTurningDirection != 0*: [j2]\ ->>> $~~~~$if A_BUTTON in hJoyPressed:\ ->>> $~~~~~~~~$*if facing to object event*: CallScript() 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)\ ->>> $~~~~~~~~$*if bg event (signpost) in current coords and facing, and event's flag set if any*: CallScript( / HiddenItemScript) 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:\ ->>> $~~~~~~~~$CallScript(SelectMenuScript) and r3_player_event = PLAYEREVENT_MAPSCRIPT\ ->>> $~~~~$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:\ ->>> $~~~~$hMapEntryMethod <= MAPSETUP_CONNECTION\ ->>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ ->>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE - ->>> wScriptRunning == PLAYEREVENT_WARP:\ ->>> $~~~~$*play warp sound*\ ->>> $~~~~$hMapEntryMethod <= MAPSETUP_DOOR\ ->>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ ->>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE this write is exactly what the 'end' script also does - ->>> wScriptRunning == PLAYEREVENT_FALL:\ ->>> $~~~~$hMapEntryMethod <= MAPSETUP_FALL\ ->>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ ->>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE\ ->>> $~~~~$*play fall sound 1*\ ->>> $~~~~$*apply fall movement*\ ->>> $~~~~$*play fall sound 2* - ->>> wScriptRunning == PLAYEREVENT_WHITEOUT:\ ->>> $~~~~$OverworldWhiteoutScript + Script_Whiteout ends with hMapEntryMethod <= MAPSETUP_WARP + wMapStatus <= MAPSTATUS_ENTER + *endall* - ->>> wScriptRunning == PLAYEREVENT_HATCH:\ ->>> $~~~~$OverworldHatchEgg - ->>> wScriptRunning == PLAYEREVENT_JOYCHANGEFACING:\ ->>> $~~~~$wScriptDelay <= 3\ ->>> $~~~~$wScriptMode <= SCRIPT_WAIT\ ->>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE\ ->>> $~~~~$wScriptFlags2[4] == TRUE enable wild encounters - ->> **[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:\ ->>> $~~~~$wHandlePlayerStep <= 4\ ->>> $~~~~$*Scroll map in the direction at wPlayerStepDirection*\ ->>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1 ->>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ ->>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY\ ->>> else wPlayerStepFlags(PLAYERSTEP_STOP_F) == TRUE:\ ->>> $~~~~$*Increase or decrease wYCoord or wXCoord according to wPlayerStepDirection*\ ->>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1\ ->>> $~~~~$wHandlePlayerStep == 1: BufferScreen\ ->>> $~~~~$wHandlePlayerStep == 0: GetMovementPermissions Update *wPlayerTile*, *wTilePermissions*, *wTileDown*, *wTileUp*, *wTileLeft*, and/or *wTileRight*\ ->>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ ->>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY\ ->>> else wPlayerStepFlags(PLAYERSTEP_CONTINUE_F) == TRUE: same as PLAYERSTEP_STOP_F case except don't update *wYCoord* or *wXCoord*\ ->>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1\ ->>> $~~~~$wHandlePlayerStep == 1: BufferScreen\ ->>> $~~~~$wHandlePlayerStep == 0: GetMovementPermissions Update wPlayerTile, wTilePermissions, wTileDown, wTileUp, wTileLeft, and/or wTileRight\ ->>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ ->>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY - ->> **CheckObjectEnteringVisibleRange** (wPlayerStepFlags[PLAYERSTEP_STOP_F] == TRUE) - -> DelayFrames(hOverworldDelay) - -> **HandleMapBackground** UpdateActiveSprites + ScrollScreen - -> CheckPlayerState:\ -> wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == FALSE:\ -> $~~~~$wMapEventStatus <= MAPEVENTS_ON\ -> wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == TRUE and (wPlayerStepFlags[PLAYERSTEP_STOP_F] == FALSE or wPlayerStepFlags[PLAYERSTEP_MIDAIR_F] == TRUE):\ -> $~~~~$wMapEventStatus <= MAPEVENTS_OFF\ -> else:\ -> $~~~~$wScriptFlags2 <= \$ff\ -> $~~~~$wMapEventStatus <= MAPEVENTS_ON - -> **[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:\ -$~~~~$wPlayerTurningDirection <= 0\ -$~~~~$wMovementAnimation <= movement_step_sleep\ -else:\ -$~~~~$wMovementAnimation <= \ -$~~~~$wPlayerTurningDirection <= \ | 1 << 7\ -$~~~~$then always returns PLAYERMOVEMENT_FINISH but often is overwritten by caller - ---- - ## Board behavior ### RAM addresses diff --git a/docs/overworld_loop.md b/docs/overworld_loop.md new file mode 100755 index 000000000..33280bac1 --- /dev/null +++ b/docs/overworld_loop.md @@ -0,0 +1,262 @@ +## Overworld loop (pokecrystal) + +``` +Primary functions are denoted in red and using indentation +*[j]* means jumping ahead +*r_* means break/return from current function with a return value +Horizontal line means end of loop +Bold denotes not documented yet +This denotes a comment +``` + +wMapStatus == MAPSTATUS_START:\ +$~~~~$wScriptRunning <= 0\ +$~~~~$wMapStatus ~ wMapStatusEnd <= 0 + +wMapStatus == MAPSTATUS_START or wMapStatus == MAPSTATUS_ENTER:\ +$~~~~$**RunMapSetupScript**\ +$~~~~$hMapEntryMethod == MAPSETUP_CONNECTION:\ +$~~~~~~~~$wScriptFlags2 <= \$ff\ +$~~~~$hMapEntryMethod <= 0\ +$~~~~$wMapStatus <= MAPSTATUS_HANDLE + +--- + +wMapStatus == MAPSTATUS_DONE:\ +$~~~~$*Exit overworld loop* + +--- + +wMapStatus == MAPSTATUS_HANDLE: the remainder of the code goes at this level +> wOverworldDelay <= 2 2 is *MaxOverworldDelay*\ +> wMapEventStatus == MAPEVENTS_ON:\ +>$~~~~$*Get joypad* update hJoyDown, hJoyReleased, hJoyPressed\ +>$~~~~$*Refresh pals* + +> 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)*:\ +>>>$~~~~$*update wSeenTrainerDistance, wSeenTrainerDirection, wSeenTrainerBank, hLastTalked*\ +>>>$~~~~$*load trainer data to wTempTrainer ~ wTempTrainerEnd*\ +>>>$~~~~$[j1(PLAYEREVENT_SEENBYTRAINER)] + +>>> CheckTileEvent:\ +>>> *if warp, coord event, step event, or wild encounter*:\ +>>> $~~~~$[j1(PLAYEREVENT_CONNECTION / PLAYEREVENT_FALL / PLAYEREVENT_WARP / PLAYEREVENT_MAPSCRIPT / PLAYEREVENT_HATCH)] step events include: special phone call, repel, poison, happiness, egg, daycare, bike\ +>>> $~~~~$*may also* CallScript( / Script_ReceivePhoneCall / RepelWoreOffScript / Script_MonFaintedToPoison / WildBattleScript / BugCatchingContestBattleScript) + +>>> **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_WALL*s) 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:\ +>>>>> $~~~~$*if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button*\ +>>>>> $~~~~$*update wWalkingDirection, wFacingDirection, wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction*\ +>>>>> $~~~~$*if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN*\ +>>>>> $~~~~$*if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ +>>>>> $~~~~$*if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ +>>>>> $~~~~$*if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN*\ +>>>>> $~~~~$*if no bump (land tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)*\ +>>>>> $~~~~~~~~$*if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH*\ +>>>>> $~~~~~~~~$*if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER*\ +>>>>> $~~~~$*if ledge tile: play sfx, DoStep(STEP_LEDGE), and r1_player_movement = PLAYERMOVEMENT_JUMP*\ +>>>>> $~~~~$*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: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep\ +>>>>> $~~~~$wWalkingDirection != STANDING: if wWalkingIntoEdgeWarp == FALSE, *play bump sound*, wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_bump + +>>>>> wPlayerState == PLAYER_SURF:\ +>>>>> $~~~~$*if on ice tile and wPlayerTurningDirection != 0: wCurInput <= current direction button*\ +>>>>> $~~~~$*update wWalkingDirection, wFacingDirection: wWalkingX, wWalkingY, wWalkingTile, based on wCurInput direction*\ +>>>>> $~~~~$*if whirlpool tile: r1_player_movement = PLAYERMOVEMENT_FORCE_TURN*\ +>>>>> $~~~~$*if waterfall tile: wWalkingDirection <= direction, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ +>>>>> $~~~~$*if door/staircase/cave warp tile (non ladder/carpet): wWalkingDirection <= DOWN, DoStep(STEP_WALK), r1_player_movement = PLAYERMOVEMENT_CONTINUE*\ +>>>>> $~~~~$*if directions at wWalkingDirection and wPlayerDirection are not the same (turning): DoStep(STEP_TURN), r1_player_movement = PLAYERMOVEMENT_TURN*\ +>>>>> $~~~~$*if no bump (water tile permissions or NPC): DoStep(STEP_WALK / STEP_BIKE / STEP_ICE)*\ +>>>>> $~~~~~~~~$*if not leaving water: r1_player_movement = PLAYERMOVEMENT_FINISH*\ +>>>>> $~~~~~~~~$*if leaving water: wPlayerState <= PLAYER_NORMAL, reload music and sprites, and r1_player_movement = PLAYERMOVEMENT_EXIT_WATER*\ +>>>>> $~~~~$wWalkingDirection == STANDING: wPlayerTurningDirection <= 0, wMovementAnimation <= movement_step_sleep\ +>>>>> $~~~~$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 on ice tile and wPlayerTurningDirection != 0*: [j2]\ +>>> $~~~~$if A_BUTTON in hJoyPressed:\ +>>> $~~~~~~~~$*if facing to object event*: CallScript() 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)\ +>>> $~~~~~~~~$*if bg event (signpost) in current coords and facing, and event's flag set if any*: CallScript( / HiddenItemScript) 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:\ +>>> $~~~~~~~~$CallScript(SelectMenuScript) and r3_player_event = PLAYEREVENT_MAPSCRIPT\ +>>> $~~~~$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:\ +>>> $~~~~$hMapEntryMethod <= MAPSETUP_CONNECTION\ +>>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ +>>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE + +>>> wScriptRunning == PLAYEREVENT_WARP:\ +>>> $~~~~$*play warp sound*\ +>>> $~~~~$hMapEntryMethod <= MAPSETUP_DOOR\ +>>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ +>>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE this write is exactly what the 'end' script also does + +>>> wScriptRunning == PLAYEREVENT_FALL:\ +>>> $~~~~$hMapEntryMethod <= MAPSETUP_FALL\ +>>> $~~~~$wMapStatus <= MAPSTATUS_ENTER\ +>>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE\ +>>> $~~~~$*play fall sound 1*\ +>>> $~~~~$*apply fall movement*\ +>>> $~~~~$*play fall sound 2* + +>>> wScriptRunning == PLAYEREVENT_WHITEOUT:\ +>>> $~~~~$OverworldWhiteoutScript + Script_Whiteout ends with hMapEntryMethod <= MAPSETUP_WARP + wMapStatus <= MAPSTATUS_ENTER + *endall* + +>>> wScriptRunning == PLAYEREVENT_HATCH:\ +>>> $~~~~$OverworldHatchEgg + +>>> wScriptRunning == PLAYEREVENT_JOYCHANGEFACING:\ +>>> $~~~~$wScriptDelay <= 3\ +>>> $~~~~$wScriptMode <= SCRIPT_WAIT\ +>>> $~~~~$wScriptFlags[SCRIPT_RUNNING] = FALSE\ +>>> $~~~~$wScriptFlags2[4] == TRUE enable wild encounters + +>> **[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:\ +>>> $~~~~$wHandlePlayerStep <= 4\ +>>> $~~~~$*Scroll map in the direction at wPlayerStepDirection*\ +>>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1 +>>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ +>>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY\ +>>> else wPlayerStepFlags(PLAYERSTEP_STOP_F) == TRUE:\ +>>> $~~~~$*Increase or decrease wYCoord or wXCoord according to wPlayerStepDirection*\ +>>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1\ +>>> $~~~~$wHandlePlayerStep == 1: BufferScreen\ +>>> $~~~~$wHandlePlayerStep == 0: GetMovementPermissions Update *wPlayerTile*, *wTilePermissions*, *wTileDown*, *wTileUp*, *wTileLeft*, and/or *wTileRight*\ +>>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ +>>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY\ +>>> else wPlayerStepFlags(PLAYERSTEP_CONTINUE_F) == TRUE: same as PLAYERSTEP_STOP_F case except don't update *wYCoord* or *wXCoord*\ +>>> $~~~~$wHandlePlayerStep <= wHandlePlayerStep - 1\ +>>> $~~~~$wHandlePlayerStep == 1: BufferScreen\ +>>> $~~~~$wHandlePlayerStep == 0: GetMovementPermissions Update wPlayerTile, wTilePermissions, wTileDown, wTileUp, wTileLeft, and/or wTileRight\ +>>> $~~~~$wPlayerBGMapOffsetX <= wPlayerBGMapOffsetX - wPlayerStepVectorX\ +>>> $~~~~$wPlayerBGMapOffsetY <= wPlayerBGMapOffsetY - wPlayerStepVectorY + +>> **CheckObjectEnteringVisibleRange** (wPlayerStepFlags[PLAYERSTEP_STOP_F] == TRUE) + +> DelayFrames(wOverworldDelay) + +> **HandleMapBackground** UpdateActiveSprites + ScrollScreen + +> CheckPlayerState:\ +> wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == FALSE:\ +> $~~~~$wMapEventStatus <= MAPEVENTS_ON\ +> wPlayerStepFlags[PLAYERSTEP_CONTINUE_F] == TRUE and (wPlayerStepFlags[PLAYERSTEP_STOP_F] == FALSE or wPlayerStepFlags[PLAYERSTEP_MIDAIR_F] == TRUE):\ +> $~~~~$wMapEventStatus <= MAPEVENTS_OFF\ +> else:\ +> $~~~~$wScriptFlags2 <= \$ff\ +> $~~~~$wMapEventStatus <= MAPEVENTS_ON + +> **[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:\ +$~~~~$wPlayerTurningDirection <= 0\ +$~~~~$wMovementAnimation <= movement_step_sleep\ +else:\ +$~~~~$wMovementAnimation <= \ +$~~~~$wPlayerTurningDirection <= \ | 1 << 7\ +$~~~~$then always returns PLAYERMOVEMENT_FINISH but often is overwritten by caller + +---