#include "global.h" #include "gflib.h" #include "event_data.h" #include "event_scripts.h" #include "field_camera.h" #include "field_player_avatar.h" #include "field_specials.h" #include "fieldmap.h" #include "heal_location.h" #include "load_save.h" #include "money.h" #include "overworld.h" #include "roamer.h" #include "script.h" #include "script_pokemon_util.h" #include "tileset_anims.h" #include "constants/maps.h" #include "constants/flags.h" #include "constants/species.h" struct InitialPlayerAvatarState { u8 transitionFlags; u8 direction; u8 unk2; }; EWRAM_DATA struct WarpData gLastUsedWarp = {}; EWRAM_DATA struct WarpData sWarpDestination = {}; EWRAM_DATA struct WarpData gFixedDiveWarp = {}; EWRAM_DATA struct WarpData gFixedHoleWarp = {}; EWRAM_DATA struct InitialPlayerAvatarState gUnknown_2031DD4 = {}; EWRAM_DATA bool8 gDisableMapMusicChangeOnMapLoad = FALSE; EWRAM_DATA u16 gUnknown_2031DDA = SPECIES_NONE; EWRAM_DATA bool8 gUnknown_2031DDC = 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] = {}; u8 CountBadgesForOverworldWhiteOutLossCalculation(void); void Overworld_ResetStateAfterWhitingOut(void); void Overworld_SetWhiteoutRespawnPoint(void); void sub_805610C(void); extern const struct MapLayout * gMapLayouts[]; extern const struct MapHeader *const *gMapGroups[]; 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 sub_8054BC8(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_UNK_802); 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_UNK_802); 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_UNK_802); 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_UNK_802); 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); sub_805610C(); UpdateLocationHistoryForRoamer(); RoamerMoveToOtherLocationSet(); } 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); } } 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 sub_80550A8(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; } } } 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; } 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; }