## 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 ---