#include "global.h" #include "gflib.h" #include "bg_regs.h" #include "event_data.h" #include "event_object_movement.h" #include "event_scripts.h" #include "field_camera.h" #include "field_control_avatar.h" #include "field_effect.h" #include "field_fadetransition.h" #include "field_message_box.h" #include "field_player_avatar.h" #include "field_screen_effect.h" #include "field_specials.h" #include "field_tasks.h" #include "field_weather.h" #include "fieldmap.h" #include "heal_location.h" #include "help_system.h" #include "link.h" #include "load_save.h" #include "m4a.h" #include "map_name_popup.h" #include "map_preview_screen.h" #include "metatile_behavior.h" #include "money.h" #include "new_game.h" #include "new_menu_helpers.h" #include "overworld.h" #include "play_time.h" #include "quest_log.h" #include "quest_log_objects.h" #include "random.h" #include "renewable_hidden_items.h" #include "roamer.h" #include "safari_zone.h" #include "save_location.h" #include "scanline_effect.h" #include "script.h" #include "script_pokemon_util.h" #include "tileset_anims.h" #include "trainer_pokemon_sprites.h" #include "vs_seeker.h" #include "wild_encounter.h" #include "constants/maps.h" #include "constants/flags.h" #include "constants/species.h" #include "constants/region_map_sections.h" #include "constants/songs.h" struct InitialPlayerAvatarState { u8 transitionFlags; u8 direction; bool8 unk2; }; EWRAM_DATA struct WarpData gLastUsedWarp = {}; EWRAM_DATA struct WarpData sWarpDestination = {}; EWRAM_DATA struct WarpData gFixedDiveWarp = {}; EWRAM_DATA struct WarpData gFixedHoleWarp = {}; // File boundary perhaps? EWRAM_DATA struct InitialPlayerAvatarState gInitialPlayerAvatarState = {}; // File boundary perhaps? EWRAM_DATA bool8 gDisableMapMusicChangeOnMapLoad = FALSE; EWRAM_DATA u16 sAmbientCrySpecies = SPECIES_NONE; EWRAM_DATA bool8 sIsAmbientCryWaterMon = FALSE; // File boundary perhaps? ALIGNED(4) EWRAM_DATA bool8 gUnknown_2031DE0 = FALSE; EWRAM_DATA const struct CreditsOverworldCmd *gUnknown_2031DE4 = NULL; EWRAM_DATA s16 gUnknown_2031DE8 = 0; EWRAM_DATA s16 gUnknown_2031DEA = 0; // File boundary perhaps? EWRAM_DATA struct LinkPlayerObjectEvent gLinkPlayerObjectEvents[4] = {}; u16 *gBGTilemapBuffers1; u16 *gBGTilemapBuffers2; u16 *gBGTilemapBuffers3; void (*gFieldCallback)(void); bool8 (*gFieldCallback2)(void); u16 gHeldKeyCodeToSend; u8 gLocalLinkPlayerId; u8 gFieldLinkPlayerCount; u8 CountBadgesForOverworldWhiteOutLossCalculation(void); void Overworld_ResetStateAfterWhitingOut(void); void Overworld_SetWhiteoutRespawnPoint(void); u8 GetAdjustedInitialTransitionFlags(struct InitialPlayerAvatarState *playerStruct, u16 metatileBehavior, u8 mapType); u8 GetAdjustedInitialDirection(struct InitialPlayerAvatarState *playerStruct, u8 transitionFlags, u16 metatileBehavior, u8 mapType); u16 GetCenterScreenMetatileBehavior(void); bool8 sub_8055B38(u16 metatileBehavior); void SetDefaultFlashLevel(void); void Overworld_TryMapConnectionMusicTransition(void); void ChooseAmbientCrySpecies(void); void CB2_Overworld(void); void CB2_DoChangeMap(void); void CB2_LoadMap2(void); void c2_80567AC(void); void CB2_ReturnToFieldLocal(void); void CB2_ReturnToFieldLink(void); void FieldClearVBlankHBlankCallbacks(void); void SetFieldVBlankCallback(void); void VBlankCB_Field(void); bool32 map_loading_iteration_3(u8 *state); bool32 sub_8056CD8(u8 *state); bool32 map_loading_iteration_2_link(u8 *state); void do_load_map_stuff_loop(u8 *state); void MoveSaveBlocks_ResetHeap_(void); void sub_8056E80(void); void sub_8056F08(void); void InitOverworldGraphicsRegisters(void); void sub_8057024(bool32 a0); void sub_8057074(void); void mli4_mapscripts_and_other(void); void sub_8057100(void); void sub_8057114(void); void SetCameraToTrackGuestPlayer(void); void SetCameraToTrackGuestPlayer_2(void); void sub_8057178(void); void sub_80571A8(void); void CreateLinkPlayerSprites(void); void sub_80572D8(void); void sub_8057300(u8 *state); bool32 sub_8057314(u8 *state); bool32 sub_8057528(u8 *state, u8 unused); bool8 sub_8057650(void); void sub_8057748(struct CameraObject * camera); void sub_805781C(u8 taskId); void sub_8057854(u8 taskId); void SpawnLinkPlayerObjectEvent(u8 i, s16 x, s16 y, u8 gender); void CreateLinkPlayerSprite(u8 i, u8 version); void ClearAllPlayerKeys(void); u8 GetSpriteForLinkedPlayer(u8 linkPlayerId); void CB1_UpdateLinkState(void); void ResetAllMultiplayerState(void); extern const struct MapLayout * gMapLayouts[]; extern const struct MapHeader *const *gMapGroups[]; // Routines related to game state on warping in static const u8 sWhiteOutMoneyLossMultipliers[] = { 2, 4, 6, 9, 12, 16, 20, 25, 30 }; const u16 sWhiteOutMoneyLossBadgeFlagIDs[] = { FLAG_BADGE01_GET, FLAG_BADGE02_GET, FLAG_BADGE03_GET, FLAG_BADGE04_GET, FLAG_BADGE05_GET, FLAG_BADGE06_GET, FLAG_BADGE07_GET, FLAG_BADGE08_GET }; void DoWhiteOut(void) { ScriptContext2_RunNewScript(EventScript_ResetEliteFourEnd); RemoveMoney(&gSaveBlock1Ptr->money, ComputeWhiteOutMoneyLoss()); HealPlayerParty(); Overworld_ResetStateAfterWhitingOut(); Overworld_SetWhiteoutRespawnPoint(); WarpIntoMap(); } u32 ComputeWhiteOutMoneyLoss(void) { u8 nbadges = CountBadgesForOverworldWhiteOutLossCalculation(); u8 toplevel = GetPlayerPartyHighestLevel(); u32 losings = toplevel * 4 * sWhiteOutMoneyLossMultipliers[nbadges]; u32 money = GetMoney(&gSaveBlock1Ptr->money); if (losings > money) losings = money; return losings; } void OverworldWhiteOutGetMoneyLoss(void) { u32 losings = ComputeWhiteOutMoneyLoss(); ConvertIntToDecimalStringN(gStringVar1, losings, STR_CONV_MODE_LEFT_ALIGN, CountDigits(losings)); } u8 CountBadgesForOverworldWhiteOutLossCalculation(void) { int i; u8 nbadges = 0; for (i = 0; i < NELEMS(sWhiteOutMoneyLossBadgeFlagIDs); i++) { if (FlagGet(sWhiteOutMoneyLossBadgeFlagIDs[i])) nbadges++; } return nbadges; } void Overworld_ResetStateAfterFly(void) { ResetInitialPlayerAvatarState(); FlagClear(FLAG_SYS_ON_CYCLING_ROAD); VarSet(VAR_MAP_SCENE_ROUTE16, 0); FlagClear(FLAG_SYS_CRUISE_MODE); FlagClear(FLAG_SYS_SAFARI_MODE); VarSet(VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, 0); FlagClear(FLAG_SYS_USE_STRENGTH); FlagClear(FLAG_SYS_FLASH_ACTIVE); FlagClear(FLAG_0x808); VarSet(VAR_0x404D, 0); } void Overworld_ResetStateAfterTeleport(void) { ResetInitialPlayerAvatarState(); FlagClear(FLAG_SYS_ON_CYCLING_ROAD); VarSet(VAR_MAP_SCENE_ROUTE16, 0); FlagClear(FLAG_SYS_CRUISE_MODE); FlagClear(FLAG_SYS_SAFARI_MODE); VarSet(VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, 0); FlagClear(FLAG_SYS_USE_STRENGTH); FlagClear(FLAG_SYS_FLASH_ACTIVE); FlagClear(FLAG_0x808); VarSet(VAR_0x404D, 0); } void Overworld_ResetStateAfterDigEscRope(void) { ResetInitialPlayerAvatarState(); FlagClear(FLAG_SYS_ON_CYCLING_ROAD); VarSet(VAR_MAP_SCENE_ROUTE16, 0); FlagClear(FLAG_SYS_CRUISE_MODE); FlagClear(FLAG_SYS_SAFARI_MODE); VarSet(VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, 0); FlagClear(FLAG_SYS_USE_STRENGTH); FlagClear(FLAG_SYS_FLASH_ACTIVE); FlagClear(FLAG_0x808); VarSet(VAR_0x404D, 0); } void Overworld_ResetStateAfterWhitingOut(void) { ResetInitialPlayerAvatarState(); FlagClear(FLAG_SYS_ON_CYCLING_ROAD); VarSet(VAR_MAP_SCENE_ROUTE16, 0); FlagClear(FLAG_SYS_CRUISE_MODE); FlagClear(FLAG_SYS_SAFARI_MODE); VarSet(VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, 0); FlagClear(FLAG_SYS_USE_STRENGTH); FlagClear(FLAG_SYS_FLASH_ACTIVE); FlagClear(FLAG_0x808); VarSet(VAR_0x404D, 0); } void sub_8054E40(void) { FlagClear(FLAG_SYS_SAFARI_MODE); VarSet(VAR_MAP_SCENE_FUCHSIA_CITY_SAFARI_ZONE_ENTRANCE, 0); ChooseAmbientCrySpecies(); UpdateLocationHistoryForRoamer(); RoamerMoveToOtherLocationSet(); } // Routines related to game stats void ResetGameStats(void) { int i; for (i = 0; i < NUM_GAME_STATS; i++) { gSaveBlock1Ptr->gameStats[i] = 0; } } void IncrementGameStat(u8 statId) { u32 statVal; if (statId >= NUM_USED_GAME_STATS) return; statVal = GetGameStat(statId); if (statVal < 0xFFFFFF) statVal++; else statVal = 0xFFFFFF; SetGameStat(statId, statVal); } u32 GetGameStat(u8 statId) { if (statId >= NUM_USED_GAME_STATS) return 0; else return gSaveBlock1Ptr->gameStats[statId] ^ gSaveBlock2Ptr->encryptionKey; } void SetGameStat(u8 statId, u32 statVal) { if (statId >= NUM_USED_GAME_STATS) return; gSaveBlock1Ptr->gameStats[statId] = statVal ^ gSaveBlock2Ptr->encryptionKey; } void ApplyNewEncryptionKeyToGameStats(u32 newKey) { u8 i; for (i = 0; i < NUM_GAME_STATS; i++) { ApplyNewEncryptionKeyToWord(&gSaveBlock1Ptr->gameStats[i], newKey); } } // Routines related to object events void sub_8054F68(void) { u8 i, j; u8 mapGroup; u8 mapNum; u8 localId; const struct MapHeader * linkedMap; for (i = 0, j = 0; i < gMapHeader.events->objectEventCount; i++) { if (gMapHeader.events->objectEvents[i].unk2 == 0xFF) { localId = gMapHeader.events->objectEvents[i].elevation; mapNum = gMapHeader.events->objectEvents[i].trainerType; mapGroup = gMapHeader.events->objectEvents[i].trainerRange_berryTreeId; linkedMap = Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum); gSaveBlock1Ptr->objectEventTemplates[j] = linkedMap->events->objectEvents[localId - 1]; gSaveBlock1Ptr->objectEventTemplates[j].localId = gMapHeader.events->objectEvents[i].localId; gSaveBlock1Ptr->objectEventTemplates[j].x = gMapHeader.events->objectEvents[i].x; gSaveBlock1Ptr->objectEventTemplates[j].y = gMapHeader.events->objectEvents[i].y; gSaveBlock1Ptr->objectEventTemplates[j].elevation = localId; gSaveBlock1Ptr->objectEventTemplates[j].trainerType = mapNum; gSaveBlock1Ptr->objectEventTemplates[j].trainerRange_berryTreeId = mapGroup; gSaveBlock1Ptr->objectEventTemplates[j].unk2 = 0xFF; j++; } else { gSaveBlock1Ptr->objectEventTemplates[j] = gMapHeader.events->objectEvents[i]; j++; } } } void LoadSaveblockObjEventScripts(void) { int i; const struct ObjectEventTemplate * src = gMapHeader.events->objectEvents; struct ObjectEventTemplate * savObjTemplates = gSaveBlock1Ptr->objectEventTemplates; for (i = 0; i < OBJECT_EVENT_TEMPLATES_COUNT; i++) { savObjTemplates[i].script = src[i].script; } } void Overworld_SetMapObjTemplateCoords(u8 localId, s16 x, s16 y) { int i; struct ObjectEventTemplate * savObjTemplates = gSaveBlock1Ptr->objectEventTemplates; for (i = 0; i < OBJECT_EVENT_TEMPLATES_COUNT; i++) { if (savObjTemplates[i].localId == localId) { savObjTemplates[i].x = x; savObjTemplates[i].y = y; break; } } } void Overworld_SetObjEventTemplateMovementType(u8 localId, u8 movementType) { s32 i; struct ObjectEventTemplate *savObjTemplates = gSaveBlock1Ptr->objectEventTemplates; for (i = 0; i < OBJECT_EVENT_TEMPLATES_COUNT; i++) { struct ObjectEventTemplate *objectEventTemplate = &savObjTemplates[i]; if (objectEventTemplate->localId == localId) { objectEventTemplate->movementType = movementType; return; } } } // Routines related to the map layout void mapdata_load_assets_to_gpu_and_full_redraw(void) { move_tilemap_camera_to_upper_left_corner(); copy_map_tileset1_tileset2_to_vram(gMapHeader.mapLayout); apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); DrawWholeMapView(); InitTilesetAnimations(); } const struct MapLayout *GetMapLayout(void) { u16 mapLayoutId = gSaveBlock1Ptr->mapLayoutId; if (mapLayoutId) return gMapLayouts[mapLayoutId - 1]; return NULL; } // Routines related to warps const struct WarpData sDummyWarpData = { .mapGroup = MAP_GROUP(UNDEFINED), .mapNum = MAP_NUM(UNDEFINED), .warpId = 0xFF, .x = -1, .y = -1 }; void ApplyCurrentWarp(void) { gLastUsedWarp = gSaveBlock1Ptr->location; gSaveBlock1Ptr->location = sWarpDestination; gFixedDiveWarp = sDummyWarpData; gFixedHoleWarp = sDummyWarpData; } void SetWarpData(struct WarpData *warp, s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { warp->mapGroup = mapGroup; warp->mapNum = mapNum; warp->warpId = warpId; warp->x = x; warp->y = y; } bool32 IsDummyWarp(struct WarpData *warp) { if (warp->mapGroup != -1) return FALSE; else if (warp->mapNum != -1) return FALSE; else if (warp->warpId != -1) return FALSE; else if (warp->x != -1) return FALSE; else if (warp->y != -1) return FALSE; else return TRUE; } struct MapHeader const *const Overworld_GetMapHeaderByGroupAndId(u16 mapGroup, u16 mapNum) { return gMapGroups[mapGroup][mapNum]; } struct MapHeader const *const GetDestinationWarpMapHeader(void) { return Overworld_GetMapHeaderByGroupAndId(sWarpDestination.mapGroup, sWarpDestination.mapNum); } void LoadCurrentMapData(void) { gMapHeader = *Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum); gSaveBlock1Ptr->mapLayoutId = gMapHeader.mapLayoutId; gMapHeader.mapLayout = GetMapLayout(); } void LoadSaveblockMapHeader(void) { gMapHeader = *Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum); gMapHeader.mapLayout = GetMapLayout(); } void SetPlayerCoordsFromWarp(void) { if (gSaveBlock1Ptr->location.warpId >= 0 && gSaveBlock1Ptr->location.warpId < gMapHeader.events->warpCount) { gSaveBlock1Ptr->pos.x = gMapHeader.events->warps[gSaveBlock1Ptr->location.warpId].x; gSaveBlock1Ptr->pos.y = gMapHeader.events->warps[gSaveBlock1Ptr->location.warpId].y; } else if (gSaveBlock1Ptr->location.x >= 0 && gSaveBlock1Ptr->location.y >= 0) { gSaveBlock1Ptr->pos.x = gSaveBlock1Ptr->location.x; gSaveBlock1Ptr->pos.y = gSaveBlock1Ptr->location.y; } else { gSaveBlock1Ptr->pos.x = gMapHeader.mapLayout->width / 2; gSaveBlock1Ptr->pos.y = gMapHeader.mapLayout->height / 2; } } void WarpIntoMap(void) { ApplyCurrentWarp(); LoadCurrentMapData(); SetPlayerCoordsFromWarp(); } void SetWarpDestination(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&sWarpDestination, mapGroup, mapNum, warpId, x, y); } void SetWarpDestinationToMapWarp(s8 mapGroup, s8 mapNum, s8 warpId) { SetWarpDestination(mapGroup, mapNum, warpId, -1, -1); } void SetDynamicWarp(s32 unused, s8 mapGroup, s8 mapNum, s8 warpId) { SetWarpData(&gSaveBlock1Ptr->dynamicWarp, mapGroup, mapNum, warpId, gSaveBlock1Ptr->pos.x, gSaveBlock1Ptr->pos.y); } void SetDynamicWarpWithCoords(s32 unused, s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&gSaveBlock1Ptr->dynamicWarp, mapGroup, mapNum, warpId, x, y); } void SetWarpDestinationToDynamicWarp(u8 unusedWarpId) { sWarpDestination = gSaveBlock1Ptr->dynamicWarp; } void SetWarpDestinationToHealLocation(u8 healLocationId) { const struct HealLocation *warp = GetHealLocation(healLocationId); if (warp) SetWarpDestination(warp->group, warp->map, -1, warp->x, warp->y); } void SetWarpDestinationToLastHealLocation(void) { sWarpDestination = gSaveBlock1Ptr->lastHealLocation; } void Overworld_SetWhiteoutRespawnPoint(void) { SetWhiteoutRespawnWarpAndHealerNpc(&sWarpDestination); } void SetLastHealLocationWarp(u8 healLocationId) { const struct HealLocation *healLocation = GetHealLocation(healLocationId); if (healLocation) SetWarpData(&gSaveBlock1Ptr->lastHealLocation, healLocation->group, healLocation->map, -1, healLocation->x, healLocation->y); } void UpdateEscapeWarp(s16 x, s16 y) { u8 currMapType = GetCurrentMapType(); u8 destMapType = GetMapTypeByGroupAndId(sWarpDestination.mapGroup, sWarpDestination.mapNum); u8 delta; if (IsMapTypeOutdoors(currMapType) && IsMapTypeOutdoors(destMapType) != TRUE && !(gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(VIRIDIAN_FOREST) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(VIRIDIAN_FOREST))) { delta = GetPlayerFacingDirection() != DIR_SOUTH; SetEscapeWarp(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum, -1, x - 7, y - 7 + delta); } } void SetEscapeWarp(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&gSaveBlock1Ptr->escapeWarp, mapGroup, mapNum, warpId, x, y); } void SetWarpDestinationToEscapeWarp(void) { sWarpDestination = gSaveBlock1Ptr->escapeWarp; } void SetFixedDiveWarp(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&gFixedDiveWarp, mapGroup, mapNum, warpId, x, y); } void SetWarpDestinationToDiveWarp(void) { sWarpDestination = gFixedDiveWarp; } void SetFixedHoleWarp(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&gFixedHoleWarp, mapGroup, mapNum, warpId, x, y); } void SetWarpDestinationToFixedHoleWarp(s16 x, s16 y) { if (IsDummyWarp(&gFixedHoleWarp) == TRUE) sWarpDestination = gLastUsedWarp; else SetWarpDestination(gFixedHoleWarp.mapGroup, gFixedHoleWarp.mapNum, -1, x, y); } void SetWarpDestinationToContinueGameWarp(void) { sWarpDestination = gSaveBlock1Ptr->continueGameWarp; } void SetContinueGameWarp(s8 mapGroup, s8 mapNum, s8 warpId, s8 x, s8 y) { SetWarpData(&gSaveBlock1Ptr->continueGameWarp, mapGroup, mapNum, warpId, x, y); } void SetContinueGameWarpToHealLocation(u8 healLocationId) { const struct HealLocation *warp = GetHealLocation(healLocationId); if (warp) SetWarpData(&gSaveBlock1Ptr->continueGameWarp, warp->group, warp->map, -1, warp->x, warp->y); } void SetContinueGameWarpToDynamicWarp(int unused) { gSaveBlock1Ptr->continueGameWarp = gSaveBlock1Ptr->dynamicWarp; } const struct MapConnection * GetMapConnection(u8 dir) { s32 i; s32 count = gMapHeader.connections->count; const struct MapConnection *connection = gMapHeader.connections->connections; if (connection == NULL) return NULL; for(i = 0; i < count; i++, connection++) if (connection->direction == dir) return connection; return NULL; } bool8 SetDiveWarp(u8 dir, u16 x, u16 y) { const struct MapConnection *connection = GetMapConnection(dir); if (connection != NULL) { SetWarpDestination(connection->mapGroup, connection->mapNum, -1, x, y); } else { RunOnDiveWarpMapScript(); if (IsDummyWarp(&gFixedDiveWarp)) return FALSE; SetWarpDestinationToDiveWarp(); } return TRUE; } bool8 SetDiveWarpEmerge(u16 x, u16 y) { return SetDiveWarp(CONNECTION_EMERGE, x, y); } bool8 SetDiveWarpDive(u16 x, u16 y) { return SetDiveWarp(CONNECTION_DIVE, x, y); } // Map loaders void LoadMapFromCameraTransition(u8 mapGroup, u8 mapNum) { int paletteIndex; SetWarpDestination(mapGroup, mapNum, -1, -1, -1); Overworld_TryMapConnectionMusicTransition(); ApplyCurrentWarp(); LoadCurrentMapData(); sub_8054F68(); TrySetMapSaveWarpStatus(); ClearTempFieldEventData(); ResetCyclingRoadChallengeData(); RestartWildEncounterImmunitySteps(); TryUpdateRandomTrainerRematches(mapGroup, mapNum); SetSav1WeatherFromCurrMapHeader(); ChooseAmbientCrySpecies(); SetDefaultFlashLevel(); Overworld_ClearSavedMusic(); RunOnTransitionMapScript(); TryRegenerateRenewableHiddenItems(); InitMap(); copy_map_tileset2_to_vram_2(gMapHeader.mapLayout); apply_map_tileset2_palette(gMapHeader.mapLayout); for (paletteIndex = 7; paletteIndex < 13; paletteIndex++) ApplyWeatherGammaShiftToPal(paletteIndex); InitSecondaryTilesetAnimation(); UpdateLocationHistoryForRoamer(); RoamerMove(); sub_8110920(); DoCurrentWeather(); ResetFieldTasksArgs(); RunOnResumeMapScript(); if (GetLastUsedWarpMapSectionId() != gMapHeader.regionMapSectionId) ShowMapNamePopup(TRUE); } void mli0_load_map(bool32 a1) { bool8 isOutdoors; LoadCurrentMapData(); sub_8054F68(); isOutdoors = IsMapTypeOutdoors(gMapHeader.mapType); TrySetMapSaveWarpStatus(); ClearTempFieldEventData(); ResetCyclingRoadChallengeData(); RestartWildEncounterImmunitySteps(); TryUpdateRandomTrainerRematches(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum); SetSav1WeatherFromCurrMapHeader(); ChooseAmbientCrySpecies(); if (isOutdoors) FlagClear(FLAG_SYS_FLASH_ACTIVE); SetDefaultFlashLevel(); Overworld_ClearSavedMusic(); RunOnTransitionMapScript(); TryRegenerateRenewableHiddenItems(); UpdateLocationHistoryForRoamer(); RoamerMoveToOtherLocationSet(); sub_8110920(); InitMap(); } void sub_80559A8(void) { bool8 isOutdoors; LoadCurrentMapData(); sub_8054F68(); isOutdoors = IsMapTypeOutdoors(gMapHeader.mapType); TrySetMapSaveWarpStatus(); SetSav1WeatherFromCurrMapHeader(); ChooseAmbientCrySpecies(); SetDefaultFlashLevel(); sub_8110920(); sub_8111708(); LoadSaveblockMapHeader(); InitMap(); } // Routines related to the initial player avatar state void ResetInitialPlayerAvatarState(void) { gInitialPlayerAvatarState.direction = DIR_SOUTH; gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_ON_FOOT; gInitialPlayerAvatarState.unk2 = FALSE; } void SetInitialPlayerAvatarStateWithDirection(u8 dirn) { gInitialPlayerAvatarState.direction = dirn; gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_ON_FOOT; gInitialPlayerAvatarState.unk2 = TRUE; } void StoreInitialPlayerAvatarState(void) { gInitialPlayerAvatarState.direction = GetPlayerFacingDirection(); if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE)) gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_MACH_BIKE; else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_ACRO_BIKE)) gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_ACRO_BIKE; else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING)) gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_SURFING; else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_UNDERWATER)) gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_UNDERWATER; else gInitialPlayerAvatarState.transitionFlags = PLAYER_AVATAR_FLAG_ON_FOOT; gInitialPlayerAvatarState.unk2 = FALSE; } struct InitialPlayerAvatarState *GetInitialPlayerAvatarState(void) { struct InitialPlayerAvatarState playerStruct; u8 mapType = GetCurrentMapType(); u16 metatileBehavior = GetCenterScreenMetatileBehavior(); u8 transitionFlags = GetAdjustedInitialTransitionFlags(&gInitialPlayerAvatarState, metatileBehavior, mapType); playerStruct.transitionFlags = transitionFlags; playerStruct.direction = GetAdjustedInitialDirection(&gInitialPlayerAvatarState, transitionFlags, metatileBehavior, mapType); playerStruct.unk2 = FALSE; gInitialPlayerAvatarState = playerStruct; return &gInitialPlayerAvatarState; } u8 GetAdjustedInitialTransitionFlags(struct InitialPlayerAvatarState *playerStruct, u16 metatileBehavior, u8 mapType) { if (mapType != MAP_TYPE_INDOOR && FlagGet(FLAG_SYS_CRUISE_MODE)) return PLAYER_AVATAR_FLAG_ON_FOOT; else if (mapType == MAP_TYPE_UNDERWATER) return PLAYER_AVATAR_FLAG_UNDERWATER; else if (sub_8055B38(metatileBehavior) == TRUE) return PLAYER_AVATAR_FLAG_ON_FOOT; else if (MetatileBehavior_IsSurfable(metatileBehavior) == TRUE) return PLAYER_AVATAR_FLAG_SURFING; else if (Overworld_IsBikingAllowed() != TRUE) return PLAYER_AVATAR_FLAG_ON_FOOT; else if (playerStruct->transitionFlags == PLAYER_AVATAR_FLAG_MACH_BIKE) return PLAYER_AVATAR_FLAG_MACH_BIKE; else if (playerStruct->transitionFlags != PLAYER_AVATAR_FLAG_ACRO_BIKE) return PLAYER_AVATAR_FLAG_ON_FOOT; else return PLAYER_AVATAR_FLAG_ACRO_BIKE; } bool8 sub_8055B38(u16 metatileBehavior) { if (MetatileBehavior_IsSurfable(metatileBehavior) != TRUE) return FALSE; if ((gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(SEAFOAM_ISLANDS_B3F) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEAFOAM_ISLANDS_B3F)) || (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(SEAFOAM_ISLANDS_B4F) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(SEAFOAM_ISLANDS_B4F))) return TRUE; return FALSE; } u8 GetAdjustedInitialDirection(struct InitialPlayerAvatarState *playerStruct, u8 transitionFlags, u16 metatileBehavior, u8 mapType) { if (FlagGet(FLAG_SYS_CRUISE_MODE) && mapType == MAP_TYPE_OCEAN_ROUTE) return DIR_EAST; else if (MetatileBehavior_IsDeepSouthWarp(metatileBehavior) == TRUE) return DIR_NORTH; else if (MetatileBehavior_IsNonAnimDoor(metatileBehavior) == TRUE || MetatileBehavior_IsWarpDoor_2(metatileBehavior) == TRUE) return DIR_SOUTH; else if (MetatileBehavior_IsSouthArrowWarp(metatileBehavior) == TRUE) return DIR_NORTH; else if (MetatileBehavior_IsNorthArrowWarp(metatileBehavior) == TRUE) return DIR_SOUTH; else if (MetatileBehavior_IsWestArrowWarp(metatileBehavior) == TRUE) return DIR_EAST; else if (MetatileBehavior_IsEastArrowWarp(metatileBehavior) == TRUE) return DIR_WEST; else if (MetatileBehavior_IsUnknownWarp6C(metatileBehavior) == TRUE || MetatileBehavior_IsUnknownWarp6E(metatileBehavior) == TRUE) return DIR_WEST; else if (MetatileBehavior_IsUnknownWarp6D(metatileBehavior) == TRUE || MetatileBehavior_IsUnknownWarp6F(metatileBehavior) == TRUE) return DIR_EAST; else if ((playerStruct->transitionFlags == PLAYER_AVATAR_FLAG_UNDERWATER && transitionFlags == PLAYER_AVATAR_FLAG_SURFING) || (playerStruct->transitionFlags == PLAYER_AVATAR_FLAG_SURFING && transitionFlags == PLAYER_AVATAR_FLAG_UNDERWATER )) return playerStruct->direction; else if (MetatileBehavior_IsLadder(metatileBehavior) == TRUE) return playerStruct->direction; else if (playerStruct->unk2) return playerStruct->direction; else return DIR_SOUTH; } u16 GetCenterScreenMetatileBehavior(void) { return MapGridGetMetatileBehaviorAt(gSaveBlock1Ptr->pos.x + 7, gSaveBlock1Ptr->pos.y + 7); } // Routines related to flash level and map perms bool32 Overworld_IsBikingAllowed(void) { if (!gMapHeader.bikingAllowed) return FALSE; else return TRUE; } void SetDefaultFlashLevel(void) { if (!gMapHeader.cave) gSaveBlock1Ptr->flashLevel = 0; else if (FlagGet(FLAG_SYS_FLASH_ACTIVE)) gSaveBlock1Ptr->flashLevel = 0; else gSaveBlock1Ptr->flashLevel = gMaxFlashLevel; } void Overworld_SetFlashLevel(s32 flashLevel) { if (flashLevel < 0 || flashLevel > gMaxFlashLevel) flashLevel = 0; gSaveBlock1Ptr->flashLevel = flashLevel; } u8 Overworld_GetFlashLevel(void) { return gSaveBlock1Ptr->flashLevel; } void SetCurrentMapLayout(u16 mapLayoutId) { gSaveBlock1Ptr->mapLayoutId = mapLayoutId; gMapHeader.mapLayout = GetMapLayout(); } void sub_8055D5C(struct WarpData * warp) { sWarpDestination = *warp; } // Routines related to map music u16 GetLocationMusic(struct WarpData * warp) { return Overworld_GetMapHeaderByGroupAndId(warp->mapGroup, warp->mapNum)->music; } u16 GetCurrLocationDefaultMusic(void) { u16 music; music = GetLocationMusic(&gSaveBlock1Ptr->location); return music; } u16 GetWarpDestinationMusic(void) { u16 music = GetLocationMusic(&sWarpDestination); return music; } void Overworld_ResetMapMusic(void) { ResetMapMusic(); } void Overworld_PlaySpecialMapMusic(void) { u16 music; s16 x, y; if (gDisableMapMusicChangeOnMapLoad == 1) { StopMapMusic(); return; } if (gDisableMapMusicChangeOnMapLoad == 2) { return; } if (gSaveBlock1Ptr->location.mapGroup == MAP_GROUP(POKEMON_LEAGUE_CHAMPIONS_ROOM) && gSaveBlock1Ptr->location.mapNum == MAP_NUM(POKEMON_LEAGUE_CHAMPIONS_ROOM)) { PlayerGetDestCoords(&x, &y); if (y - 7 < 11 && gMPlayInfo_BGM.songHeader == &mus_win_gym) { FadeInBGM(4); return; } } music = GetCurrLocationDefaultMusic(); if (gSaveBlock1Ptr->savedMusic) music = gSaveBlock1Ptr->savedMusic; else if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) &&sub_8056124(MUS_NAMINORI)) music = MUS_NAMINORI; if (music != GetCurrentMapMusic()) PlayNewMapMusic(music); } void Overworld_SetSavedMusic(u16 songNum) { gSaveBlock1Ptr->savedMusic = songNum; } void Overworld_ClearSavedMusic(void) { gSaveBlock1Ptr->savedMusic = 0; } void Overworld_TryMapConnectionMusicTransition(void) { u16 newMusic; u16 currentMusic; if (gDisableMapMusicChangeOnMapLoad == 1) { StopMapMusic(); return; } if (gDisableMapMusicChangeOnMapLoad == 2) { return; } if (FlagGet(FLAG_DONT_TRANSITION_MUSIC) != TRUE) { newMusic = GetWarpDestinationMusic(); currentMusic = GetCurrentMapMusic(); if (currentMusic == MUS_NAMINORI) return; if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_SURFING) && sub_8056124(MUS_NAMINORI)) newMusic = MUS_NAMINORI; if (newMusic != currentMusic) { if (TestPlayerAvatarFlags(PLAYER_AVATAR_FLAG_MACH_BIKE | PLAYER_AVATAR_FLAG_ACRO_BIKE)) FadeOutAndFadeInNewMapMusic(newMusic, 4, 4); else FadeOutAndPlayNewMapMusic(newMusic, 8); } } } void Overworld_ChangeMusicToDefault(void) { u16 currentMusic = GetCurrentMapMusic(); if (currentMusic != GetCurrLocationDefaultMusic()) FadeOutAndPlayNewMapMusic(GetCurrLocationDefaultMusic(), 8); } void Overworld_ChangeMusicTo(u16 newMusic) { u16 currentMusic = GetCurrentMapMusic(); if (currentMusic != newMusic) FadeOutAndPlayNewMapMusic(newMusic, 8); } u8 GetMapMusicFadeoutSpeed(void) { const struct MapHeader *mapHeader = GetDestinationWarpMapHeader(); if (IsMapTypeIndoors(mapHeader->mapType) == TRUE) return 2; else return 4; } void TryFadeOutOldMapMusic(void) { u16 warpMusic = GetWarpDestinationMusic(); if (FlagGet(FLAG_DONT_TRANSITION_MUSIC) != TRUE && warpMusic != GetCurrentMapMusic()) { FadeOutMapMusic(GetMapMusicFadeoutSpeed()); } } bool8 BGMusicStopped(void) { return IsNotWaitingForBGMStop(); } void Overworld_FadeOutMapMusic(void) { FadeOutMapMusic(4); } void PlayAmbientCry(void) { s16 x, y; s8 pan; s8 volume; PlayerGetDestCoords(&x, &y); if (sIsAmbientCryWaterMon == TRUE && !MetatileBehavior_IsSurfable(MapGridGetMetatileBehaviorAt(x, y))) return; pan = (Random() % 88) + 212; volume = (Random() % 30) + 50; if (gDisableMapMusicChangeOnMapLoad == 1) { StopMapMusic(); return; } if (gDisableMapMusicChangeOnMapLoad == 2) { return; } PlayCry2(sAmbientCrySpecies, pan, volume, 1); } void UpdateAmbientCry(s16 *state, u16 *delayCounter) { u8 i, monsCount, divBy; switch (*state) { case 0: if (sAmbientCrySpecies == SPECIES_NONE) *state = 4; else *state = 1; break; case 1: *delayCounter = (Random() % 2400) + 1200; *state = 3; break; case 2: *delayCounter = (Random() % 1200) + 1200; *state = 3; break; case 3: (*delayCounter)--; if (*delayCounter == 0) { PlayAmbientCry(); *state = 2; } break; case 4: break; } } void ChooseAmbientCrySpecies(void) { sAmbientCrySpecies = GetLocalWildMon(&sIsAmbientCryWaterMon); } bool32 sub_8056124(u16 music) { if (music == MUS_CYCLING || music == MUS_NAMINORI) { if (gMapHeader.regionMapSectionId == MAPSEC_KANTO_VICTORY_ROAD || gMapHeader.regionMapSectionId == MAPSEC_ROUTE_23 || gMapHeader.regionMapSectionId == MAPSEC_INDIGO_PLATEAU) return FALSE; } return TRUE; } u8 GetMapTypeByGroupAndId(s8 mapGroup, s8 mapNum) { return Overworld_GetMapHeaderByGroupAndId(mapGroup, mapNum)->mapType; } u8 GetMapTypeByWarpData(struct WarpData *warp) { return GetMapTypeByGroupAndId(warp->mapGroup, warp->mapNum); } u8 GetCurrentMapType(void) { return GetMapTypeByWarpData(&gSaveBlock1Ptr->location); } u8 GetLastUsedWarpMapType(void) { return GetMapTypeByWarpData(&gLastUsedWarp); } u8 GetLastUsedWarpMapSectionId(void) { return Overworld_GetMapHeaderByGroupAndId(gLastUsedWarp.mapGroup, gLastUsedWarp.mapNum)->regionMapSectionId; } bool8 IsMapTypeOutdoors(u8 mapType) { if (mapType == MAP_TYPE_ROUTE || mapType == MAP_TYPE_TOWN || mapType == MAP_TYPE_UNDERWATER || mapType == MAP_TYPE_CITY || mapType == MAP_TYPE_OCEAN_ROUTE) return TRUE; else return FALSE; } bool8 Overworld_MapTypeAllowsTeleportAndFly(u8 mapType) { if (mapType == MAP_TYPE_ROUTE || mapType == MAP_TYPE_TOWN || mapType == MAP_TYPE_OCEAN_ROUTE || mapType == MAP_TYPE_CITY) return TRUE; else return FALSE; } bool8 IsMapTypeIndoors(u8 mapType) { if (mapType == MAP_TYPE_INDOOR || mapType == MAP_TYPE_SECRET_BASE) return TRUE; else return FALSE; } u8 GetSavedWarpRegionMapSectionId(void) { return Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->dynamicWarp.mapGroup, gSaveBlock1Ptr->dynamicWarp.mapNum)->regionMapSectionId; } u8 GetCurrentRegionMapSectionId(void) { return Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum)->regionMapSectionId; } u8 GetCurrentMapBattleScene(void) { return Overworld_GetMapHeaderByGroupAndId(gSaveBlock1Ptr->location.mapGroup, gSaveBlock1Ptr->location.mapNum)->battleType; } const int sUnusedData[] = { 1200, 3600, 1200, 2400, 50, 80, -44, 44 }; const struct UCoords32 gDirectionToVectors[] = { { 0u, 0u}, { 0u, 1u}, { 0u, -1u}, {-1u, 0u}, { 1u, 0u}, {-1u, 1u}, { 1u, 1u}, {-1u, -1u}, { 1u, -1u}, }; const struct BgTemplate sOverworldBgTemplates[] = { { .bg = 0, .charBaseIndex = 2, .mapBaseIndex = 31, .screenSize = 0, .paletteMode = 0, .priority = 0, .baseTile = 0x000 }, { .bg = 1, .charBaseIndex = 0, .mapBaseIndex = 29, .screenSize = 0, .paletteMode = 0, .priority = 1, .baseTile = 0x000 }, { .bg = 2, .charBaseIndex = 0, .mapBaseIndex = 28, .screenSize = 0, .paletteMode = 0, .priority = 2, .baseTile = 0x000 }, { .bg = 3, .charBaseIndex = 0, .mapBaseIndex = 30, .screenSize = 0, .paletteMode = 0, .priority = 3, .baseTile = 0x000 } }; void InitOverworldBgs(void) { MoveSaveBlocks_ResetHeap_(); sub_8056E80(); ResetBgsAndClearDma3BusyFlags(FALSE); InitBgsFromTemplates(0, sOverworldBgTemplates, NELEMS(sOverworldBgTemplates)); SetBgAttribute(1, BG_ATTR_MOSAIC, TRUE); SetBgAttribute(2, BG_ATTR_MOSAIC, TRUE); SetBgAttribute(3, BG_ATTR_MOSAIC, TRUE); gBGTilemapBuffers2 = AllocZeroed(BG_SCREEN_SIZE); gBGTilemapBuffers1 = AllocZeroed(BG_SCREEN_SIZE); gBGTilemapBuffers3 = AllocZeroed(BG_SCREEN_SIZE); SetBgTilemapBuffer(1, gBGTilemapBuffers2); SetBgTilemapBuffer(2, gBGTilemapBuffers1); SetBgTilemapBuffer(3, gBGTilemapBuffers3); InitStandardTextBoxWindows(); ResetBg0(); sub_8069348(); } void InitOverworldBgs_NoResetHeap(void) { ResetBgsAndClearDma3BusyFlags(FALSE); InitBgsFromTemplates(0, sOverworldBgTemplates, NELEMS(sOverworldBgTemplates)); SetBgAttribute(1, BG_ATTR_MOSAIC, TRUE); SetBgAttribute(2, BG_ATTR_MOSAIC, TRUE); SetBgAttribute(3, BG_ATTR_MOSAIC, TRUE); gBGTilemapBuffers2 = AllocZeroed(BG_SCREEN_SIZE); gBGTilemapBuffers1 = AllocZeroed(BG_SCREEN_SIZE); gBGTilemapBuffers3 = AllocZeroed(BG_SCREEN_SIZE); SetBgTilemapBuffer(1, gBGTilemapBuffers2); SetBgTilemapBuffer(2, gBGTilemapBuffers1); SetBgTilemapBuffer(3, gBGTilemapBuffers3); InitStandardTextBoxWindows(); ResetBg0(); sub_8069348(); } void CleanupOverworldWindowsAndTilemaps(void) { FreeAllOverworldWindowBuffers(); Free(gBGTilemapBuffers3); Free(gBGTilemapBuffers1); Free(gBGTilemapBuffers2); } void ResetSafariZoneFlag_(void) { ResetSafariZoneFlag(); } bool32 IsUpdateLinkStateCBActive(void) { if (gMain.callback1 == CB1_UpdateLinkState) return TRUE; else return FALSE; } void DoCB1_Overworld(u16 newKeys, u16 heldKeys) { struct FieldInput fieldInput; sub_8112B3C(); sub_805BEB8(); FieldClearPlayerInput(&fieldInput); FieldGetPlayerInput(&fieldInput, newKeys, heldKeys); FieldInput_HandleCancelSignpost(&fieldInput); if (!ScriptContext2_IsEnabled()) { if (ProcessPlayerFieldInput(&fieldInput) == TRUE) { if (gUnknown_3005E88 == 2) sub_81127F8(&gInputToStoreInQuestLogMaybe); ScriptContext2_Enable(); DismissMapNamePopup(); } else { player_step(fieldInput.dpadDirection, newKeys, heldKeys); } } RunQuestLogCB(); } void DoCB1_Overworld_QuestLogPlayback(void) { struct FieldInput fieldInput; sub_8112B3C(); sub_805BEB8(); sub_8111C68(); FieldClearPlayerInput(&fieldInput); fieldInput = gUnknown_3005E90; FieldInput_HandleCancelSignpost(&fieldInput); if (!ScriptContext2_IsEnabled()) { if (ProcessPlayerFieldInput(&fieldInput) == TRUE) { ScriptContext2_Enable(); DismissMapNamePopup(); } else { RunQuestLogCB(); } } else if (sub_8111CD0() == TRUE) { RunQuestLogCB(); } FieldClearPlayerInput(&gUnknown_3005E90); } void CB1_Overworld(void) { if (gMain.callback2 == CB2_Overworld) { if (sub_8112CAC() == TRUE || gQuestLogState == QL_STATE_2) DoCB1_Overworld_QuestLogPlayback(); else DoCB1_Overworld(gMain.newKeys, gMain.heldKeys); } } void OverworldBasic(void) { ScriptContext2_RunScript(); RunTasks(); AnimateSprites(); CameraUpdate(); sub_8115798(); UpdateCameraPanning(); BuildOamBuffer(); UpdatePaletteFade(); UpdateTilesetAnimations(); DoScheduledBgTilemapCopiesToVram(); } // This CB2 is used when starting void CB2_OverworldBasic(void) { OverworldBasic(); } void CB2_Overworld(void) { bool32 fading = !!gPaletteFade.active; if (fading) SetVBlankCallback(NULL); OverworldBasic(); if (fading) SetFieldVBlankCallback(); } void SetMainCallback1(MainCallback cb) { gMain.callback1 = cb; } bool8 map_post_load_hook_exec(void) { if (gFieldCallback2) { if (!gFieldCallback2()) { return FALSE; } else { gFieldCallback2 = NULL; gFieldCallback = NULL; } } else { if (gFieldCallback) gFieldCallback(); else FieldCB_DefaultWarpExit(); gFieldCallback = NULL; } return TRUE; } void CB2_NewGame(void) { FieldClearVBlankHBlankCallbacks(); StopMapMusic(); ResetSafariZoneFlag_(); NewGameInitData(); ResetInitialPlayerAvatarState(); PlayTimeCounter_Start(); ScriptContext1_Init(); ScriptContext2_Disable(); gFieldCallback = FieldCB_WarpExitFadeFromBlack; gFieldCallback2 = NULL; do_load_map_stuff_loop(&gMain.state); SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); SetMainCallback2(CB2_Overworld); } void CB2_WhiteOut(void) { u8 val; if (++gMain.state >= 120) { FieldClearVBlankHBlankCallbacks(); StopMapMusic(); ResetSafariZoneFlag_(); DoWhiteOut(); SetInitialPlayerAvatarStateWithDirection(DIR_NORTH); ScriptContext1_Init(); ScriptContext2_Disable(); gFieldCallback = FieldCB_RushInjuredPokemonToCenter; val = 0; do_load_map_stuff_loop(&val); sub_8112364(); SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); SetMainCallback2(CB2_Overworld); } } void CB2_LoadMap(void) { FieldClearVBlankHBlankCallbacks(); ScriptContext1_Init(); ScriptContext2_Disable(); SetMainCallback1(NULL); SetMainCallback2(CB2_DoChangeMap); gMain.savedCallback = CB2_LoadMap2; } void CB2_LoadMap2(void) { do_load_map_stuff_loop(&gMain.state); if (sub_8113748() == TRUE) { sub_81119C8(); } else { SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); SetMainCallback2(CB2_Overworld); } } void CB2_ReturnToFieldCableClub(void) { FieldClearVBlankHBlankCallbacks(); gFieldCallback = FieldCB_ReturnToFieldWirelessLink; SetMainCallback2(c2_80567AC); } void c2_80567AC(void) { if (map_loading_iteration_3(&gMain.state)) { SetFieldVBlankCallback(); SetMainCallback1(CB1_UpdateLinkState); ResetAllMultiplayerState(); SetMainCallback2(CB2_Overworld); } } void CB2_ReturnToField(void) { if (IsUpdateLinkStateCBActive() == TRUE) { SetMainCallback2(CB2_ReturnToFieldLink); } else { FieldClearVBlankHBlankCallbacks(); SetMainCallback2(CB2_ReturnToFieldLocal); } } void CB2_ReturnToFieldLocal(void) { if (sub_8056CD8(&gMain.state)) { SetFieldVBlankCallback(); SetMainCallback2(CB2_Overworld); } } void CB2_ReturnToFieldLink(void) { if (!sub_8058244() && map_loading_iteration_2_link(&gMain.state)) SetMainCallback2(CB2_Overworld); } void CB2_ReturnToFieldFromMultiplayer(void) { FieldClearVBlankHBlankCallbacks(); StopMapMusic(); SetMainCallback1(CB1_UpdateLinkState); ResetAllMultiplayerState(); if (gWirelessCommType != 0) gFieldCallback = FieldCB_ReturnToFieldWirelessLink; else gFieldCallback = FieldCB_ReturnToFieldCableLink; ScriptContext1_Init(); ScriptContext2_Disable(); CB2_ReturnToField(); } void CB2_ReturnToFieldWithOpenMenu(void) { FieldClearVBlankHBlankCallbacks(); gFieldCallback2 = FieldCB_ReturnToFieldOpenStartMenu; CB2_ReturnToField(); } void CB2_ReturnToFieldContinueScript(void) { FieldClearVBlankHBlankCallbacks(); gFieldCallback = FieldCB_ContinueScript; CB2_ReturnToField(); } void CB2_ReturnToFieldContinueScriptPlayMapMusic(void) { FieldClearVBlankHBlankCallbacks(); gFieldCallback = FieldCB_ContinueScriptHandleMusic; CB2_ReturnToField(); } void sub_80568FC(void) { FieldClearVBlankHBlankCallbacks(); gFieldCallback = FieldCB_WarpExitFadeFromBlack; CB2_ReturnToField(); } void sub_8056918(void) { if (SHOW_MAP_NAME_ENABLED) ShowMapNamePopup(FALSE); FieldCB_WarpExitFadeFromBlack(); } void CB2_ContinueSavedGame(void) { FieldClearVBlankHBlankCallbacks(); StopMapMusic(); ResetSafariZoneFlag_(); LoadSaveblockMapHeader(); LoadSaveblockObjEventScripts(); UnfreezeObjectEvents(); sub_8054E40(); InitMapFromSavedGame(); PlayTimeCounter_Start(); ScriptContext1_Init(); ScriptContext2_Disable(); gFieldCallback2 = NULL; gUnknown_2031DE0 = TRUE; if (UseContinueGameWarp() == TRUE) { ClearContinueGameWarpStatus(); SetWarpDestinationToContinueGameWarp(); WarpIntoMap(); SetMainCallback2(CB2_LoadMap); } else { gFieldCallback = sub_8056918; SetMainCallback1(CB1_Overworld); CB2_ReturnToField(); } } void FieldClearVBlankHBlankCallbacks(void) { if (UsedPokemonCenterWarp() == TRUE) CloseLink(); if (gWirelessCommType != 0) { EnableInterrupts(INTR_FLAG_VBLANK | INTR_FLAG_VCOUNT | INTR_FLAG_TIMER3 | INTR_FLAG_SERIAL); DisableInterrupts(INTR_FLAG_HBLANK); } else { DisableInterrupts(INTR_FLAG_HBLANK); EnableInterrupts(INTR_FLAG_VBLANK); } SetVBlankCallback(NULL); SetHBlankCallback(NULL); } void SetFieldVBlankCallback(void) { SetVBlankCallback(VBlankCB_Field); } void VBlankCB_Field(void) { LoadOam(); ProcessSpriteCopyRequests(); ScanlineEffect_InitHBlankDmaTransfer(); FieldUpdateBgTilemapScroll(); TransferPlttBuffer(); TransferTilesetAnimsBuffer(); } void InitCurrentFlashLevelScanlineEffect(void) { u8 flashLevel = Overworld_GetFlashLevel(); if (flashLevel != 0) { WriteFlashScanlineEffectBuffer(flashLevel); ScanlineEffect_SetParams((struct ScanlineEffectParams){ .dmaDest = ®_WIN0H, .dmaControl = (2 >> 1) | ((DMA_16BIT | DMA_DEST_RELOAD | DMA_SRC_INC | DMA_REPEAT | DMA_START_HBLANK | DMA_ENABLE) << 16), .initState = 1, .unused9 = 0 }); } } bool32 map_loading_iteration_3(u8 *state) { switch (*state) { case 0: InitOverworldBgs(); ScriptContext1_Init(); ScriptContext2_Disable(); (*state)++; break; case 1: mli0_load_map(TRUE); (*state)++; break; case 2: sub_8057024(TRUE); (*state)++; break; case 3: sub_8057178(); sub_8057074(); sub_80571A8(); SetCameraToTrackGuestPlayer(); SetHelpContextForMap(); (*state)++; break; case 4: InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); (*state)++; break; case 5: move_tilemap_camera_to_upper_left_corner(); (*state)++; break; case 6: copy_map_tileset1_to_vram(gMapHeader.mapLayout); (*state)++; break; case 7: copy_map_tileset2_to_vram(gMapHeader.mapLayout); (*state)++; break; case 8: if (FreeTempTileDataBuffersIfPossible() != TRUE) { apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); (*state)++; } break; case 9: DrawWholeMapView(); (*state)++; break; case 10: InitTilesetAnimations(); (*state)++; break; case 11: if (gWirelessCommType != 0) { LoadWirelessStatusIndicatorSpriteGfx(); CreateWirelessStatusIndicatorSprite(0, 0); } (*state)++; break; case 12: if (map_post_load_hook_exec()) (*state)++; break; case 13: return TRUE; } return FALSE; } bool32 load_map_stuff(u8 *state, bool32 a1) { switch (*state) { case 0: InitOverworldBgs(); FieldClearVBlankHBlankCallbacks(); mli0_load_map(a1); (*state)++; break; case 1: sub_8111F14(); (*state)++; break; case 2: sub_8057024(a1); (*state)++; break; case 3: if (sub_8113748() == TRUE) return TRUE; (*state)++; break; case 4: mli4_mapscripts_and_other(); sub_8057114(); if (gQuestLogState != QL_STATE_2) { sub_80CC534(); sub_80CC59C(); } SetHelpContextForMap(); (*state)++; break; case 5: InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); (*state)++; break; case 6: move_tilemap_camera_to_upper_left_corner(); (*state)++; break; case 7: copy_map_tileset1_to_vram(gMapHeader.mapLayout); (*state)++; break; case 8: copy_map_tileset2_to_vram(gMapHeader.mapLayout); (*state)++; break; case 9: if (FreeTempTileDataBuffersIfPossible() != TRUE) { apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); (*state)++; } break; case 10: DrawWholeMapView(); (*state)++; break; case 11: InitTilesetAnimations(); (*state)++; break; case 12: if (GetLastUsedWarpMapSectionId() != gMapHeader.regionMapSectionId && MapHasPreviewScreen_HandleQLState2(gMapHeader.regionMapSectionId, MPS_TYPE_FOREST) == TRUE) { MapPreview_LoadGfx(gMapHeader.regionMapSectionId); MapPreview_StartForestTransition(gMapHeader.regionMapSectionId); } else if (SHOW_MAP_NAME_ENABLED) { ShowMapNamePopup(FALSE); } (*state)++; break; case 13: if (map_post_load_hook_exec()) (*state)++; break; case 14: return TRUE; } return FALSE; } bool32 sub_8056CD8(u8 *state) { switch (*state) { case 0: InitOverworldBgs(); sub_8111F14(); sub_8057024(FALSE); sub_8057100(); sub_8057114(); (*state)++; break; case 1: (*state)++; break; case 2: sub_8056F08(); SetHelpContextForMap(); (*state)++; break; case 3: if (map_post_load_hook_exec()) (*state)++; break; case 4: return TRUE; } return FALSE; } bool32 map_loading_iteration_2_link(u8 *state) { switch (*state) { case 0: InitOverworldBgs(); FieldClearVBlankHBlankCallbacks(); (*state)++; break; case 1: sub_8111F14(); sub_8057024(1); (*state)++; break; case 2: CreateLinkPlayerSprites(); sub_8057100(); SetCameraToTrackGuestPlayer_2(); SetHelpContextForMap(); (*state)++; break; case 3: InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); (*state)++; break; case 4: move_tilemap_camera_to_upper_left_corner(); (*state)++; break; case 5: copy_map_tileset1_to_vram(gMapHeader.mapLayout); (*state)++; break; case 6: copy_map_tileset2_to_vram(gMapHeader.mapLayout); (*state)++; break; case 7: if (FreeTempTileDataBuffersIfPossible() != TRUE) { apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); (*state)++; } break; case 8: DrawWholeMapView(); (*state)++; break; case 9: InitTilesetAnimations(); (*state)++; break; case 10: (*state)++; break; case 11: if (gWirelessCommType != 0) { LoadWirelessStatusIndicatorSpriteGfx(); CreateWirelessStatusIndicatorSprite(0, 0); } (*state)++; break; case 12: if (map_post_load_hook_exec()) (*state)++; break; case 13: SetFieldVBlankCallback(); (*state)++; return TRUE; } return FALSE; } void do_load_map_stuff_loop(u8 *state) { while (!load_map_stuff(state, FALSE)) ; } void MoveSaveBlocks_ResetHeap_(void) { MoveSaveBlocks_ResetHeap(); } void sub_8056E80(void) { SetGpuReg(REG_OFFSET_DISPCNT, 0); ScanlineEffect_Stop(); DmaClear16(3, PLTT + 2, PLTT_SIZE - 2); DmaFillLarge16(3, 0, (void *)(VRAM + 0x0), 0x18000, 0x1000); ResetOamRange(0, 128); LoadOam(); } void sub_8056F08(void) { InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); mapdata_load_assets_to_gpu_and_full_redraw(); } void InitOverworldGraphicsRegisters(void) { ClearScheduledBgCopiesToVram(); ResetTempTileDataBuffers(); SetGpuReg(REG_OFFSET_MOSAIC, 0); SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ); SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG0 | WINOUT_WINOBJ_BG0); SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(0, 255)); SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(0, 255)); SetGpuReg(REG_OFFSET_WIN1H, WIN_RANGE(255, 255)); SetGpuReg(REG_OFFSET_WIN1V, WIN_RANGE(255, 255)); SetGpuReg(REG_OFFSET_BLDCNT, gOverworldBackgroundLayerFlags[1] | gOverworldBackgroundLayerFlags[2] | gOverworldBackgroundLayerFlags[3] | BLDCNT_TGT2_OBJ | BLDCNT_EFFECT_BLEND); SetGpuReg(REG_OFFSET_BLDALPHA, BLDALPHA_BLEND(13, 7)); ScheduleBgCopyTilemapToVram(1); ScheduleBgCopyTilemapToVram(2); ScheduleBgCopyTilemapToVram(3); SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | 0x20 | DISPCNT_OBJ_ON | DISPCNT_WIN0_ON | DISPCNT_WIN1_ON); ShowBg(0); ShowBg(1); ShowBg(2); ShowBg(3); ChangeBgX(0, 0, 0); ChangeBgY(0, 0, 0); ChangeBgX(1, 0, 0); ChangeBgY(1, 0, 0); ChangeBgX(2, 0, 0); ChangeBgY(2, 0, 0); ChangeBgX(3, 0, 0); ChangeBgY(3, 0, 0); } void sub_8057024(u32 a1) { ResetTasks(); ResetSpriteData(); ResetPaletteFade(); ScanlineEffect_Clear(); ResetAllPicSprites(); ResetCameraUpdateInfo(); InstallCameraPanAheadCallback(); if (!a1) InitObjectEventPalettes(0); else InitObjectEventPalettes(1); FieldEffectActiveListClear(); StartWeather(); ResumePausedWeather(); if (!a1) SetUpFieldTasks(); RunOnResumeMapScript(); } void sub_8057074(void) { gTotalCameraPixelOffsetX = 0; gTotalCameraPixelOffsetY = 0; ResetObjectEvents(); TrySpawnObjectEvents(0, 0); TryRunOnWarpIntoMapScript(); } void mli4_mapscripts_and_other(void) { s16 x, y; struct InitialPlayerAvatarState *player; gTotalCameraPixelOffsetX = 0; gTotalCameraPixelOffsetY = 0; ResetObjectEvents(); GetCameraFocusCoords(&x, &y); player = GetInitialPlayerAvatarState(); InitPlayerAvatar(x, y, player->direction, gSaveBlock2Ptr->playerGender); SetPlayerAvatarTransitionFlags(player->transitionFlags); ResetInitialPlayerAvatarState(); TrySpawnObjectEvents(0, 0); TryRunOnWarpIntoMapScript(); } void sub_8057100(void) { sub_805EDF0(0, 0); RunOnReturnToFieldMapScript(); } void sub_8057114(void) { gObjectEvents[gPlayerAvatar.objectEventId].trackedByCamera = 1; InitCameraUpdateCallback(gPlayerAvatar.spriteId); } void SetCameraToTrackGuestPlayer(void) { InitCameraUpdateCallback(GetSpriteForLinkedPlayer(gLocalLinkPlayerId)); } // Duplicate function. void SetCameraToTrackGuestPlayer_2(void) { InitCameraUpdateCallback(GetSpriteForLinkedPlayer(gLocalLinkPlayerId)); } void sub_8057178(void) { u16 x, y; GetCameraFocusCoords(&x, &y); // This is a hack of some kind; it's undone in sub_8086B14, which is called // soon after this function. SetCameraFocusCoords(x + gLocalLinkPlayerId, y); } void sub_80571A8(void) { u16 i; u16 x, y; GetCameraFocusCoords(&x, &y); x -= gLocalLinkPlayerId; for (i = 0; i < gFieldLinkPlayerCount; i++) { SpawnLinkPlayerObjectEvent(i, i + x, y, gLinkPlayers[i].gender); CreateLinkPlayerSprite(i, gLinkPlayers[i].version); } ClearAllPlayerKeys(); } void CreateLinkPlayerSprites(void) { u16 i; for (i = 0; i < gFieldLinkPlayerCount; i++) CreateLinkPlayerSprite(i, gLinkPlayers[i].version); } // Credits void sub_805726C(void) { FieldClearVBlankHBlankCallbacks(); gUnknown_2036E28 = 1; ScriptContext1_Init(); ScriptContext2_Disable(); SetMainCallback1(NULL); SetMainCallback2(CB2_DoChangeMap); gMain.savedCallback = sub_80572D8; } void sub_80572A8(void) { FieldClearVBlankHBlankCallbacks(); gUnknown_2036E28 = 1; LoadSaveblockMapHeader(); ScriptContext1_Init(); ScriptContext2_Disable(); SetMainCallback1(NULL); SetMainCallback2(sub_80572D8); } void sub_80572D8(void) { sub_8057300(&gMain.state); SetFieldVBlankCallback(); SetMainCallback1(CB1_Overworld); SetMainCallback2(CB2_Overworld); } void sub_8057300(u8 *state) { while (!sub_8057314(state)) ; } bool32 sub_8057314(u8 *state) { switch (*state) { case 0: InitOverworldBgs(); FieldClearVBlankHBlankCallbacks(); sub_8111F14(); sub_81113E4(); sub_8111438(); if (sub_8110AC8() == 2) { gUnknown_2031DE0 = 0; mli0_load_map(FALSE); } else { gUnknown_2031DE0 = 1; sub_80559A8(); } (*state)++; break; case 1: sub_8110FCC(); (*state)++; break; case 2: sub_8057024(0); (*state)++; break; case 3: sub_8057100(); sub_8057114(); (*state)++; break; case 4: InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); (*state)++; break; case 5: move_tilemap_camera_to_upper_left_corner(); (*state)++; break; case 6: copy_map_tileset1_to_vram(gMapHeader.mapLayout); (*state)++; break; case 7: copy_map_tileset2_to_vram(gMapHeader.mapLayout); (*state)++; break; case 8: if (FreeTempTileDataBuffersIfPossible() != TRUE) { apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); (*state)++; } break; case 9: DrawWholeMapView(); (*state)++; break; case 10: InitTilesetAnimations(); sub_815A540(); (*state)++; break; default: if (map_post_load_hook_exec()) return TRUE; break; } return FALSE; } void sub_8057430(void) { FieldClearVBlankHBlankCallbacks(); StopMapMusic(); gUnknown_2036E28 = 3; ResetSafariZoneFlag_(); LoadSaveblockMapHeader(); LoadSaveblockObjEventScripts(); UnfreezeObjectEvents(); sub_8054E40(); InitMapFromSavedGame(); PlayTimeCounter_Start(); ScriptContext1_Init(); gUnknown_2031DE0 = TRUE; if (UseContinueGameWarp() == TRUE) { ClearContinueGameWarpStatus(); SetWarpDestinationToContinueGameWarp(); WarpIntoMap(); SetMainCallback2(CB2_LoadMap); } else { SetMainCallback1(CB1_Overworld); CB2_ReturnToField(); } } void Overworld_CreditsMainCB(void) { bool8 fading = !!gPaletteFade.active; if (fading) SetVBlankCallback(NULL); RunTasks(); AnimateSprites(); sub_805ACF0(); UpdateCameraPanning(); BuildOamBuffer(); UpdatePaletteFade(); UpdateTilesetAnimations(); DoScheduledBgTilemapCopiesToVram(); if (fading) SetFieldVBlankCallback(); } bool8 sub_80574EC(void) { if (gPaletteFade.active) return TRUE; else return FALSE; } bool32 Overworld_DoScrollSceneForCredits(u8 *state_p, const struct CreditsOverworldCmd * script, u8 a2) { gUnknown_2031DE4 = script; gUnknown_2036E28 = a2; return sub_8057528(state_p, 0); } bool32 sub_8057528(u8 *state, u8 unused) { struct WarpData warp; switch (*state) { case 0: gUnknown_2031DEA = 0; gUnknown_2031DE8 = 0; (*state)++; return FALSE; case 1: warp.mapGroup = gUnknown_2031DE4[gUnknown_2031DEA].unk_2; warp.mapNum = gUnknown_2031DE4[gUnknown_2031DEA].unk_4; warp.warpId = -1; gUnknown_2031DEA++; warp.x = gUnknown_2031DE4[gUnknown_2031DEA].unk_0; warp.y = gUnknown_2031DE4[gUnknown_2031DEA].unk_2; sWarpDestination = warp; gUnknown_2031DE8 = gUnknown_2031DE4[gUnknown_2031DEA].unk_4; WarpIntoMap(); gPaletteFade.bufferTransferDisabled = TRUE; ScriptContext1_Init(); ScriptContext2_Disable(); SetMainCallback1(NULL); gFieldCallback2 = sub_80574EC; gMain.state = 0; (*state)++; return FALSE; case 2: if (sub_8057650()) { (*state)++; return FALSE; } break; case 3: gFieldCamera.callback = sub_8057748; SetFieldVBlankCallback(); *state = 0; return TRUE; } return FALSE; } bool8 sub_8057650(void) { u8 *state = &gMain.state; switch (*state) { case 0: InitOverworldBgs_NoResetHeap(); mli0_load_map(FALSE); (*state)++; break; case 1: ScanlineEffect_Clear(); ResetAllPicSprites(); ResetCameraUpdateInfo(); InstallCameraPanAheadCallback(); FieldEffectActiveListClear(); StartWeather(); ResumePausedWeather(); SetUpFieldTasks(); RunOnResumeMapScript(); (*state)++; break; case 2: InitCurrentFlashLevelScanlineEffect(); InitOverworldGraphicsRegisters(); (*state)++; break; case 3: move_tilemap_camera_to_upper_left_corner(); (*state)++; break; case 4: copy_map_tileset1_to_vram(gMapHeader.mapLayout); (*state)++; break; case 5: copy_map_tileset2_to_vram(gMapHeader.mapLayout); (*state)++; break; case 6: if (FreeTempTileDataBuffersIfPossible() != TRUE) { apply_map_tileset1_tileset2_palette(gMapHeader.mapLayout); (*state)++; } break; case 7: DrawWholeMapView(); (*state)++; break; case 8: InitTilesetAnimations(); gPaletteFade.bufferTransferDisabled = FALSE; FadeSelectedPals(FADE_FROM_BLACK, 0, 0x3FFFFFFF); (*state)++; break; default: return TRUE; } return FALSE; } void sub_8057748(struct CameraObject * camera) { if (gUnknown_2031DE8 == 0) { gUnknown_2031DEA++; switch (gUnknown_2031DE4[gUnknown_2031DEA].unk_0) { case 0xFC: case 0xFE: return; case 0xFF: camera->movementSpeedX = 0; camera->movementSpeedY = 0; camera->callback = NULL; CreateTask(sub_805781C, 0); return; case 0xFB: camera->movementSpeedX = 0; camera->movementSpeedY = 0; camera->callback = NULL; break; case 0xFD: camera->movementSpeedX = 0; camera->movementSpeedY = 0; camera->callback = NULL; return; default: gUnknown_2031DE8 = gUnknown_2031DE4[gUnknown_2031DEA].unk_4; camera->movementSpeedX = gUnknown_2031DE4[gUnknown_2031DEA].unk_0; camera->movementSpeedY = gUnknown_2031DE4[gUnknown_2031DEA].unk_2; break; } } if (gUnknown_2031DE4[gUnknown_2031DEA].unk_0 == 0xFF) { camera->movementSpeedX = 0; camera->movementSpeedY = 0; } else gUnknown_2031DE8--; } void sub_805781C(u8 taskId) { BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB_BLACK); gTasks[taskId].func = sub_8057854; } void sub_8057854(u8 taskId) { if (!gPaletteFade.active) { CleanupOverworldWindowsAndTilemaps(); SetMainCallback2(CB2_LoadMap); DestroyTask(taskId); } }