#include "area.h" #include "asm.h" #include "common.h" #include "flags.h" #include "global.h" #include "item.h" #include "kinstone.h" #include "manager.h" #include "message.h" #include "player.h" #include "room.h" #include "subtask.h" extern const struct_gUnk_080B3D20 gUnk_080B3D20[]; extern EntityData gUnk_080FEC28[]; extern EntityData gUnk_080FEBE8[]; extern EntityData gUnk_080FECC8[]; extern EntityData gUnk_080FEE78[]; extern EntityData gUnk_080FED58[]; extern const EntityData gUnk_080FED18[]; extern const EntityData gUnk_080FEE38[]; extern const EntityData gUnk_080FEE18[]; extern const EntityData gUnk_080FEE48[]; extern const EntityData gUnk_080FEE58[]; extern const void* gUnk_080FED98[]; void sub_08018AB4(int); void sub_08018BB4(u32 worldEventId); void sub_08018A58(u32 worldEventId); void sub_08018B50(u32 worldEventId); void sub_080189EC(u32 worldEventId); void sub_0801876C(u32 worldEventId, bool32 isKinstoneFused); void sub_08018738(u32 kinstoneId, u32 worldEventId); void ShuffleEzloHints(int count, u16* basePtr); void sub_08018500(); bool32 sub_080185B4(const struct_gUnk_080B3D20* param_1); const u16 gEzloHintTextBase[] = { TEXT_INDEX(TEXT_EZLO2, 0x0), TEXT_INDEX(TEXT_EZLO2, 0x12), TEXT_INDEX(TEXT_EZLO2, 0x2d), TEXT_INDEX(TEXT_EZLO2, 0x48), TEXT_INDEX(TEXT_EZLO2, 0x57), TEXT_INDEX(TEXT_EZLO2, 0x6f) }; void sub_08018500(void) { s32 sVar1; u32 i; u16* puVar3; u16* puVar4; struct_area_28* ptr = &gArea.unk28; puVar3 = ptr->ezloHintTexts; sVar1 = gEzloHintTextBase[ptr->textBaseIndex] + ptr->textIndexOffset * 3; for (i = 0; i < 3; i++) { *puVar3 = sVar1; sVar1++; puVar3++; } sVar1 = ptr->textBaseIndex * 5 + 0xc81; for (i = 0, puVar4 = &ptr->ezloHintTexts[3]; i < 5; i++) { *puVar3 = sVar1; sVar1++; puVar3++; } ShuffleEzloHints(5, puVar4); ptr->currentHint = 0; } /* Some sort of ezlo hint? Seem to be the ezlo hints depending on the current progress. */ #define CHECK_ITEM 0xfe #define CHECK_KINSTONE 0xfd const struct_gUnk_080B3D20 gUnk_080B3D20[] = { { LOCAL_BANK_0, EZERO_1ST, 0, 0 }, { LOCAL_BANK_0, ENTRANCE_0, 0, 1 }, { LOCAL_BANK_2, KOBITO_MORI_1ST, 0, 2 }, { LOCAL_BANK_2, M_PRIEST_TALK, 0, 3 }, { CHECK_ITEM, ITEM_JABBERNUT, 0, 4 }, { LOCAL_BANK_2, M_ELDER_TALK1ST, 0, 5 }, { LOCAL_BANK_0, LV1_CLEAR, 1, 0 }, { LOCAL_BANK_2, M_ELDER_TALK2ND, 1, 1 }, { CHECK_ITEM, ITEM_KINSTONE_BAG, 1, 2 }, { CHECK_ITEM, ITEM_SKILL_SPIN_ATTACK, 1, 3 }, { LOCAL_BANK_1, YAMA_00_01, 1, 4 }, { LOCAL_BANK_0, WATERBEAN_PUT, 1, 5 }, { LOCAL_BANK_1, YAMA_00_00, 1, 6 }, { LOCAL_BANK_2, KOBITO_YAMA_ENTER, 1, 7 }, { LOCAL_BANK_2, OYAKATA_DEMO, 1, 8 }, { LOCAL_BANK_0, LV2_CLEAR, 2, 0 }, { CHECK_ITEM, ITEM_GREEN_SWORD, 2, 1 }, { LOCAL_BANK_3, SEIIKI_ENTER, 2, 2 }, { LOCAL_BANK_3, SEIIKI_BUNSHIN, 2, 3 }, { LOCAL_BANK_0, DASHBOOTS, 2, 4 }, { LOCAL_BANK_2, KHOUSE52_KINOKO, 2, 5 }, { CHECK_ITEM, ITEM_QST_MUSHROOM, 2, 6 }, { CHECK_ITEM, ITEM_PEGASUS_BOOTS, 2, 7 }, { LOCAL_BANK_1, LOST_00_ENTER, 2, 8 }, { CHECK_ITEM, ITEM_OCARINA, 3, 0 }, { LOCAL_BANK_0, MIZUKAKI_START, 3, 1 }, { LOCAL_BANK_0, MIZUKAKI_NECHAN, 3, 2 }, { LOCAL_BANK_2, MIZUKAKI_BOOK_ALLBACK, 3, 3 }, { CHECK_ITEM, ITEM_FLIPPERS, 3, 4 }, { LOCAL_BANK_1, LV4_CLEAR_MES, 4, 0 }, { CHECK_ITEM, ITEM_BLUE_SWORD, 4, 1 }, { LOCAL_BANK_3, LV4_HAKA_08_CAP_0, 4, 2 }, { LOCAL_BANK_3, OUBO_KAKERA, 4, 3 }, { CHECK_KINSTONE, KINSTONE_SOURCE_FLOW, 4, 4 }, { LOCAL_BANK_0, TATSUMAKI, 4, 5 }, { LOCAL_BANK_2, SORA_YAKATA_ENTER, 4, 6 }, { LOCAL_BANK_2, SORA_CHIEF_TALK, 4, 7 }, { LOCAL_BANK_0, LV5_CLEAR, 5, 0 }, { CHECK_ITEM, ITEM_FOURSWORD, 5, 1 }, { LOCAL_BANK_10, LV6_1d_KEYGET, 5, 2 }, { LOCAL_BANK_10, LV6_KANE_START, 5, 3 }, { LOCAL_BANK_10, LV6_GUFUU2_DEAD, 5, 4 }, { LOCAL_BANK_10, LV6_ZELDA_DISCURSE, 5, 5 }, { 0xff, 0xff, 0xff, 0xff }, }; void sub_0801855C(void) { u32 bVar3; struct_area_28* ptr; // TODO: Figure out what is up with the pointer assignment const struct_gUnk_080B3D20* pcVar2 = (const struct_gUnk_080B3D20*)&gArea.unk28; MemClear((void*)pcVar2, sizeof(struct_area_28)); ptr = (struct_area_28*)pcVar2; // Find the latest hint that is true. for (pcVar2 = gUnk_080B3D20, bVar3 = 0; pcVar2->unk0 != 0xff; pcVar2++) { if (sub_080185B4(pcVar2)) { bVar3 = ptr->unk2b; } ptr->unk2b++; } ptr->unk2b = bVar3; pcVar2 = &gUnk_080B3D20[ptr->unk2b]; ptr->textBaseIndex = pcVar2->unk2; ptr->textIndexOffset = pcVar2->unk3; ptr->unk2b = bVar3 + 1; sub_08018500(); } bool32 sub_080185B4(const struct_gUnk_080B3D20* param_1) { if (param_1->unk0 == 0xff) return FALSE; if (param_1->unk0 == CHECK_ITEM) { return GetInventoryValue(param_1->unk1) != 0; } if (param_1->unk0 == CHECK_KINSTONE) { return CheckKinstoneFused(param_1->unk1); } return CheckLocalFlagByBank(gLocalFlagBanks[param_1->unk0], param_1->unk1); } void sub_080185F8(void) { struct_area_28* ptr2 = &gArea.unk28; const struct_gUnk_080B3D20* ptr = &gUnk_080B3D20[ptr2->unk2b]; if (sub_080185B4(ptr)) { ptr2->textBaseIndex = ptr->unk2; ptr2->textIndexOffset = ptr->unk3; ptr2->unk2b++; sub_08018500(); } } void GenerateAreaHint(void) { u16 tmp; struct_area_28* ptr; gPlayerState.queued_action = PLAYER_TALKEZLO; #if defined(EU) || defined(JP) // TODO what fields of the room transition are switched in these variants? gRoomTransition.field_0x2c[7] = 0; #else gRoomTransition.hint_height = 0; #endif ptr = &gArea.unk28; if (ptr->textBaseIndex == 0xff) { gRoomTransition.hint_idx = ptr->ezloHintTexts[0]; } else { gRoomTransition.hint_idx = ptr->ezloHintTexts[ptr->currentHint]; ptr->currentHint++; if (ptr->currentHint > 7) { ptr->currentHint = 0; ShuffleEzloHints(8, ptr->ezloHintTexts); if (ptr->ezloHintTexts[0] == gRoomTransition.hint_idx) { tmp = ptr->ezloHintTexts[0]; ptr->ezloHintTexts[0] = ptr->ezloHintTexts[7]; ptr->ezloHintTexts[7] = tmp; } } } } void ShuffleEzloHints(int count, u16* basePtr) { u32 uVar1; s32 uVar4; s32 uVar2; s32 iVar3; u16* puVar4; u16* puVar5; uVar4 = count - 1; if (uVar4 != 0) { puVar5 = (u16*)(uVar4 * 2 + (int)basePtr); do { uVar2 = Random(); iVar3 = uVar2 % (uVar4 + 1); uVar1 = *puVar5; puVar4 = (u16*)(iVar3 * 2 + (int)basePtr); *puVar5 = *puVar4; *puVar4 = uVar1; puVar5--; uVar4--; } while (uVar4 != 0); } } void SetNextAreaHint(u32 textId) { gArea.unk28.textBaseIndex = 0xff; gArea.unk28.ezloHintTexts[0] = textId; } void sub_080186D4(void) { if (gArea.unk28.textBaseIndex == 0xff) { sub_0801855C(); } } void sub_080186EC(u32 param_1) { const KinstoneWorldEvent* psVar1; u32 i; for (i = 0, psVar1 = gKinstoneWorldEvents; i <= 100; psVar1++, i++) { if (psVar1->subtask == SUBTASK_WORLDEVENT) { sub_08018738(i, psVar1->worldEventId); } } } void sub_08018710(u32 previousworldEventId) { const KinstoneWorldEvent* psVar1; u32 i; for (i = 0, psVar1 = gKinstoneWorldEvents; i <= 100; psVar1++, i++) { if (psVar1->subtask == SUBTASK_WORLDEVENT && previousworldEventId != psVar1->worldEventId) { sub_08018738(i, psVar1->worldEventId); } } } void sub_08018738(u32 kinstoneId, u32 worldEventId) { const WorldEvent* ptr = &gWorldEvents[worldEventId]; if (ptr->area == gRoomControls.area && ptr->room == gRoomControls.room) { sub_0801876C(worldEventId, CheckKinstoneFused(kinstoneId)); } } void sub_0801876C(u32 worldEventId, bool32 isKinstoneFused) { Entity* roomEnt; Entity* ent; u32 uVar3; u32 tmp; u8* puVar4; u32 uVar5; const WorldEvent* ptr; ptr = &gWorldEvents[worldEventId]; switch (ptr->type) { case WORLD_EVENT_TYPE_6: if (isKinstoneFused == 0) { sub_08018AB4((ptr->x >> 4 & 0x3f) | (ptr->y >> 4 & 0x3f) << 6); } break; case WORLD_EVENT_TYPE_0: break; case WORLD_EVENT_TYPE_2: if (isKinstoneFused != 0) { sub_08018BB4(worldEventId); } break; case WORLD_EVENT_TYPE_1: if (isKinstoneFused == 0) { return; } if (CheckGlobalFlag(ptr->flag)) { return; } LoadRoomEntity(gUnk_080FEC28 + ptr->entity_idx); break; case WORLD_EVENT_TYPE_3: if (isKinstoneFused == 0) { return; } if (GetInventoryValue(ptr->flag)) { return; } LoadRoomEntity(gUnk_080FEBE8 + ptr->entity_idx); break; case WORLD_EVENT_TYPE_4: if (isKinstoneFused == 0) { sub_08018A58(worldEventId); } break; case WORLD_EVENT_TYPE_5: if (isKinstoneFused != 0) { sub_08018B50(worldEventId); } break; case WORLD_EVENT_TYPE_7: if (isKinstoneFused != 0) { return; } if (ptr->entity_idx != 0x80) { LoadRoomEntity(gUnk_080FECC8 + ptr->entity_idx); } else { sub_080189EC(worldEventId); } break; case WORLD_EVENT_TYPE_25: roomEnt = LoadRoomEntity(&gUnk_080FED18[ptr->entity_idx]); if (roomEnt != 0) { roomEnt->type = isKinstoneFused ? 2 : 0; } break; case WORLD_EVENT_TYPE_8: if (isKinstoneFused == 0) { return; } SetTileType(0x168, (ptr->x >> 4 & 0x3f) | (ptr->y >> 4 & 0x3f) << 6, 1); break; case WORLD_EVENT_TYPE_11: if (isKinstoneFused != 0) { LoadRoomEntity(&gUnk_080FED58[ptr->entity_idx]); gRoomVars.field_0x8c[ptr->entity_idx] = (void*)gUnk_080FED98[ptr->entity_idx]; } break; case WORLD_EVENT_TYPE_9: if (isKinstoneFused == 0) { return; } ent = LoadRoomEntity(&gUnk_080FEE78[ptr->entity_idx]); if (ent != 0) { *(u16*)&ent->collisionLayer = ptr->x + gRoomControls.origin_x; *(u16*)&ent->gustJarState = ptr->y + gRoomControls.origin_y; } if (ptr->entity_idx == 0) { SetTileType(0x8d, (ptr->x >> 4 & 0x3f) | (ptr->y >> 4 & 0x3f) << 6, 1); } else { uVar5 = (ptr->x >> 4 & 0x3f) | (ptr->y >> 4 & 0x3f) << 6; SetTileType(0x8c, uVar5 - 1, 1); uVar3 = 0x8e; SetTileType(uVar3, uVar5, 1); } break; case WORLD_EVENT_TYPE_24: if (isKinstoneFused != 0) { LoadRoomEntityList(gUnk_080FEE18); } break; case WORLD_EVENT_TYPE_15: if (isKinstoneFused != 0) { LoadRoomEntity(gUnk_080FEE58); } else { LoadRoomEntity(gUnk_080FEE48); } break; case WORLD_EVENT_TYPE_17: if (isKinstoneFused != 0) { SetLocalFlagByBank(FLAG_BANK_1, SOUGEN_05_BOMB_00); LoadRoomEntityList(gUnk_080FEE38); } break; case WORLD_EVENT_TYPE_26: case WORLD_EVENT_TYPE_27: case WORLD_EVENT_TYPE_28: break; } } void sub_080189EC(u32 worldEventId) { u32 i; int iVar1; int tilePosition; const WorldEvent* ptr; ptr = &gWorldEvents[worldEventId]; tilePosition = (ptr->x >> 4) & 0x3f; tilePosition |= ((ptr->y >> 4) & 0x3f) << 6; tilePosition -= 0x42; for (i = 0; i < 4; i++) { SetTileType(i + 0x1df, tilePosition + i, 2); } tilePosition += 0x40; for (i = 0; i < 4; i++) { SetTileType(i + 0x1e3, tilePosition + i, 2); SetTileType(i + 0x1db, tilePosition + i, 1); } } void sub_08018A58(u32 worldEventId) { u32 i; int iVar2; u32 j; int tilePosition; const WorldEvent* ptr; ptr = &gWorldEvents[worldEventId]; tilePosition = (ptr->x >> 4) & 0x3f; tilePosition |= ((ptr->y >> 4) & 0x3f) << 6; tilePosition -= 0x43; iVar2 = 0x232; for (i = 0; i < 4; tilePosition += 0x40, i++) { for (j = 0; j < 7; j++) { SetTileType(iVar2++, tilePosition + j, 1); } } } void sub_08018AB4(int param_1) { u32 i; int iVar2; u32 j; int iVar6; iVar2 = 0x1e8; iVar6 = 500; for (i = 0; i < 3; i++) { j = 0; for (; j < 4; j++) { SetTileType(iVar2++, param_1 + j, 1); SetTileType(iVar6++, param_1 - 0x40 + j, 2); } param_1 += 0x40; } } void sub_08018B10(int param_1) { int iVar1; u32 index; int iVar3; int iVar4; iVar4 = 0x1f0; iVar3 = 0x1fc; index = 0; iVar1 = param_1 - 0x40; for (; index < 4; iVar1++, index++) { SetTileType(iVar4++, param_1 + index, 1); SetTileType(iVar3++, iVar1, 2); } } void sub_08018B50(u32 worldEventId) { u32 i; int iVar2; u32 j; int tilePosition; const WorldEvent* ptr; ptr = &gWorldEvents[worldEventId]; if ((ptr->entity_idx & 0x80) == 0) { iVar2 = 0x200; } else { iVar2 = 0x219; } tilePosition = (ptr->x >> 4) & 0x3f; tilePosition |= ((ptr->y >> 4) & 0x3f) << 6; tilePosition -= 0x82; for (i = 0; i < 5; tilePosition += 0x40, i++) { for (j = 0; j < 5; j++) { SetTileType(iVar2++, tilePosition + j, 1); } } } // TODO world event that loads tile entity void sub_08018BB4(u32 worldEventId) { u32 layer; TileEntity tile; const WorldEvent* ptr; u32 position; MemCopy(gUnk_080FEAC8 + worldEventId, &tile, sizeof(TileEntity)); ptr = &gWorldEvents[worldEventId]; tile.tilePos = (ptr->x >> 4 & 0x3f) | (((ptr->y) >> 4 & 0x3f) << 6); sub_0804B3C4(&tile); if (CheckLocalFlag(tile.localFlag) == 0) { position = tile.tilePos; if ((tile._6 & 1) == 0) { layer = 1; } else { layer = 2; } SetTileType(0x73, position, layer); } } void CreateMinishEntrance(u32 tilePos) { u32 x, y; u32 tileID = 0x185; for (y = 0; y <= 3; y++) { for (x = 0; x <= 4; x++) { SetTileType(tileID++, tilePos + x, 1); } tilePos += 0x40; } } void sub_08018C58(u32 tilePos) { u32 i; for (i = 0; i < 6; i += 2, tilePos += 0x40) { SetTileType(0x260 + i, tilePos, 1); SetTileType(0x261 + i, tilePos + 1, 1); } }