#include "global.h" #include "secret_base.h" #include "decoration.h" #include "event_data.h" #include "field_camera.h" #include "field_effect.h" #include "field_fadetransition.h" #include "field_player_avatar.h" #include "field_specials.h" #include "field_weather.h" #include "fieldmap.h" #include "fldeff_decoration.h" #include "link.h" #include "main.h" #include "sound.h" #include "constants/songs.h" #include "constants/maps.h" #include "map_name_popup.h" #include "menu.h" #include "menu_helpers.h" #include "metatile_behavior.h" #include "new_game.h" #include "palette.h" #include "pokemon.h" #include "overworld.h" #include "script.h" #include "sound.h" #include "string_util.h" #include "strings.h" #include "task.h" #include "text.h" #include "constants/event_bg.h" #include "constants/event_objects.h" #include "constants/decorations.h" #include "constants/items.h" #include "constants/map_types.h" #include "constants/moves.h" #include "constants/species.h" #include "constants/vars.h" static void sub_80BC7D8(u8 taskId); static void sub_80BC824(u8 taskId); static u8 sub_80BC948(u8 a); static void sub_80BC980(u8 taskId); static void sub_80BC9E4(u8 taskId); static void sub_80BCA84(u8); static void sub_80BCAEC(u8 taskId); static void sub_80BCB90(u8); static void sub_80BCBC0(u8); static void sub_80BCBF8(u8 taskId); static void sub_80BCC54(u8 taskId); static void Task_SecretBasePC_Registry(u8 taskId); static u8 GetSecretBaseOwnerType(u8 secretBaseIndex); extern u8 SecretBase_EventScript_PCCancel[]; extern u8 SecretBase_EventScript_ShowRegisterMenu[]; EWRAM_DATA u8 gCurrentSecretBaseId = 0; const struct { u16 unk_083D1358_0; u16 unk_083D1358_1; } gUnknown_083D1358[] = { {0x26, 0x36}, {0x27, 0x37}, {0x1a0, 0x1a1}, {0x1a8, 0x1a9}, {0x1b0, 0x1b1}, {0x208, 0x210}, {0x271, 0x278} }; const u8 gUnknown_083D1374[] = { MAP_NUM(SECRET_BASE_RED_CAVE1), 0, 1, 3, MAP_NUM(SECRET_BASE_RED_CAVE2), 0, 5, 9, MAP_NUM(SECRET_BASE_RED_CAVE3), 0, 1, 3, MAP_NUM(SECRET_BASE_RED_CAVE4), 0, 7, 13, MAP_NUM(SECRET_BASE_BROWN_CAVE1), 0, 2, 3, MAP_NUM(SECRET_BASE_BROWN_CAVE2), 0, 9, 2, MAP_NUM(SECRET_BASE_BROWN_CAVE3), 0, 13, 4, MAP_NUM(SECRET_BASE_BROWN_CAVE4), 0, 1, 2, MAP_NUM(SECRET_BASE_BLUE_CAVE1), 0, 1, 3, MAP_NUM(SECRET_BASE_BLUE_CAVE2), 0, 1, 2, MAP_NUM(SECRET_BASE_BLUE_CAVE3), 0, 3, 15, MAP_NUM(SECRET_BASE_BLUE_CAVE4), 0, 3, 14, MAP_NUM(SECRET_BASE_YELLOW_CAVE1), 0, 9, 3, MAP_NUM(SECRET_BASE_YELLOW_CAVE2), 0, 8, 7, MAP_NUM(SECRET_BASE_YELLOW_CAVE3), 0, 3, 6, MAP_NUM(SECRET_BASE_YELLOW_CAVE4), 0, 5, 9, MAP_NUM(SECRET_BASE_TREE1), 0, 2, 3, MAP_NUM(SECRET_BASE_TREE2), 0, 5, 6, MAP_NUM(SECRET_BASE_TREE3), 0, 15, 3, MAP_NUM(SECRET_BASE_TREE4), 0, 4, 10, MAP_NUM(SECRET_BASE_SHRUB1), 0, 3, 3, MAP_NUM(SECRET_BASE_SHRUB2), 0, 1, 2, MAP_NUM(SECRET_BASE_SHRUB3), 0, 7, 8, MAP_NUM(SECRET_BASE_SHRUB4), 0, 9, 6 }; const struct MenuAction2 gUnknown_083D13D4[] = { {SecretBaseText_DelRegist, sub_80BCA84}, {gOtherText_Exit, sub_80BCBF8} }; const struct YesNoFuncTable gUnknown_083D13E4 = { sub_80BCB90, sub_80BCBC0 }; static const u8 sSecretBaseOwnerGfxIds[] = { // Male OBJ_EVENT_GFX_YOUNGSTER, OBJ_EVENT_GFX_BUG_CATCHER, OBJ_EVENT_GFX_BOY_4, OBJ_EVENT_GFX_CAMPER, OBJ_EVENT_GFX_MAN_4, // Female OBJ_EVENT_GFX_LASS, OBJ_EVENT_GFX_GIRL_3, OBJ_EVENT_GFX_WOMAN_3, OBJ_EVENT_GFX_PICNICKER, OBJ_EVENT_GFX_WOMAN_7, }; extern u8 gUnknown_081A2E14[]; extern u8 UnknownString_81A1BB2[]; extern u8 UnknownString_81A1F67[]; extern u8 UnknownString_81A2254[]; extern u8 UnknownString_81A25C3[]; extern u8 UnknownString_81A2925[]; extern u8 UnknownString_81A1D74[]; extern u8 UnknownString_81A20C9[]; extern u8 UnknownString_81A2439[]; extern u8 UnknownString_81A2B2A[]; extern u8 UnknownString_81A2754[]; void ClearSecretBase(struct SecretBaseRecord *record) { u16 i; u16 j; record->secretBaseId = 0; for (i = 0; i < OT_NAME_LENGTH; i++) record->playerName[i] = 0xff; for (i = 0; i < 4; i++) record->trainerId[i] = 0x00; record->numSecretBasesReceived = 0; record->numTimesEntered = 0; record->unused = 0; record->toRegister = 0; record->gender = 0; record->battledOwnerToday = 0; record->registryStatus = 0; for (i = 0; i < 16; i++) { record->decorations[i] = 0; record->decorationPos[i] = 0; } for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) record->party.moves[i * 4 + j] = 0; record->party.personality[i] = 0; record->party.EVs[i] = 0; record->party.species[i] = 0; record->party.heldItems[i] = 0; record->party.levels[i] = 0; } } void ResetSecretBase(u8 idx) { ClearSecretBase(&gSaveBlock1.secretBases[idx]); } void ResetSecretBases(void) { u16 i; for (i = 0; i < MAX_SECRET_BASES; i++) ResetSecretBase(i); } void sub_80BB5D0(void) { gCurrentSecretBaseId = gSpecialVar_0x8004; } void SetCurrentSecretBaseVar(void) { u16 i; gSpecialVar_Result = 0; for (i = 0; i < MAX_SECRET_BASES; i++) { if (gCurrentSecretBaseId == gSaveBlock1.secretBases[i].secretBaseId) { gSpecialVar_Result = 1; VarSet(VAR_CURRENT_SECRET_BASE, i); break; } } } void CheckPlayerHasSecretBase(void) { if (gSaveBlock1.secretBases[0].secretBaseId) gSpecialVar_Result = 1; else gSpecialVar_Result = 0; } u8 sub_80BB66C(void) { s16 x, y; s16 v0; GetXYCoordsOneStepInFrontOfPlayer(&x, &y); v0 = MapGridGetMetatileBehaviorAt(x, y) & 0xFFF; if (v0 == 0x90 || v0 == 0x91) return 1; else if (v0 == 0x92 || v0 == 0x93) return 2; else if (v0 == 0x9a || v0 == 0x9b) return 3; else if (v0 == 0x94 || v0 == 0x95) return 4; else if (v0 == 0x96 || v0 == 0x97 || v0 == 0x9c || v0 == 0x9d) return 5; else if (v0 == 0x98 || v0 == 0x99) return 6; return 0; } void sub_80BB70C(void) { gSpecialVar_0x8007 = sub_80BB66C(); } s16 unref_sub_80BB724(u16 *a0, u8 a1) { u16 v2; for (v2 = 0; v2 < 0x200; v2++) { if ((a0[v2] & 0xFFF) == a1) return v2; } return -1; } void sub_80BB764(s16 *arg1, s16 *arg2, u16 arg3) { s16 x, y; for (y=0; yheight; y++) { for (x=0; xwidth; x++) { if ((gMapHeader.mapLayout->map[y * gMapHeader.mapLayout->width + x] & 0x3ff) == arg3) { *arg1 = x; *arg2 = y; return; } } } } void SetOpenedSecretBaseMetatile(void) { s16 x, y; s16 tile_id; u16 idx; GetXYCoordsOneStepInFrontOfPlayer(&x, &y); tile_id = MapGridGetMetatileIdAt(x, y); for (idx = 0; idx < 7; idx++) { if (gUnknown_083D1358[idx].unk_083D1358_0 == tile_id) { MapGridSetMetatileIdAt(x, y, gUnknown_083D1358[idx].unk_083D1358_1 | 0xc00); CurrentMapDrawMetatileAt(x, y); return; } } for (idx = 0; idx < 7; idx++) { if (gUnknown_083D1358[idx].unk_083D1358_1 == tile_id) { MapGridSetMetatileIdAt(x, y, gUnknown_083D1358[idx].unk_083D1358_0 | 0xc00); CurrentMapDrawMetatileAt(x, y); return; } } } u8 sub_80BB8A8(u8 *arg1) { u8 idx; for (idx=0; idx<7; idx++) { if (arg1[idx] == EOS) return idx; } return 7; } void sub_80BB8CC(void) { u8 nameLength; u16 idx; gSaveBlock1.secretBases[0].secretBaseId = gCurrentSecretBaseId; for (idx=0; idx<4; idx++) gSaveBlock1.secretBases[0].trainerId[idx] = gSaveBlock2.playerTrainerId[idx]; VarSet(VAR_CURRENT_SECRET_BASE, 0); nameLength = sub_80BB8A8(gSaveBlock2.playerName); memset(gSaveBlock1.secretBases[0].playerName, 0xFF, OT_NAME_LENGTH); StringCopyN(gSaveBlock1.secretBases[0].playerName, gSaveBlock2.playerName, nameLength); gSaveBlock1.secretBases[0].gender = gSaveBlock2.playerGender; VarSet(VAR_SECRET_BASE_MAP, gMapHeader.regionMapSectionId); } void sub_80BB970(struct MapEvents *events) { u16 bgevidx, idx, jdx; s16 tile_id; for (bgevidx = 0; bgevidx < events->bgEventCount; bgevidx++) { if (events->bgEvents[bgevidx].kind == BG_EVENT_SECRET_BASE) { for (jdx = 0; jdx < MAX_SECRET_BASES; jdx++) { if (gSaveBlock1.secretBases[jdx].secretBaseId == events->bgEvents[bgevidx].bgUnion.secretBaseId) { tile_id = MapGridGetMetatileIdAt(events->bgEvents[bgevidx].x + 7, events->bgEvents[bgevidx].y + 7); for (idx = 0; idx < 7; idx++) { if (gUnknown_083D1358[idx].unk_083D1358_0 == tile_id) { MapGridSetMetatileIdAt(events->bgEvents[bgevidx].x + 7, events->bgEvents[bgevidx].y + 7, gUnknown_083D1358[idx].unk_083D1358_1 | 0xc00); break; } } break; } } } } } void sub_80BBA14(void) { s8 idx = 4 * (gCurrentSecretBaseId / 10); warp1_set_2(MAP_GROUP(SECRET_BASE_RED_CAVE1), gUnknown_083D1374[idx], gUnknown_083D1374[idx + 1]); } void sub_80BBA48(u8 taskid) { u16 curbaseid; switch (gTasks[taskid].data[0]) { case 0: gTasks[taskid].data[0] = 1; break; case 1: if (!gPaletteFade.active) gTasks[taskid].data[0] = 2; break; case 2: curbaseid = VarGet(VAR_CURRENT_SECRET_BASE); if (gSaveBlock1.secretBases[curbaseid].numTimesEntered < 0xff) gSaveBlock1.secretBases[curbaseid].numTimesEntered++; sub_80BBA14(); WarpIntoMap(); gFieldCallback = sub_8080990; SetMainCallback2(CB2_LoadMap); DestroyTask(taskid); break; } } void sub_80BBAF0(void) { CreateTask(sub_80BBA48, 0); FadeScreen(1, 0); saved_warp2_set(0, gSaveBlock1.location.mapGroup, gSaveBlock1.location.mapNum, -1); } bool8 sub_80BBB24(void) { if (gMapHeader.mapType == MAP_TYPE_SECRET_BASE && VarGet(VAR_INIT_SECRET_BASE) == 0) return FALSE; return TRUE; } void sub_80BBB50(u8 taskid) { ObjectEventTurn(&(gObjectEvents[gPlayerAvatar.objectEventId]), 2); if (IsWeatherNotFadingIn() == 1) { EnableBothScriptContexts(); DestroyTask(taskid); } } void sub_80BBB90(void) { s16 x, y; ScriptContext2_Enable(); HideMapNamePopup(); sub_80BB764(&x, &y, 0x220); MapGridSetMetatileIdAt(x + 7, y + 7, 0xe20); CurrentMapDrawMetatileAt(x + 7, y + 7); pal_fill_black(); CreateTask(sub_80BBB50, 0); } void sub_80BBBEC(u8 taskid) { s8 idx; if (!gPaletteFade.active) { idx = 4 * (gCurrentSecretBaseId / 10); Overworld_SetWarpDestination(gSaveBlock1.location.mapGroup, gSaveBlock1.location.mapNum, -1, gUnknown_083D1374[idx + 2], gUnknown_083D1374[idx + 3]); WarpIntoMap(); gFieldCallback = sub_80BBB90; SetMainCallback2(CB2_LoadMap); DestroyTask(taskid); } } void sub_80BBC78(void) { u8 taskid = CreateTask(sub_80BBBEC, 0); gTasks[taskid].data[0] = 0; FadeScreen(1, 0); } bool8 CurrentMapIsSecretBase(void) { if (gSaveBlock1.location.mapGroup == MAP_GROUP(SECRET_BASE_SHRUB4) && (u8)(gSaveBlock1.location.mapNum) <= MAP_NUM(SECRET_BASE_SHRUB4)) return TRUE; return FALSE; } void sub_80BBCCC(u8 flagIn) { u16 curBaseId; u16 x, y; if (CurrentMapIsSecretBase()) { curBaseId = VarGet(VAR_CURRENT_SECRET_BASE); for (x = 0; x < 16; x++) { if (gSaveBlock1.secretBases[curBaseId].decorations[x] > 0 && gSaveBlock1.secretBases[curBaseId].decorations[x] <= 0x78 && gDecorations[gSaveBlock1.secretBases[curBaseId].decorations[x]].permission != DECORPERM_SOLID_MAT) { sub_80FF394( (gSaveBlock1.secretBases[curBaseId].decorationPos[x] >> 4) + 7, (gSaveBlock1.secretBases[curBaseId].decorationPos[x] & 0xF) + 7, gSaveBlock1.secretBases[curBaseId].decorations[x]); } } if (curBaseId != 0) { sub_80BB764(&x, &y, 0x220); MapGridSetMetatileIdAt(x + 7, y + 7, 0xe21); } else if (flagIn == 1 && VarGet(VAR_SECRET_BASE_INITIALIZED) == 1) { sub_80BB764(&x, &y, 0x220); MapGridSetMetatileIdAt(x + 7, y + 7, 0xe0a); } } } void sub_80BBDD0(void) { u8 *roomdecor; u8 *roomdecorpos; u8 decidx; u8 objid = 0; u8 metatile; u8 permission; u8 ndecor; u16 curBase = VarGet(VAR_CURRENT_SECRET_BASE); if (!CurrentMapIsSecretBase()) { roomdecor = gSaveBlock1.playerRoomDecor; roomdecorpos = gSaveBlock1.playerRoomDecorPos; ndecor = 12; } else { roomdecor = gSaveBlock1.secretBases[curBase].decorations; roomdecorpos = gSaveBlock1.secretBases[curBase].decorationPos; ndecor = 16; } for (decidx = 0; decidx < ndecor; decidx++) { if (roomdecor[decidx] != DECOR_NONE) { permission = gDecorations[roomdecor[decidx]].permission; if (permission == DECORPERM_SOLID_MAT) { for (objid = 0; objid < gMapHeader.events->objectEventCount; objid++) { if (gMapHeader.events->objectEvents[objid].flagId == gSpecialVar_0x8004 + 0xAE) break; } if (objid != gMapHeader.events->objectEventCount) { gSpecialVar_0x8006 = roomdecorpos[decidx] >> 4; gSpecialVar_0x8007 = roomdecorpos[decidx] & 0xF; metatile = MapGridGetMetatileBehaviorAt(gSpecialVar_0x8006 + 7, gSpecialVar_0x8007 + 7); if (MetatileBehavior_IsSecretBaseLargeMatEdge(metatile) == TRUE || MetatileBehavior_IsLargeMatCenter(metatile) == TRUE) { gSpecialVar_Result = VAR_OBJ_GFX_ID_0 + (gMapHeader.events->objectEvents[objid].graphicsId - OBJ_EVENT_GFX_VAR_0); VarSet(gSpecialVar_Result, gDecorations[roomdecor[decidx]].tiles[0]); gSpecialVar_Result = gMapHeader.events->objectEvents[objid].localId; FlagClear(gSpecialVar_0x8004 + 0xAE); show_sprite(gSpecialVar_Result, gSaveBlock1.location.mapNum, gSaveBlock1.location.mapGroup); sub_805C0F8(gSpecialVar_Result, gSaveBlock1.location.mapNum, gSaveBlock1.location.mapGroup, gSpecialVar_0x8006, gSpecialVar_0x8007); TryOverrideTemplateCoordsForObjectEvent(gSpecialVar_Result, gSaveBlock1.location.mapNum, gSaveBlock1.location.mapGroup); gSpecialVar_0x8004 ++; } } } } } } void SetSecretBaseOwnerGfxId(void) { int curBase = VarGet(VAR_CURRENT_SECRET_BASE); VarSet(VAR_OBJ_GFX_ID_F, sSecretBaseOwnerGfxIds[GetSecretBaseOwnerType(curBase)]); } void SetCurrentSecretBaseFromPosition(struct MapPosition *position, struct MapEvents *events) { s16 i; for (i = 0; i < events->bgEventCount; i++) { if (events->bgEvents[i].kind == BG_EVENT_SECRET_BASE && position->x == events->bgEvents[i].x + 7 && position->y == events->bgEvents[i].y + 7) { gCurrentSecretBaseId = events->bgEvents[i].bgUnion.secretBaseId; break; } } } void sub_80BC038(struct MapPosition *position, struct MapEvents *events) { SetCurrentSecretBaseFromPosition(position, events); SetCurrentSecretBaseVar(); ScriptContext1_SetupScript(gUnknown_081A2E14); } bool8 sub_80BC050(void) { sub_80BB5D0(); SetCurrentSecretBaseVar(); if (gSpecialVar_Result == 1) return FALSE; return TRUE; } void sub_80BC074(u8 taskid) { switch (gTasks[taskid].data[0]) { case 0: ScriptContext2_Enable(); gTasks[taskid].data[0] = 1; break; case 1: if (!gPaletteFade.active) gTasks[taskid].data[0] = 2; break; case 2: copy_saved_warp2_bank_and_enter_x_to_warp1(0x7E); WarpIntoMap(); gFieldCallback = mapldr_default; SetMainCallback2(CB2_LoadMap); ScriptContext2_Disable(); DestroyTask(taskid); break; } } void sub_80BC0F8(void) { CreateTask(sub_80BC074, 0); FadeScreen(1, 0); } void sub_80BC114(void) { if (gSaveBlock1.secretBases[0].secretBaseId != gCurrentSecretBaseId) gSpecialVar_Result = 1; else gSpecialVar_Result = 0; } u8 sub_80BC14C(u8 sbid) { s16 idx; for (idx = 0; idx < MAX_SECRET_BASES; idx++) { if (gSaveBlock1.secretBases[idx].secretBaseId == sbid) return idx; } return 0; } u8 *sub_80BC190(u8 *dest, u8 arg1) { u8 local1; u8 *str; local1 = sub_80BB8A8(gSaveBlock1.secretBases[arg1].playerName); str = StringCopyN(dest, gSaveBlock1.secretBases[arg1].playerName, local1); str[0] = EOS; #if ENGLISH return StringAppend(dest, gOtherText_PlayersBase); #elif GERMAN return de_sub_8073174(dest, gOtherText_PlayersBase); #endif } u8 *GetSecretBaseMapName(u8 *dest) { gCurrentSecretBaseId = gSaveBlock1.secretBases[VarGet(VAR_CURRENT_SECRET_BASE)].secretBaseId; return sub_80BC190(dest, VarGet(VAR_CURRENT_SECRET_BASE)); } void BufferSecretBaseOwnerName(void) { u8 *var0 = gSaveBlock1.secretBases[(u8)VarGet(VAR_CURRENT_SECRET_BASE)].playerName; u8 *var1 = gStringVar1; u8 var2 = sub_80BB8A8(var0); u8 *var3 = StringCopyN(var1, var0, var2); *var3 = EOS; } bool8 sub_80BC268(u8 i) { if (gSaveBlock1.secretBases[i].registryStatus) return TRUE; else return FALSE; } static u8 CalculateMonAverageEVs(struct Pokemon *mon) { u16 evsum = GetMonData(mon, MON_DATA_HP_EV); evsum += GetMonData(mon, MON_DATA_ATK_EV); evsum += GetMonData(mon, MON_DATA_DEF_EV); evsum += GetMonData(mon, MON_DATA_SPEED_EV); evsum += GetMonData(mon, MON_DATA_SPATK_EV); evsum += GetMonData(mon, MON_DATA_SPDEF_EV); return (u8)(evsum / 6); } void SetPlayerSecretBaseRecordMixingParty(void) { u16 i; u16 secretBasePartyIndex = 0; struct SecretBaseRecord *record = &gSaveBlock1.secretBases[0]; for (i = 0; i < PARTY_SIZE; i++) { u16 j; for (j = 0; j < 4; j++) record->party.moves[i * 4 + j] = MOVE_NONE; record->party.species[i] = SPECIES_NONE; record->party.heldItems[i] = ITEM_NONE; record->party.levels[i] = 0; record->party.personality[i] = 0; record->party.EVs[i] = 0; if (GetMonData(&gPlayerParty[i], MON_DATA_SPECIES) != SPECIES_NONE && !GetMonData(&gPlayerParty[i], MON_DATA_IS_EGG)) { for (j = 0; j < 4; j++) record->party.moves[secretBasePartyIndex * 4 + j] = GetMonData(&gPlayerParty[i], MON_DATA_MOVE1 + j); record->party.species[secretBasePartyIndex] = GetMonData(&(gPlayerParty[i]), MON_DATA_SPECIES); record->party.heldItems[secretBasePartyIndex] = GetMonData(&gPlayerParty[i], MON_DATA_HELD_ITEM); record->party.levels[secretBasePartyIndex] = GetMonData(&gPlayerParty[i], MON_DATA_LEVEL); record->party.personality[secretBasePartyIndex] = GetMonData(&gPlayerParty[i], MON_DATA_PERSONALITY); record->party.EVs[secretBasePartyIndex] = CalculateMonAverageEVs(&gPlayerParty[i]); secretBasePartyIndex++; } } } void sub_80BC440(void) { u16 backupValue = gSaveBlock1.secretBases[0].numSecretBasesReceived; ResetSecretBase(0); gSaveBlock1.secretBases[0].numSecretBasesReceived = backupValue; sub_80BC0F8(); } void MoveOutOfSecretBase(void) { IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE); sub_80BC440(); } void sub_80BC474(void) { u16 eventId; struct MapEvents *mapEvents = gMapHeader.events; for (eventId = 0; eventId < mapEvents->bgEventCount; eventId++) { if (mapEvents->bgEvents[eventId].kind == BG_EVENT_SECRET_BASE && gSaveBlock1.secretBases[0].secretBaseId == mapEvents->bgEvents[eventId].bgUnion.secretBaseId) { u16 i; s16 tileId = MapGridGetMetatileIdAt(mapEvents->bgEvents[eventId].x + 7, mapEvents->bgEvents[eventId].y + 7); for (i = 0; i < 7; i++) { if (gUnknown_083D1358[i].unk_083D1358_1 == tileId) { MapGridSetMetatileIdAt( mapEvents->bgEvents[eventId].x + 7, mapEvents->bgEvents[eventId].y + 7, gUnknown_083D1358[i].unk_083D1358_0 | 0xc00); break; } } DrawWholeMapView(); break; } } } void MoveSecretBase(void) { u16 backupValue; sub_80BC474(); IncrementGameStat(GAME_STAT_MOVED_SECRET_BASE); backupValue = gSaveBlock1.secretBases[0].numSecretBasesReceived; ResetSecretBase(0); gSaveBlock1.secretBases[0].numSecretBasesReceived = backupValue; } u8 sub_80BC538(void) { s16 secretBaseIndex; u8 retVal = 0; for (secretBaseIndex = 1; secretBaseIndex < MAX_SECRET_BASES; secretBaseIndex++) { if (sub_80BC268(secretBaseIndex) == TRUE) retVal++; } return retVal; } void GetCurSecretBaseRegistrationValidity(void) { if (sub_80BC268(sub_80BC14C(gCurrentSecretBaseId)) == TRUE) gSpecialVar_Result = 1; else if (sub_80BC538() > 9) gSpecialVar_Result = 2; else gSpecialVar_Result = 0; } void ToggleCurSecretBaseRegistry(void) { gSaveBlock1.secretBases[sub_80BC14C(gCurrentSecretBaseId)].registryStatus ^= 1; FlagSet(FLAG_SECRET_BASE_REGISTRY_ENABLED); } void SecretBasePC_Decoration(void) { CreateTask(Task_SecretBasePC_Decoration, 0); } void SecretBasePC_Registry(void) { CreateTask(Task_SecretBasePC_Registry, 0); } void Task_SecretBasePC_Registry(u8 taskId) { s16 *taskData; ScriptContext2_Enable(); ClearVerticalScrollIndicatorPalettes(); LoadScrollIndicatorPalette(); taskData = gTasks[taskId].data; taskData[0] = sub_80BC538(); if (taskData[0] != 0) { if (taskData[0] > 7) taskData[3] = 7; else taskData[3] = taskData[0]; taskData[1] = 0; taskData[2] = 0; Menu_EraseWindowRect(0, 0, 29, 19); sub_80BC7D8(taskId); gTasks[taskId].func = sub_80BC824; } else { DisplayItemMessageOnField(taskId, gSecretBaseText_NoRegistry, sub_80BCC54, 0); } } void sub_80BC6B0(u8 taskId) { u8 i; s16 *taskData = gTasks[taskId].data; u8 m = 0; u8 n = 0; for (i = 1; i < MAX_SECRET_BASES; i++) { if (m == taskData[2]) { m = i; break; } if (sub_80BC268(i) == TRUE) m++; } for (i = m; i < MAX_SECRET_BASES; i++) { if (sub_80BC268(i) == TRUE) { sub_80BC190(gStringVar1, i); Menu_BlankWindowRect(18, 2 * n + 2, 28, 2 * n + 3); Menu_PrintText(gStringVar1, 18, 2 * n + 2); if (++n == 8) break; } } if (n < 8) { Menu_BlankWindowRect(18, 2 * n + 2, 28, 2 * n + 3); Menu_PrintText(gOtherText_Exit, 18, 2 * n + 2); DestroyVerticalScrollIndicator(BOTTOM_ARROW); if (n != 7) { n++; n--; Menu_BlankWindowRect(18, n * 2 + 4, 28, 18); } } else { CreateVerticalScrollIndicators(BOTTOM_ARROW, 0xbc, 0x98); } if (taskData[2] == 0) DestroyVerticalScrollIndicator(TOP_ARROW); else CreateVerticalScrollIndicators(TOP_ARROW, 0xbc, 0x08); } void sub_80BC7D8(u8 taskId) { u16 *taskData = gTasks[taskId].data; Menu_DrawStdWindowFrame(17, 0, 29, 19); InitMenu(0, 18, 2, taskData[3] + 1, taskData[1], 11); sub_80BC6B0(taskId); } void sub_80BC824(u8 taskId) { s16 *taskData = gTasks[taskId].data; if (gMain.newAndRepeatedKeys & DPAD_UP) { if (taskData[1]) { PlaySE(SE_SELECT); taskData[1] = Menu_MoveCursor(-1); } else if (taskData[2]) { PlaySE(SE_SELECT); taskData[2]--; sub_80BC6B0(taskId); } } else if (gMain.newAndRepeatedKeys & DPAD_DOWN) { if (taskData[1] == taskData[3]) { if (taskData[2] + taskData[1] != taskData[0]) { PlaySE(SE_SELECT); taskData[2]++; sub_80BC6B0(taskId); } } else { PlaySE(SE_SELECT); taskData[1] = Menu_MoveCursor(1); } } else if (gMain.newKeys & A_BUTTON) { PlaySE(SE_SELECT); if (taskData[1] + taskData[2] == taskData[0]) { Menu_DestroyCursor(); Menu_EraseWindowRect(0, 0, 29, 19); sub_80BCC54(taskId); } else { Menu_DestroyCursor(); taskData[4] = sub_80BC948(taskData[1] + taskData[2]); sub_80BC980(taskId); } } else if (gMain.newKeys & B_BUTTON) { PlaySE(SE_SELECT); Menu_DestroyCursor(); Menu_EraseWindowRect(0, 0, 29, 19); sub_80BCC54(taskId); } } u8 sub_80BC948(u8 a) { u8 secretBaseIndex; u8 count = 0; for (secretBaseIndex = 1; secretBaseIndex < MAX_SECRET_BASES; secretBaseIndex++) { if (sub_80BC268(secretBaseIndex) == TRUE) { if (a == count) { return secretBaseIndex; } count++; } } return 0; } void sub_80BC980(u8 taskId) { PauseVerticalScrollIndicator(TOP_ARROW); PauseVerticalScrollIndicator(BOTTOM_ARROW); Menu_DrawStdWindowFrame(1, 0, 12, 5); Menu_PrintItems(2, 1, 2, (const struct MenuAction *)gUnknown_083D13D4); InitMenu(0, 2, 1, 2, 0, 10); gTasks[taskId].func = sub_80BC9E4; } void sub_80BC9E4(u8 taskId) { if (gMain.newAndRepeatedKeys & DPAD_UP) { if (Menu_GetCursorPos()) { PlaySE(SE_SELECT); Menu_MoveCursor(-1); } } else if (gMain.newAndRepeatedKeys & DPAD_DOWN) { if (Menu_GetCursorPos() != 1) { PlaySE(SE_SELECT); Menu_MoveCursor(1); } } else if (gMain.newKeys & A_BUTTON) { PlaySE(SE_SELECT); gUnknown_083D13D4[Menu_GetCursorPos()].func(taskId); } else if (gMain.newKeys & B_BUTTON) { PlaySE(SE_SELECT); sub_80BCBF8(taskId); } } void sub_80BCA84(u8 taskId) { s16 *taskData = gTasks[taskId].data; DestroyVerticalScrollIndicator(TOP_ARROW); DestroyVerticalScrollIndicator(BOTTOM_ARROW); Menu_DestroyCursor(); Menu_EraseWindowRect(0, 0, 29, 19); sub_80BC190(gStringVar1, taskData[4]); StringExpandPlaceholders(gStringVar4, gOtherText_OkayToDeleteFromRegistry); DisplayItemMessageOnField(taskId, gStringVar4, sub_80BCAEC, 0); } void sub_80BCAEC(u8 taskId) { DisplayYesNoMenu(20, 8, 1); DoYesNoFuncWithChoice(taskId, &gUnknown_083D13E4); } void sub_80BCB10(u8 taskId) { s16 *taskData = gTasks[taskId].data; Menu_EraseWindowRect(0, 0, 29, 19); gSaveBlock1.secretBases[taskData[4]].registryStatus = 0; taskData[0]--; if (taskData[2] > 0) taskData[2]--; if (taskData[0] < 8) taskData[3]--; sub_80BC7D8(taskId); gTasks[taskId].func = sub_80BC824; } void sub_80BCB90(u8 taskId) { Menu_EraseWindowRect(20, 8, 26, 13); DisplayItemMessageOnField(taskId, gOtherText_RegisteredDataDeleted, sub_80BCB10, 0); } void sub_80BCBC0(u8 taskId) { Menu_EraseWindowRect(0, 0, 29, 19); sub_80BC7D8(taskId); gTasks[taskId].func = sub_80BC824; } void sub_80BCBF8(u8 taskId) { s16 *taskData = gTasks[taskId].data; InitMenu(0, 18, 2, taskData[3] + 1, taskData[1], 11); Menu_EraseWindowRect(1, 0, 12, 5); StartVerticalScrollIndicators(TOP_ARROW); StartVerticalScrollIndicators(BOTTOM_ARROW); gTasks[taskId].func = sub_80BC824; } void sub_80BCC54(u8 taskId) { u16 curBaseIndex = VarGet(VAR_CURRENT_SECRET_BASE); BuyMenuFreeMemory(); DestroyVerticalScrollIndicator(TOP_ARROW); DestroyVerticalScrollIndicator(BOTTOM_ARROW); if (curBaseIndex == 0) ScriptContext1_SetupScript(SecretBase_EventScript_PCCancel); else ScriptContext1_SetupScript(SecretBase_EventScript_ShowRegisterMenu); DestroyTask(taskId); } static u8 GetSecretBaseOwnerType(u8 secretBaseIndex) { return (gSaveBlock1.secretBases[secretBaseIndex].playerName[OT_NAME_LENGTH] % 5) + gSaveBlock1.secretBases[secretBaseIndex].gender * 5; } const u8 *GetSecretBaseTrainerLoseText(void) { u8 param = GetSecretBaseOwnerType(VarGet(VAR_CURRENT_SECRET_BASE)); if (param == 0) return UnknownString_81A1BB2; if (param == 1) return UnknownString_81A1F67; if (param == 2) return UnknownString_81A2254; if (param == 3) return UnknownString_81A25C3; if (param == 4) return UnknownString_81A2925; if (param == 5) return UnknownString_81A1D74; if (param == 6) return UnknownString_81A20C9; if (param == 7) return UnknownString_81A2439; if (param == 8) return UnknownString_81A2754; return UnknownString_81A2B2A; } // Debugging function to test secret base battles. void unref_sub_80BCD7C(u8 secretBaseIndex) { u16 i; for (i = 0; i < 1; i++) { gSaveBlock1.secretBases[secretBaseIndex].party.personality[i] = i + 1; gSaveBlock1.secretBases[secretBaseIndex].party.moves[i * 4] = i + 1; gSaveBlock1.secretBases[secretBaseIndex].party.species[i] = SPECIES_TREECKO; gSaveBlock1.secretBases[secretBaseIndex].party.heldItems[i] = i + 1; gSaveBlock1.secretBases[secretBaseIndex].party.levels[i] = i + 5; gSaveBlock1.secretBases[secretBaseIndex].party.EVs[i] = i * 5; } } void sub_80BCE1C(void) { u16 curBaseIndex = VarGet(VAR_CURRENT_SECRET_BASE); sub_810FB10(1); CreateSecretBaseEnemyParty(&gSaveBlock1.secretBases[curBaseIndex]); } void sub_80BCE4C() { gSaveBlock1.secretBases[VarGet(VAR_CURRENT_SECRET_BASE)].battledOwnerToday = gSpecialVar_Result; } void sub_80BCE90() { u16 curBaseIndex = VarGet(VAR_CURRENT_SECRET_BASE); if (!FlagGet(FLAG_DAILY_UNKNOWN_8C2)) { u8 i; for (i = 0; i < MAX_SECRET_BASES; i++) gSaveBlock1.secretBases[i].battledOwnerToday = 0; FlagSet(FLAG_DAILY_UNKNOWN_8C2); } gSpecialVar_0x8004 = GetSecretBaseOwnerType(curBaseIndex); gSpecialVar_Result = gSaveBlock1.secretBases[curBaseIndex].battledOwnerToday; } void sub_80BCF1C(u8 taskId) { s16 x, y; u32 metatileBehavior; s16 *taskData = gTasks[taskId].data; switch (taskData[1]) { case 0: PlayerGetDestCoords(&taskData[2], &taskData[3]); taskData[1] = 1; break; case 1: PlayerGetDestCoords(&x, &y); if (x != taskData[2] || y != taskData[3]) { taskData[2] = x; taskData[3] = y; metatileBehavior = MapGridGetMetatileBehaviorAt(x, y); if (MetatileBehavior_IsSecretBaseGlitterMat(metatileBehavior) == TRUE) DoSecretBaseGlitterMatSparkle(); else if (MetatileBehavior_IsSecretBaseBalloon(metatileBehavior) == TRUE) PopSecretBaseBalloon(MapGridGetMetatileIdAt(x, y), x, y); else if (MetatileBehavior_IsSecretBaseBreakableDoor(metatileBehavior) == TRUE) ShatterSecretBaseBreakableDoor(x, y); else if (MetatileBehavior_IsSecretBaseMusicNoteMat(metatileBehavior) == TRUE) PlaySecretBaseMusicNoteMatSound(MapGridGetMetatileIdAt(x, y)); } break; case 2: if (!FieldEffectActiveListContains(taskData[4])) taskData[1] = 1; break; } } void sub_80BD034(u8 i, struct SecretBaseRecord *secretBase) { gSaveBlock1.secretBases[i] = *secretBase; gSaveBlock1.secretBases[i].registryStatus = 2; } bool8 sub_80BD070(struct SecretBaseRecord *baseA, struct SecretBaseRecord *baseB) { u8 i; for (i = 0; i < 4; i++) { if (baseA->trainerId[i] != baseB->trainerId[i]) return FALSE; } return TRUE; } bool8 sub_80BD0A0(struct SecretBaseRecord *baseA, struct SecretBaseRecord *baseB) { u8 i; for (i = 0; i < OT_NAME_LENGTH && (baseA->playerName[i] != 0xFF || baseB->playerName[i] != 0xFF); i++) { if (baseA->playerName[i] != baseB->playerName[i]) return FALSE; } return TRUE; } bool8 sub_80BD0EC(struct SecretBaseRecord *baseA, struct SecretBaseRecord *baseB) { if (baseA->gender == baseB->gender && sub_80BD070(baseA, baseB) && sub_80BD0A0(baseA, baseB)) return TRUE; else return FALSE; } s16 sub_80BD12C(u8 secretBaseId) { s16 i; for (i = 0; i < MAX_SECRET_BASES; i++) { if (gSaveBlock1.secretBases[i].secretBaseId == secretBaseId) return i; } return -1; } u8 sub_80BD170(void) { s16 i; for (i = 1; i < MAX_SECRET_BASES; i++) { if (gSaveBlock1.secretBases[i].secretBaseId == 0) return i; } return 0; } u8 sub_80BD1B0(void) { s16 i; for (i = 1; i < MAX_SECRET_BASES; i++) { if (gSaveBlock1.secretBases[i].registryStatus == 0 && gSaveBlock1.secretBases[i].toRegister == 0) return i; } return 0; } u8 sub_80BD1FC(struct SecretBaseRecord *secretBase) { s16 secretBaseIndex; if (secretBase->secretBaseId == 0) return 0; secretBaseIndex = sub_80BD12C(secretBase->secretBaseId); if (secretBaseIndex != 0) { if (secretBaseIndex != -1) { if (gSaveBlock1.secretBases[secretBaseIndex].toRegister == 1) return 0; if (gSaveBlock1.secretBases[secretBaseIndex].registryStatus != 2 || secretBase->toRegister == 1) { sub_80BD034(secretBaseIndex, secretBase); return secretBaseIndex; } } else { secretBaseIndex = sub_80BD170(); if (secretBaseIndex != 0) { sub_80BD034(secretBaseIndex, secretBase); return secretBaseIndex; } secretBaseIndex = sub_80BD1B0(); if (secretBaseIndex) { sub_80BD034(secretBaseIndex, secretBase); return secretBaseIndex; } } } return 0; } void sub_80BD280(void) { u8 i; u8 j; struct SecretBaseRecord temp; struct SecretBaseRecord *secretBases = gSaveBlock1.secretBases; for (i = 1; i < MAX_SECRET_BASES - 1; i++) { for (j = i + 1; j < MAX_SECRET_BASES; j++) { if ((!secretBases[i].registryStatus && secretBases[j].registryStatus == 1) || (secretBases[i].registryStatus == 2 && secretBases[j].registryStatus != 2)) { temp = secretBases[i]; secretBases[i] = secretBases[j]; secretBases[j] = temp; } } } } void sub_80BD328(struct SecretBaseRecord *secretBases, u8 b) { u16 i; for (i = 1; i < MAX_SECRET_BASES; i++) { if (secretBases[i].registryStatus == b) sub_80BD1FC(&secretBases[i]); } } bool8 sub_80BD358(struct SecretBaseRecord *secretBase) { u8 i; if (!secretBase->secretBaseId) return FALSE; if (secretBase->secretBaseId && secretBase->gender != gSaveBlock2.playerGender) return FALSE; // Check if the player's trainer Id matches the secret base's id. for (i = 0; i < 4; i++) { if (secretBase->trainerId[i] != gSaveBlock2.playerTrainerId[i]) return FALSE; } for (i = 0; i < OT_NAME_LENGTH && (secretBase->playerName[i] != 0xFF || gSaveBlock2.playerName[i] != 0xFF); i++) { if (secretBase->playerName[i] != gSaveBlock2.playerName[i]) return FALSE; } return TRUE; } void sub_80BD3DC(struct SecretBaseRecord *basesA, struct SecretBaseRecord *basesB, struct SecretBaseRecord *basesC) { u8 i; u8 var1 = 0; for (i = 0; i < MAX_SECRET_BASES; i++) { if ((var1 & 1) == 0) { if (sub_80BD358(&basesA[i]) == TRUE) { ClearSecretBase(&basesA[i]); var1 |= 1; } } if ((var1 & 2) == 0) { if (sub_80BD358(&basesB[i]) == TRUE) { ClearSecretBase(&basesB[i]); var1 |= 2; } } if ((var1 & 4) == 0) { if (sub_80BD358(&basesC[i]) == TRUE) { ClearSecretBase(&basesC[i]); var1 |= 4; } } if (var1 == 7) break; } } bool8 sub_80BD494(struct SecretBaseRecord *base, struct SecretBaseRecord *secretBases, u8 c) { u8 i; for (i = 0; i < MAX_SECRET_BASES; i++) { if (secretBases[i].secretBaseId) { if (sub_80BD0EC(base, &secretBases[i]) == TRUE) { if (c == 0) { ClearSecretBase(&secretBases[i]); return FALSE; } if (base->numSecretBasesReceived > secretBases[i].numSecretBasesReceived) { ClearSecretBase(&secretBases[i]); return FALSE; } secretBases[i].toRegister = base->toRegister; ClearSecretBase(base); return TRUE; } } } return FALSE; } void sub_80BD514(struct SecretBaseRecord *basesA, struct SecretBaseRecord *basesB, struct SecretBaseRecord *basesC, struct SecretBaseRecord *basesD) { u8 i; for (i = 1; i < MAX_SECRET_BASES; i++) { if (basesA[i].secretBaseId) { if (basesA[i].registryStatus == 1) basesA[i].toRegister = 1; if (!sub_80BD494(&basesA[i], basesB, i)) { if (!sub_80BD494(&basesA[i], basesC, i)) sub_80BD494(&basesA[i], basesD, i); } } } for (i = 0; i < MAX_SECRET_BASES; i++) { if (basesB[i].secretBaseId) { basesB[i].battledOwnerToday = 0; if (!sub_80BD494(&basesB[i], basesC, i)) sub_80BD494(&basesB[i], basesD, i); } } for (i = 0; i < MAX_SECRET_BASES; i++) { if (basesC[i].secretBaseId) { basesC[i].battledOwnerToday = 0; sub_80BD494(&basesC[i], basesD, i); } if (basesD[i].secretBaseId) basesD[i].battledOwnerToday = 0; } } void sub_80BD610(struct SecretBaseRecord *basesA, struct SecretBaseRecord *basesB, struct SecretBaseRecord *basesC) { sub_80BD3DC(basesA, basesB, basesC); sub_80BD514(gSaveBlock1.secretBases, basesA, basesB, basesC); sub_80BD1FC(basesA); sub_80BD1FC(basesB); sub_80BD1FC(basesC); sub_80BD328(basesA, 1); sub_80BD328(basesB, 1); sub_80BD328(basesC, 1); sub_80BD328(basesA, 0); sub_80BD328(basesB, 0); sub_80BD328(basesC, 0); } void ReceiveSecretBasesData(void *playerRecords, u32 size, u8 c) { if ( #if DEBUG gUnknown_020297ED != 0 || #endif FlagGet(FLAG_RECEIVED_SECRET_POWER)) { u16 i; u8 numLinkedPlayers = GetLinkPlayerCount(); switch (numLinkedPlayers) { case 2: memset(playerRecords + size * 2, 0, size); memset(playerRecords + size * 3, 0, size); break; case 3: memset(playerRecords + size * 3, 0, size); break; } switch (c) { case 0: sub_80BD610(playerRecords + size, playerRecords + size * 2, playerRecords + size * 3); break; case 1: sub_80BD610(playerRecords + size * 2, playerRecords + size * 3, playerRecords); break; case 2: sub_80BD610(playerRecords + size * 3, playerRecords, playerRecords + size); break; case 3: sub_80BD610(playerRecords, playerRecords + size, playerRecords + size * 2); break; } for (i = 1; i < MAX_SECRET_BASES; i++) { if (gSaveBlock1.secretBases[i].toRegister == 1) { gSaveBlock1.secretBases[i].registryStatus = 1; gSaveBlock1.secretBases[i].toRegister = 0; } } sub_80BD280(); for (i = 1; i < MAX_SECRET_BASES; i++) { if (gSaveBlock1.secretBases[i].registryStatus == 2) gSaveBlock1.secretBases[i].registryStatus = 0; } if (gSaveBlock1.secretBases[0].numSecretBasesReceived != 0xFFFF) gSaveBlock1.secretBases[0].numSecretBasesReceived++; } }