From 2c63ae38153dd9939394cc6869c70542ffdacaba Mon Sep 17 00:00:00 2001 From: rozlette Date: Wed, 4 Dec 2024 23:53:07 -0600 Subject: [PATCH] SceneDB --- soh/include/z64.h | 3 +- soh/include/z64save.h | 6 +- soh/soh/ActorDB.cpp | 2 +- .../Enhancements/randomizer/hook_handlers.cpp | 5 +- soh/soh/Enhancements/randomizer/logic.cpp | 17 +- .../randomizer/randomizer_entrance.c | 61 +- .../Enhancements/timesaver_hook_handlers.cpp | 3 +- soh/soh/Enhancements/tts/tts.cpp | 5 +- soh/soh/OTRGlobals.cpp | 3 + soh/soh/SaveManager.cpp | 297 ++- soh/soh/SaveManager.h | 3 + soh/soh/SceneDB.cpp | 1173 ++++++++++ soh/soh/SceneDB.h | 367 ++++ soh/soh/SceneDB_Table.cpp | 1912 +++++++++++++++++ soh/soh/SohMenuBar.cpp | 4 +- soh/soh/z_play_otr.cpp | 17 +- soh/src/code/z_actor.c | 1 + soh/src/code/z_demo.c | 6 +- soh/src/code/z_horse.c | 24 +- soh/src/code/z_kaleido_scope_call.c | 2 +- soh/src/code/z_kaleido_setup.c | 6 + soh/src/code/z_map_data.c | 4 +- soh/src/code/z_map_exp.c | 763 +++---- soh/src/code/z_map_mark.c | 173 +- soh/src/code/z_message_PAL.c | 2 +- soh/src/code/z_parameter.c | 400 +++- soh/src/code/z_play.c | 21 +- soh/src/code/z_room.c | 3 +- soh/src/code/z_scene_table.c | 13 +- soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c | 6 +- .../overlays/actors/ovl_En_Horse/z_en_horse.c | 59 +- .../actors/ovl_player_actor/z_player.c | 5 +- .../overlays/gamestates/ovl_select/z_select.c | 7 +- .../ovl_kaleido_scope/z_kaleido_map_PAL.c | 31 +- .../ovl_kaleido_scope/z_kaleido_scope_PAL.c | 11 +- .../misc/ovl_kaleido_scope/z_lmap_mark.c | 184 +- 36 files changed, 4621 insertions(+), 978 deletions(-) create mode 100644 soh/soh/SceneDB.cpp create mode 100644 soh/soh/SceneDB.h create mode 100644 soh/soh/SceneDB_Table.cpp diff --git a/soh/include/z64.h b/soh/include/z64.h index cd66089a8f6..f2caaeb2ca5 100644 --- a/soh/include/z64.h +++ b/soh/include/z64.h @@ -1675,7 +1675,8 @@ typedef struct PreNMIContext { } PreNMIContext; // size = 0xAC typedef enum { - /* 1 */ F_8F = 1, + /* 0 */ F_NA, + /* 1 */ F_8F, /* 2 */ F_7F, /* 3 */ F_6F, /* 4 */ F_5F, diff --git a/soh/include/z64save.h b/soh/include/z64save.h index b64efb459d6..094823919a4 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -48,8 +48,8 @@ typedef struct { /* 0x28 */ u16 equipment; // a mask where each nibble corresponds to a type of equipment `EquipmentType`, and each bit to an owned piece `EquipInv*` /* 0x2C */ u32 upgrades; /* 0x30 */ u32 questItems; - /* 0x34 */ u8 dungeonItems[20]; - /* 0x48 */ s8 dungeonKeys[19]; + /* 0x34 */ u8* dungeonItems; + /* 0x48 */ s8* dungeonKeys; /* 0x5B */ s8 defenseHearts; /* 0x5C */ s16 gsTokens; } Inventory; // size = 0x5E @@ -189,7 +189,7 @@ typedef struct { /* 0x0066 */ s16 savedSceneNum; // Upstream TODO: sceneId /* 0x0068 */ ItemEquips equips; /* 0x0074 */ Inventory inventory; - /* 0x00D4 */ SavedSceneFlags sceneFlags[124]; + /* 0x00D4 */ SavedSceneFlags* sceneFlags; /* 0x0E64 */ FaroresWindData fw; /* 0x0E8C */ char unk_E8C[0x10]; /* 0x0E9C */ s32 gsFlags[6]; diff --git a/soh/soh/ActorDB.cpp b/soh/soh/ActorDB.cpp index de25388887d..6b9e41ef6c3 100644 --- a/soh/soh/ActorDB.cpp +++ b/soh/soh/ActorDB.cpp @@ -513,7 +513,7 @@ ActorDB::Entry& ActorDB::AddEntry(const std::string& name, const std::string& de return entry; } -// Adds an actor with the new ActorDBInit struct. The id assigned to the actor is dynamic. Use the return Entry or RetrieveId to get it. +// Adds an actor with the new ActorDBInit struct. The id assigned to the actor is dynamic. Use the returned Entry or RetrieveId to get it. ActorDB::Entry& ActorDB::AddEntry(const ActorDBInit& init) { Entry& entry = AddEntry(init.name, init.desc, nextFreeId); diff --git a/soh/soh/Enhancements/randomizer/hook_handlers.cpp b/soh/soh/Enhancements/randomizer/hook_handlers.cpp index 000081cecca..4cd80f2b144 100644 --- a/soh/soh/Enhancements/randomizer/hook_handlers.cpp +++ b/soh/soh/Enhancements/randomizer/hook_handlers.cpp @@ -1,6 +1,7 @@ #include #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" #include "soh/Enhancements/enhancementTypes.h" #include "soh/Enhancements/custom-message/CustomMessageTypes.h" #include "soh/Enhancements/item-tables/ItemTableManager.h" @@ -835,7 +836,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l case VB_BE_ELIGIBLE_FOR_LIGHT_ARROWS: *should = LINK_IS_ADULT && - (gEntranceTable[gSaveContext.entranceIndex].scene == SCENE_TEMPLE_OF_TIME) && + (EntranceDB::Instance->RetrieveEntry(gSaveContext.entranceIndex).entry.sceneId == SCENE_TEMPLE_OF_TIME) && !Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS) && MeetsLACSRequirements(); break; @@ -843,7 +844,7 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l *should = !Flags_GetEventChkInf(EVENTCHKINF_BONGO_BONGO_ESCAPED_FROM_WELL) && LINK_IS_ADULT && - gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_KAKARIKO_VILLAGE && + (EntranceDB::Instance->RetrieveEntry(gSaveContext.entranceIndex).entry.sceneId == SCENE_KAKARIKO_VILLAGE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_FOREST) && CHECK_QUEST_ITEM(QUEST_MEDALLION_FIRE) && CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER); diff --git a/soh/soh/Enhancements/randomizer/logic.cpp b/soh/soh/Enhancements/randomizer/logic.cpp index da76be1d321..42687727dfd 100644 --- a/soh/soh/Enhancements/randomizer/logic.cpp +++ b/soh/soh/Enhancements/randomizer/logic.cpp @@ -8,6 +8,7 @@ #include #include "soh/OTRGlobals.h" +#include "soh/SceneDB.h" #include "dungeon.h" #include "context.h" #include "macros.h" @@ -1785,6 +1786,7 @@ namespace Rando { mSaveContext->equips.equipment = 0; // Inventory + size_t numScenes = SceneDB::Instance->GetNumEntries(); for (int item = 0; item < ARRAY_COUNT(mSaveContext->inventory.items); item++) { mSaveContext->inventory.items[item] = ITEM_NONE; } @@ -1794,15 +1796,15 @@ namespace Rando { mSaveContext->inventory.equipment = 0; mSaveContext->inventory.upgrades = 0; mSaveContext->inventory.questItems = 0; - for (int dungeon = 0; dungeon < ARRAY_COUNT(mSaveContext->inventory.dungeonItems); dungeon++) { + for (int dungeon = 0; dungeon < numScenes; dungeon++) { mSaveContext->inventory.dungeonItems[dungeon] = 0; } - for (int dungeon = 0; dungeon < ARRAY_COUNT(mSaveContext->inventory.dungeonKeys); dungeon++) { + for (int dungeon = 0; dungeon < numScenes; dungeon++) { mSaveContext->inventory.dungeonKeys[dungeon] = 0x0; } mSaveContext->inventory.defenseHearts = 0; mSaveContext->inventory.gsTokens = 0; - for (int scene = 0; scene < ARRAY_COUNT(mSaveContext->sceneFlags); scene++) { + for (int scene = 0; scene < numScenes; scene++) { mSaveContext->sceneFlags[scene].chest = 0; mSaveContext->sceneFlags[scene].swch = 0; mSaveContext->sceneFlags[scene].clear = 0; @@ -1882,9 +1884,16 @@ namespace Rando { void Logic::NewSaveContext() { if (mSaveContext != nullptr && mSaveContext != &gSaveContext) { - free(mSaveContext); + delete[] mSaveContext->inventory.dungeonItems; + delete[] mSaveContext->inventory.dungeonKeys; + delete[] mSaveContext->sceneFlags; + delete mSaveContext; } + size_t numScenes = SceneDB::Instance->GetNumEntries(); mSaveContext = new SaveContext(); + mSaveContext->inventory.dungeonItems = new u8[numScenes]; + mSaveContext->inventory.dungeonKeys = new s8[numScenes]; + mSaveContext->sceneFlags = new SavedSceneFlags[numScenes]; InitSaveContext(); } diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 8f4a1668cdc..c476b1db1e8 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -11,6 +11,7 @@ #include "randomizer_grotto.h" #include "soh/OTRGlobals.h" #include "soh/SaveManager.h" +#include "soh/SceneDB.h" #include #include "global.h" @@ -46,8 +47,6 @@ static s16 entranceOverrideTable[ENTRANCE_TABLE_SIZE] = {0}; static s16 bossSceneSaveDeathWarps[SHUFFLEABLE_BOSS_COUNT] = {0}; static ActorEntry modifiedLinkActorEntry = {0}; -EntranceInfo originalEntranceTable[ENTRANCE_TABLE_SIZE] = {0}; - typedef struct { s16 entryway; s16 exit; @@ -84,7 +83,7 @@ static void Entrance_SeparateOGCFairyFountainExit(void) { //Overwrite unused entrance 0x03E8 (ENTR_POTION_SHOP_KAKARIKO_1) with values from 0x0340 (ENTR_CASTLE_GROUNDS_GREAT_FAIRY_EXIT) to use it as the //exit from OGC Great Fairy Fountain -> Castle Grounds for (size_t i = 0; i < 4; ++i) { - gEntranceTable[ENTR_POTION_SHOP_KAKARIKO_1 + i] = gEntranceTable[ENTR_CASTLE_GROUNDS_GREAT_FAIRY_EXIT + i]; + EntranceDB_Copy(ENTR_CASTLE_GROUNDS_GREAT_FAIRY_EXIT + i, ENTR_POTION_SHOP_KAKARIKO_1 + i); } } @@ -92,7 +91,7 @@ static void Entrance_SeparateAdultSpawnAndPrelude() { // Overwrite unused entrance 0x0282 (ENTR_HYRULE_FIELD_10) with values from 0x05F4 (ENTR_TEMPLE_OF_TIME_WARP_PAD) to use it as the // Adult Spawn index and separate it from Prelude of Light for (size_t i = 0; i < 4; ++i) { - gEntranceTable[ENTR_HYRULE_FIELD_10 + i] = gEntranceTable[ENTR_TEMPLE_OF_TIME_WARP_PAD + i]; + EntranceDB_Copy(ENTR_TEMPLE_OF_TIME_WARP_PAD + i, ENTR_HYRULE_FIELD_10 + i); } } @@ -101,53 +100,45 @@ static void Entrance_ReplaceChildTempleWarps() { if (Randomizer_GetSettingValue(RSK_SHUFFLE_DUNGEON_ENTRANCES) != RO_DUNGEON_ENTRANCE_SHUFFLE_OFF || Randomizer_GetSettingValue(RSK_SHUFFLE_BOSS_ENTRANCES) != RO_BOSS_ROOM_ENTRANCE_SHUFFLE_OFF) { // Forest Temple - gEntranceTable[ENTR_SACRED_FOREST_MEADOW_FOREST_TEMPLE_BLUE_WARP] = gEntranceTable[ENTR_SACRED_FOREST_MEADOW_WARP_PAD]; - gEntranceTable[ENTR_SACRED_FOREST_MEADOW_3_1] = gEntranceTable[ENTR_SACRED_FOREST_MEADOW_2_1]; + EntranceDB_Copy(ENTR_SACRED_FOREST_MEADOW_WARP_PAD, ENTR_SACRED_FOREST_MEADOW_FOREST_TEMPLE_BLUE_WARP); + EntranceDB_Copy(ENTR_SACRED_FOREST_MEADOW_2_1, ENTR_SACRED_FOREST_MEADOW_3_1); // Fire Temple - gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_FIRE_TEMPLE_BLUE_WARP] = gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_WARP_PAD]; - gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_5_1] = gEntranceTable[ENTR_DEATH_MOUNTAIN_CRATER_4_1]; + EntranceDB_Copy(ENTR_DEATH_MOUNTAIN_CRATER_WARP_PAD, ENTR_DEATH_MOUNTAIN_CRATER_FIRE_TEMPLE_BLUE_WARP); + EntranceDB_Copy(ENTR_DEATH_MOUNTAIN_CRATER_4_1, ENTR_DEATH_MOUNTAIN_CRATER_5_1); // Water Temple - gEntranceTable[ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP] = gEntranceTable[ENTR_LAKE_HYLIA_WARP_PAD]; - gEntranceTable[ENTR_LAKE_HYLIA_9_1] = gEntranceTable[ENTR_LAKE_HYLIA_8_1]; + EntranceDB_Copy(ENTR_LAKE_HYLIA_WARP_PAD, ENTR_LAKE_HYLIA_WATER_TEMPLE_BLUE_WARP); + EntranceDB_Copy(ENTR_LAKE_HYLIA_8_1, ENTR_LAKE_HYLIA_9_1); // Shadow Temple - gEntranceTable[ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP] = gEntranceTable[ENTR_GRAVEYARD_WARP_PAD]; - gEntranceTable[ENTR_GRAVEYARD_8_1] = gEntranceTable[ENTR_GRAVEYARD_7_1]; + EntranceDB_Copy(ENTR_GRAVEYARD_WARP_PAD, ENTR_GRAVEYARD_SHADOW_TEMPLE_BLUE_WARP); + EntranceDB_Copy(ENTR_GRAVEYARD_7_1, ENTR_GRAVEYARD_8_1); // Spirit Temple - gEntranceTable[ENTR_DESERT_COLOSSUS_SPIRIT_TEMPLE_BLUE_WARP] = gEntranceTable[ENTR_DESERT_COLOSSUS_WARP_PAD]; - gEntranceTable[ENTR_DESERT_COLOSSUS_8_1] = gEntranceTable[ENTR_DESERT_COLOSSUS_5_1]; - } -} - -void Entrance_CopyOriginalEntranceTable(void) { - if (!hasCopiedEntranceTable) { - memcpy(originalEntranceTable, gEntranceTable, sizeof(EntranceInfo) * ENTRANCE_TABLE_SIZE); - hasCopiedEntranceTable = 1; + EntranceDB_Copy(ENTR_DESERT_COLOSSUS_WARP_PAD, ENTR_DESERT_COLOSSUS_SPIRIT_TEMPLE_BLUE_WARP); + EntranceDB_Copy(ENTR_DESERT_COLOSSUS_5_1, ENTR_DESERT_COLOSSUS_8_1); } } void Entrance_ResetEntranceTable(void) { - if (hasCopiedEntranceTable && hasModifiedEntranceTable) { - memcpy(gEntranceTable, originalEntranceTable, sizeof(EntranceInfo) * ENTRANCE_TABLE_SIZE); - hasModifiedEntranceTable = 0; - } + EntranceDB_ResetVanillaEntrances(); } void Entrance_Init(void) { EntranceOverride* entranceOverrides = Randomizer_GetEntranceOverrides(); s32 index; - Entrance_CopyOriginalEntranceTable(); - // Skip Child Stealth if given by settings if (Randomizer_GetSettingValue(RSK_SKIP_CHILD_STEALTH)) { - gEntranceTable[ENTR_CASTLE_COURTYARD_GUARDS_DAY_0].scene = SCENE_CASTLE_COURTYARD_ZELDA; - gEntranceTable[ENTR_CASTLE_COURTYARD_GUARDS_DAY_0].spawn = 0; - gEntranceTable[ENTR_CASTLE_COURTYARD_GUARDS_DAY_0].field = ENTRANCE_INFO_FIELD(false, false, TRANS_TYPE_FADE_WHITE, TRANS_TYPE_FADE_WHITE); + EntranceDB_Copy(ENTR_CASTLE_COURTYARD_ZELDA_0, ENTR_CASTLE_COURTYARD_GUARDS_DAY_0); } // Delete the title card and add a fade in for Hyrule Field from Ocarina of Time cutscene for (index = ENTR_HYRULE_FIELD_16; index <= ENTR_HYRULE_FIELD_16_3; ++index) { - gEntranceTable[index].field = ENTRANCE_INFO_FIELD(false, false, TRANS_TYPE_FADE_BLACK, TRANS_TYPE_INSTANT); + // Normally modifying a EntranceDBEntry is not safe since it can mess up the internal tables, + // but since we are just changing the cosmetic stuff, it is fine + EntranceDBEntry* entry = EntranceDB_Retrieve(index); + entry->continueBgm = false; + entry->displayTitleCard = false; + entry->endTransition = TRANS_TYPE_FADE_BLACK; + entry->startTransition = TRANS_TYPE_INSTANT; } Entrance_SeparateOGCFairyFountainExit(); @@ -240,9 +231,7 @@ void Entrance_Init(void) { s16 override = indicesToSilenceBackgroundMusic[j]; for (s16 i = 0; i < 4; i++) { - // Zero out the bit in the field which tells the game to keep playing - // background music for all four scene setups at each index - gEntranceTable[override + i].field &= ~ENTRANCE_INFO_CONTINUE_BGM_FLAG; + EntranceDB_Retrieve(override + i)->continueBgm = false; } } } @@ -310,8 +299,8 @@ u32 Entrance_SceneAndSpawnAre(u8 scene, u8 spawn) { } } - EntranceInfo currentEntrance = gEntranceTable[entranceIndex]; - return currentEntrance.scene == scene && currentEntrance.spawn == spawn; + EntranceDBEntry* entry = EntranceDB_Retrieve(entranceIndex); + return entry->sceneId == scene && entry->spawn == spawn; } // Properly respawn the player after a game over, accounting for dungeon entrance randomizer diff --git a/soh/soh/Enhancements/timesaver_hook_handlers.cpp b/soh/soh/Enhancements/timesaver_hook_handlers.cpp index d9c13ed927e..eb14cb5b323 100644 --- a/soh/soh/Enhancements/timesaver_hook_handlers.cpp +++ b/soh/soh/Enhancements/timesaver_hook_handlers.cpp @@ -1,5 +1,6 @@ #include #include "soh/OTRGlobals.h" +#include "soh/SceneDB.h" #include "soh/Enhancements/randomizer/randomizerTypes.h" #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" @@ -171,7 +172,7 @@ void TimeSaverOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_li // LACS u8 meetsLACSRequirements = LINK_IS_ADULT && - (gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TEMPLE_OF_TIME) && + (EntranceDB::Instance->RetrieveEntry(gSaveContext.entranceIndex).entry.sceneId == SCENE_TEMPLE_OF_TIME) && CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) && !Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS); diff --git a/soh/soh/Enhancements/tts/tts.cpp b/soh/soh/Enhancements/tts/tts.cpp index 9d58e2d62c7..899c67845f3 100644 --- a/soh/soh/Enhancements/tts/tts.cpp +++ b/soh/soh/Enhancements/tts/tts.cpp @@ -9,13 +9,13 @@ #include #include "soh/OTRGlobals.h" +#include "soh/SceneDB.h" #include "message_data_static.h" #include "overlays/gamestates/ovl_file_choose/file_choose.h" #include "soh/Enhancements/boss-rush/BossRush.h" #include "soh/resource/type/SohResourceType.h" extern "C" { -extern MapData* gMapData; extern SaveContext gSaveContext; extern PlayState* gPlayState; } @@ -204,6 +204,7 @@ void RegisterOnKaleidoscopeUpdateHook() { PauseContext* pauseCtx = &gPlayState->pauseCtx; Input* input = &gPlayState->state.input[0]; + SceneDB::Entry& scene = SceneDB::Instance->RetrieveEntry(gSaveContext.mapIndex); // Save game prompt if (pauseCtx->state == 7) { @@ -452,7 +453,7 @@ void RegisterOnKaleidoscopeUpdateHook() { // Cursor is on a dungeon floor position if (cursorPoint >= 3 && cursorPoint < 11) { - int floorID = gMapData->floorID[gPlayState->interfaceCtx.unk_25A][pauseCtx->dungeonMapSlot - 3]; + int floorID = scene.entry.dungeonData.floors[pauseCtx->dungeonMapSlot - 3].id; // Normalize so F1 == 0, and negative numbers are basement levels int normalizedFloor = (floorID * -1) + 8; if (normalizedFloor >= 0) { diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp index 009bf76ad32..7bcabfd71ed 100644 --- a/soh/soh/OTRGlobals.cpp +++ b/soh/soh/OTRGlobals.cpp @@ -73,6 +73,7 @@ #include "SohGui.hpp" #include "ActorDB.h" #include "SaveManager.h" +#include "SceneDB.h" #ifdef ENABLE_REMOTE_CONTROL #include "soh/Network/CrowdControl/CrowdControl.h" @@ -1150,6 +1151,8 @@ extern "C" void InitOTR() { SohGui::SetupGuiElements(); AudioCollection::Instance = new AudioCollection(); ActorDB::Instance = new ActorDB(); + SceneDB::Instance = new SceneDB(); + EntranceDB::Instance = new EntranceDB(); #ifdef __APPLE__ SpeechSynthesizer::Instance = new DarwinSpeechSynthesizer(); SpeechSynthesizer::Instance->Init(); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 1edec30258c..58b8355e294 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -15,6 +15,7 @@ #include "macros.h" #include #include +#include "soh/SceneDB.h" #include "SohGui.hpp" #define NOGDI // avoid various windows defines that conflict with things in z64.h @@ -23,6 +24,7 @@ #include #include #include +#include #include extern "C" SaveContext gSaveContext; @@ -116,7 +118,8 @@ SaveManager::SaveManager() { AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 3, LoadBaseVersion3); AddLoadFunction("base", 4, LoadBaseVersion4); - AddSaveFunction("base", 4, SaveBase, true, SECTION_PARENT_NONE); + AddLoadFunction("base", 5, LoadBaseVersion5); + AddSaveFunction("base", 5, SaveBase, true, SECTION_PARENT_NONE); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); @@ -713,6 +716,7 @@ void SaveManager::InitFile(bool isDebug) { } void SaveManager::InitFileImpl(bool isDebug) { + AllocateSceneData(); if (isDebug) { InitFileDebug(); } else { @@ -777,23 +781,11 @@ void SaveManager::InitFileNormal() { gSaveContext.inventory.equipment = 0x1100; gSaveContext.inventory.upgrades = 0; gSaveContext.inventory.questItems = 0; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonItems); dungeon++) { - gSaveContext.inventory.dungeonItems[dungeon] = 0; - } - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonKeys); dungeon++) { - gSaveContext.inventory.dungeonKeys[dungeon] = 0xFF; - } + std::fill_n(gSaveContext.inventory.dungeonItems, SceneDB::Instance->GetNumEntries(), 0); + std::fill_n(gSaveContext.inventory.dungeonKeys, SceneDB::Instance->GetNumEntries(), -1); gSaveContext.inventory.defenseHearts = 0; gSaveContext.inventory.gsTokens = 0; - for (int scene = 0; scene < ARRAY_COUNT(gSaveContext.sceneFlags); scene++) { - gSaveContext.sceneFlags[scene].chest = 0; - gSaveContext.sceneFlags[scene].swch = 0; - gSaveContext.sceneFlags[scene].clear = 0; - gSaveContext.sceneFlags[scene].collect = 0; - gSaveContext.sceneFlags[scene].unk = 0; - gSaveContext.sceneFlags[scene].rooms = 0; - gSaveContext.sceneFlags[scene].floors = 0; - } + std::fill_n(gSaveContext.sceneFlags, SceneDB::Instance->GetNumEntries(), SavedSceneFlags{ 0, 0, 0, 0, 0, 0, 0 }); gSaveContext.fw.pos.x = 0; gSaveContext.fw.pos.y = 0; gSaveContext.fw.pos.z = 0; @@ -946,13 +938,12 @@ void SaveManager::InitFileDebug() { gSaveContext.inventory.equipment = 0x7777; gSaveContext.inventory.upgrades = 0x125249; gSaveContext.inventory.questItems = 0x1E3FFFF; - static std::array sDungeonItems = { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonItems); dungeon++) { - gSaveContext.inventory.dungeonItems[dungeon] = sDungeonItems[dungeon]; - } - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonKeys); dungeon++) { - gSaveContext.inventory.dungeonKeys[dungeon] = 8; + std::fill_n(gSaveContext.inventory.dungeonItems, SceneDB::Instance->GetNumEntries(), 0); + for (int dungeon = 0; dungeon <= SCENE_ICE_CAVERN; dungeon++) { + gSaveContext.inventory.dungeonItems[dungeon] = 0b111; } + std::fill_n(gSaveContext.inventory.dungeonKeys, SceneDB::Instance->GetNumEntries(), 8); + gSaveContext.inventory.defenseHearts = 0; gSaveContext.inventory.gsTokens = 0; @@ -1049,13 +1040,8 @@ void SaveManager::InitFileMaxed() { gSaveContext.inventory.equipment = 0x7777; gSaveContext.inventory.upgrades = 3597531; gSaveContext.inventory.questItems = 33554431; - static std::array sDungeonItems = { 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonItems); dungeon++) { - gSaveContext.inventory.dungeonItems[dungeon] = sDungeonItems[dungeon]; - } - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.inventory.dungeonKeys); dungeon++) { - gSaveContext.inventory.dungeonKeys[dungeon] = 9; - } + std::fill_n(gSaveContext.inventory.dungeonItems, SceneDB::Instance->GetNumEntries(), 0b111); + std::fill_n(gSaveContext.inventory.dungeonKeys, SceneDB::Instance->GetNumEntries(), 9); gSaveContext.inventory.defenseHearts = 20; gSaveContext.inventory.gsTokens = 100; @@ -1124,6 +1110,22 @@ void SaveManager::InitFileMaxed() { gSaveContext.sceneFlags[5].swch = 0x40000000; } +void SaveManager::AllocateSceneData() { + delete[] gSaveContext.inventory.dungeonItems; + delete[] gSaveContext.inventory.dungeonKeys; + delete[] gSaveContext.sceneFlags; + + size_t numScenes = SceneDB::Instance->GetNumEntries(); + + gSaveContext.inventory.dungeonItems = new u8[numScenes]; + gSaveContext.inventory.dungeonKeys = new s8[numScenes]; + gSaveContext.sceneFlags = new SavedSceneFlags[numScenes]; + + std::fill_n(gSaveContext.inventory.dungeonItems, numScenes, 0); + std::fill_n(gSaveContext.inventory.dungeonKeys, numScenes, -1); + std::fill_n(gSaveContext.sceneFlags, numScenes, SavedSceneFlags{ 0, 0, 0, 0, 0, 0, 0 }); +} + #if defined(__WIIU__) || defined(__SWITCH__) // std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm int copy_file(const char* src, const char* dst) { @@ -1491,16 +1493,16 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); - SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadArray("sceneFlags", SCENE_ID_MAX, [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); @@ -1636,10 +1638,10 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); @@ -1668,7 +1670,7 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); }); - SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadArray("sceneFlags", SCENE_ID_MAX, [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); @@ -1852,10 +1854,10 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); @@ -1901,7 +1903,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); }); - SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadArray("sceneFlags", SCENE_ID_MAX, [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); @@ -2073,16 +2075,16 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); - SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); }); - SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadArray("sceneFlags", SCENE_ID_MAX, [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); @@ -2157,6 +2159,186 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); }); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + }); + int isMQ = 0; + SaveManager::Instance->LoadData("isMasterQuest", isMQ); + if (isMQ) { + gSaveContext.questId = QUEST_MASTER; + } + SaveManager::Instance->LoadStruct("backupFW", []() { + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + }); + SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + }); + SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); +} + +void SaveManager::LoadBaseVersion5() { + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.entranceIndex); + SaveManager::Instance->LoadData("linkAge", gSaveContext.linkAge); + SaveManager::Instance->LoadData("cutsceneIndex", gSaveContext.cutsceneIndex); + SaveManager::Instance->LoadData("dayTime", gSaveContext.dayTime); + SaveManager::Instance->LoadData("nightFlag", gSaveContext.nightFlag); + SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); + SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); + SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); + int isRando = 0; + SaveManager::Instance->LoadData("n64ddFlag", isRando); + if (isRando) { + gSaveContext.questId = QUEST_RANDOMIZER; + } + SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); + SaveManager::Instance->LoadData("health", gSaveContext.health); + SaveManager::Instance->LoadData("magicLevel", gSaveContext.magicLevel); + SaveManager::Instance->LoadData("magic", gSaveContext.magic); + SaveManager::Instance->LoadData("rupees", gSaveContext.rupees); + SaveManager::Instance->LoadData("swordHealth", gSaveContext.swordHealth); + SaveManager::Instance->LoadData("naviTimer", gSaveContext.naviTimer); + SaveManager::Instance->LoadData("isMagicAcquired", gSaveContext.isMagicAcquired); + SaveManager::Instance->LoadData("isDoubleMagicAcquired", gSaveContext.isDoubleMagicAcquired); + SaveManager::Instance->LoadData("isDoubleDefenseAcquired", gSaveContext.isDoubleDefenseAcquired); + SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); + SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); + SaveManager::Instance->LoadStruct("childEquips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); + }); + SaveManager::Instance->LoadStruct("adultEquips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); + }); + SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); + SaveManager::Instance->LoadData("savedSceneNum", gSaveContext.savedSceneNum); + SaveManager::Instance->LoadStruct("equips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.equips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.buttonItems[i], static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.equips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.cButtonSlots[i], static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.equips.equipment); + }); + SaveManager::Instance->LoadStruct("inventory", []() { + SaveManager::Instance->LoadArray("items", ARRAY_COUNT(gSaveContext.inventory.items), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.items[i]); + }); + SaveManager::Instance->LoadArray("ammo", ARRAY_COUNT(gSaveContext.inventory.ammo), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.ammo[i]); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); + SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); + SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); + SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); + SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); + }); + SaveManager::Instance->LoadStruct("sceneData", []() { + for (size_t i = 0; i < SceneDB::Instance->GetNumEntries(); i++) { + const SceneDB::Entry& entry = SceneDB::Instance->RetrieveEntry(static_cast(i)); + SaveManager::Instance->LoadStruct(entry.name, [&i]() { + SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); + SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); + SaveManager::Instance->LoadData("clear", gSaveContext.sceneFlags[i].clear); + SaveManager::Instance->LoadData("collect", gSaveContext.sceneFlags[i].collect); + SaveManager::Instance->LoadData("unk", gSaveContext.sceneFlags[i].unk); + SaveManager::Instance->LoadData("rooms", gSaveContext.sceneFlags[i].rooms); + SaveManager::Instance->LoadData("floors", gSaveContext.sceneFlags[i].floors); + SaveManager::Instance->LoadData("dungeonKeys", gSaveContext.inventory.dungeonKeys[i]); + SaveManager::Instance->LoadData("dungeonItems", gSaveContext.inventory.dungeonItems[i]); + }); + } + }); + SaveManager::Instance->LoadStruct("fw", []() { + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.fw.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.fw.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.fw.pos.z); + }); + SaveManager::Instance->LoadData("yaw", gSaveContext.fw.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.fw.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.fw.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.fw.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.fw.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); + }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); + SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); + }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); + SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); + SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); + SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + }); + }); + SaveManager::Instance->LoadData("scarecrowSpawnSongSet", gSaveContext.scarecrowSpawnSongSet); + SaveManager::Instance->LoadArray("scarecrowSpawnSong", ARRAY_COUNT(gSaveContext.scarecrowSpawnSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowSpawnSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowSpawnSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowSpawnSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowSpawnSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowSpawnSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowSpawnSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowSpawnSong[i].semitone); + }); + }); + SaveManager::Instance->LoadStruct("horseData", []() { + SaveManager::Instance->LoadData("scene", gSaveContext.horseData.scene); + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.horseData.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.horseData.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.horseData.pos.z); + }); + SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); + }); + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); }); @@ -2247,25 +2429,24 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav SaveManager::Instance->SaveData("equipment", saveContext->inventory.equipment); SaveManager::Instance->SaveData("upgrades", saveContext->inventory.upgrades); SaveManager::Instance->SaveData("questItems", saveContext->inventory.questItems); - SaveManager::Instance->SaveArray("dungeonItems", ARRAY_COUNT(saveContext->inventory.dungeonItems), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->inventory.dungeonItems[i]); - }); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->inventory.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->inventory.dungeonKeys[i]); - }); SaveManager::Instance->SaveData("defenseHearts", saveContext->inventory.defenseHearts); SaveManager::Instance->SaveData("gsTokens", saveContext->inventory.gsTokens); }); - SaveManager::Instance->SaveArray("sceneFlags", ARRAY_COUNT(saveContext->sceneFlags), [&](size_t i) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("chest", saveContext->sceneFlags[i].chest); - SaveManager::Instance->SaveData("swch", saveContext->sceneFlags[i].swch); - SaveManager::Instance->SaveData("clear", saveContext->sceneFlags[i].clear); - SaveManager::Instance->SaveData("collect", saveContext->sceneFlags[i].collect); - SaveManager::Instance->SaveData("unk", saveContext->sceneFlags[i].unk); - SaveManager::Instance->SaveData("rooms", saveContext->sceneFlags[i].rooms); - SaveManager::Instance->SaveData("floors", saveContext->sceneFlags[i].floors); - }); + SaveManager::Instance->SaveStruct("sceneData", [&]() { + for (size_t i = 0; i < SceneDB::Instance->GetNumEntries(); i++) { + const SceneDB::Entry& entry = SceneDB::Instance->RetrieveEntry(static_cast(i)); + SaveManager::Instance->SaveStruct(entry.name, [&]() { + SaveManager::Instance->SaveData("chest", saveContext->sceneFlags[i].chest); + SaveManager::Instance->SaveData("swch", saveContext->sceneFlags[i].swch); + SaveManager::Instance->SaveData("clear", saveContext->sceneFlags[i].clear); + SaveManager::Instance->SaveData("collect", saveContext->sceneFlags[i].collect); + SaveManager::Instance->SaveData("unk", saveContext->sceneFlags[i].unk); + SaveManager::Instance->SaveData("rooms", saveContext->sceneFlags[i].rooms); + SaveManager::Instance->SaveData("floors", saveContext->sceneFlags[i].floors); + SaveManager::Instance->SaveData("dungeonKeys", saveContext->inventory.dungeonKeys[i]); + SaveManager::Instance->SaveData("dungeonItems", saveContext->inventory.dungeonItems[i]); + }); + } }); SaveManager::Instance->SaveStruct("fw", [&]() { SaveManager::Instance->SaveStruct("pos", [&]() { @@ -2729,7 +2910,7 @@ void CopyV0Save(SaveContext_v0& src, SaveContext& dst) { } dst.inventory.defenseHearts = src.inventory.defenseHearts; dst.inventory.gsTokens = src.inventory.gsTokens; - for (size_t i = 0; i < ARRAY_COUNT(src.sceneFlags); i++) { + for (size_t i = 0; i < SCENE_ID_MAX; i++) { dst.sceneFlags[i].chest = src.sceneFlags[i].chest; dst.sceneFlags[i].swch = src.sceneFlags[i].swch; dst.sceneFlags[i].clear = src.sceneFlags[i].clear; diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 1eb6ee87ab3..c9fb90af980 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -159,6 +159,8 @@ class SaveManager { static void InitFileDebug(); static void InitFileMaxed(); + static void AllocateSceneData(); + static void LoadRandomizerVersion1(); static void LoadRandomizerVersion2(); static void LoadRandomizerVersion3(); @@ -170,6 +172,7 @@ class SaveManager { static void LoadBaseVersion2(); static void LoadBaseVersion3(); static void LoadBaseVersion4(); + static void LoadBaseVersion5(); static void SaveBase(SaveContext* saveContext, int sectionID, bool fullSave); std::vector initFuncs; diff --git a/soh/soh/SceneDB.cpp b/soh/soh/SceneDB.cpp new file mode 100644 index 00000000000..b7e61640c23 --- /dev/null +++ b/soh/soh/SceneDB.cpp @@ -0,0 +1,1173 @@ +#include "SceneDB.h" + +#include +#include +#include + +#include "variables.h" + +SceneDB* SceneDB::Instance; +EntranceDB* EntranceDB::Instance; + +extern const std::vector sceneDBInit; + +// We need a different struct than EntranceDB::Init (scene is a int not a string) because tables/entrance_table.h has the scene +// as an enum, which we do not have a compile-time way to convert to a string +struct EntranceTableInit { + std::string name; + std::string desc; + s32 scene; + s32 spawn; + bool continueBgm; + bool displayTitleCard; + u8 endTransition; + u8 startTransition; +}; + +#define DEFINE_ENTRANCE(enumName, sceneId, spawn, continueBgm, displayTitleCard, endTransType, startTransType) \ + { #enumName, "", sceneId, spawn, continueBgm, displayTitleCard, endTransType, startTransType }, + +static const EntranceTableInit entranceDBInit[] = { +#include "tables/entrance_table.h" +}; + +#undef DEFINE_ENTRANCE + +SceneDB::SceneDB() { + db.reserve(SCENE_ID_MAX); // reserve size for all initial entries so we don't do it for each + for (const Init& init : sceneDBInit) { + AddEntry(init); + } + + SceneDB::Entry& entry = RetrieveEntry(SCENE_BOTTOM_OF_THE_WELL); + entry.entry.epona.allowed = true; + entry.SetEponaSpawnPos({ { -630, 0, 53} }); +} + +// Adds an scene at the given index. The name must be unique. +SceneDB::Entry& SceneDB::AddEntry(const std::string& name, const std::string& desc, size_t index) { + assert(!nameTable.contains(name)); // TODO this should maybe throw instead. We'll need to think about error handling + // for mods that try to declare the same scene. + + if (db.size() < (index + 1)) { + db.resize(index + 1); + } + Entry& newEntry = db.at(index); + newEntry.entry.id = index; + + assert(!newEntry.entry.valid); + + nextFreeId = std::max(nextFreeId, index + 1); + + nameTable[name] = newEntry.entry.id; + newEntry.SetName(name); + newEntry.SetDesc(desc); + + newEntry.entry.valid = true; + + return newEntry; +} + +// Adds an scene with the new SceneDBInit struct. The id assigned to the scene is dynamic. Use the returned Entry or +// RetrieveId to get it. +SceneDB::Entry& SceneDB::AddEntry(const Init& init) { + Entry& entry = AddEntry(init.name, init.desc, nextFreeId); + + entry.SetTitleCard(init.titleCard); + + entry.entry.sceneDrawConfig = init.sceneDrawConfig; + entry.entry.restrictions.hGauge = init.restrictions.hGauge; + entry.entry.restrictions.bButton = init.restrictions.bButton; + entry.entry.restrictions.aButton = init.restrictions.aButton; + entry.entry.restrictions.bottles = init.restrictions.bottles; + entry.entry.restrictions.tradeItems = init.restrictions.tradeItems; + entry.entry.restrictions.hookshot = init.restrictions.hookshot; + entry.entry.restrictions.ocarina = init.restrictions.ocarina; + entry.entry.restrictions.warpSongs = init.restrictions.warpSongs; + entry.entry.restrictions.sunsSong = init.restrictions.sunsSong; + entry.entry.restrictions.farores = init.restrictions.farores; + entry.entry.restrictions.dinsNayrus = init.restrictions.dinsNayrus; + entry.entry.restrictions.all = init.restrictions.all; + entry.entry.epona.allowed = init.epona.allowed; + entry.entry.epona.startingPos = init.epona.startingPos; + entry.entry.epona.angle = init.epona.angle; + entry.SetEponaSpawnPos(init.epona.spawnPos); + + entry.entry.compassInfo.scaleX = init.compassInfo.scaleX; + entry.entry.compassInfo.scaleY = init.compassInfo.scaleY; + entry.entry.compassInfo.x = init.compassInfo.x; + entry.entry.compassInfo.y = init.compassInfo.y; + + if (init.bossData.mapScene != "") { + int id = RetrieveId(init.bossData.mapScene); + assert(id != -1); // TODO error of some kind for invalid mods + entry.entry.bossData.mapScene = id; + } else { + entry.entry.bossData.mapScene = -1; + } + entry.entry.dungeonData.bossFloor = init.dungeonData.bossFloor; + entry.SetDungeonPalettes(init.dungeonData.palettes); + entry.SetDungeonNameTextures(init.dungeonData.nameEngTexture, init.dungeonData.nameGerTexture, init.dungeonData.nameFraTexture); + entry.SetDungeonFloors(init.dungeonData.floors); + entry.SetDungeonRooms(init.dungeonData.rooms); + entry.SetDungeonIntraRoomTransitions(init.dungeonData.intraRoomTransitions); + + entry.entry.worldData.minimapX = init.worldData.minimapX; + entry.entry.worldData.minimapY = init.worldData.minimapY; + entry.entry.worldData.minimapWidth = init.worldData.minimapWidth; + entry.entry.worldData.minimapHeight = init.worldData.minimapHeight; + entry.entry.worldData.iconX = init.worldData.iconX; + entry.entry.worldData.iconY = init.worldData.iconY; + entry.entry.worldData.entranceFlag = init.worldData.entranceFlag; + entry.SetWorldMinimapTexture(init.worldData.minimapTexture); + + return entry; +} + +// Get the SceneDB::Entry for the given scene id. +SceneDB::Entry& SceneDB::RetrieveEntry(const int id) { + static Entry invalid; + if ((id < 0) || (id >= db.size())) { + return invalid; + } + return db[id]; +} + +// Get the id for a given scene by name. +int SceneDB::RetrieveId(const std::string& name) { + auto entry = nameTable.find(name); + if (entry == nameTable.end()) { + return -1; + } + + return entry->second; +} + +// Get the number of scene entries +size_t SceneDB::GetNumEntries() { + return db.size(); +} + +SceneDB::Entry::Entry() { + entry.name = nullptr; + entry.desc = nullptr; + entry.valid = false; + entry.id = 0; + entry.titleCard = nullptr; + entry.sceneDrawConfig = SDC_DEFAULT; + entry.restrictions.hGauge = false; + entry.restrictions.bButton = false; + entry.restrictions.aButton = false; + entry.restrictions.bottles = false; + entry.restrictions.tradeItems = false; + entry.restrictions.hookshot = false; + entry.restrictions.ocarina = false; + entry.restrictions.warpSongs = false; + entry.restrictions.sunsSong = false; + entry.restrictions.farores = false; + entry.restrictions.dinsNayrus = false; + entry.restrictions.all = false; + entry.epona.allowed = false; + entry.epona.startingPos = { 0, 0, 0 }; + entry.epona.spawnPos = {}; + entry.epona.angle = 0; + entry.compassInfo.scaleX = 0; + entry.compassInfo.scaleY = 0; + entry.compassInfo.x = 0; + entry.compassInfo.y = 0; + entry.bossData.mapScene = -1; + entry.dungeonData.bossFloor = -1; + entry.dungeonData.palettes = nullptr; + entry.dungeonData.numPalettes = 0; + for (size_t i = 0; i < 8; i++) { + entry.dungeonData.floors[i].id = static_cast(0); + entry.dungeonData.floors[i].height = 0.0f; + entry.dungeonData.floors[i].rooms = nullptr; + entry.dungeonData.floors[i].numRooms = 0; + entry.dungeonData.floors[i].mapLeftTexture = nullptr; + entry.dungeonData.floors[i].mapRightTexture = nullptr; + } + entry.dungeonData.rooms = nullptr; + entry.dungeonData.numRooms = 0; + entry.dungeonData.intraRoomTransitions = nullptr; + entry.dungeonData.numIntraRoomTransitions = 0; + entry.worldData.minimapX = 0; + entry.worldData.minimapY = 0; + entry.worldData.minimapWidth = 0; + entry.worldData.minimapHeight = 0; + entry.worldData.iconX = 0; + entry.worldData.iconY = 0; + entry.worldData.entranceFlag = 0; + entry.worldData.minimapTexture = nullptr; +} + +SceneDB::Entry::Entry(const Entry& other) { + entry = other.entry; + SetName(other.name); + SetDesc(other.desc); + SetTitleCard(other.titleCard); + SetEponaSpawnPos(other.eponaSpawnPos); + SetDungeonPalettes(other.dungeonPalettes); + SetDungeonNameTextures(other.nameEngTexture, other.nameGerTexture, other.nameFraTexture); + SetDungeonFloors(other.dungeonFloors, other.dungeonFloorInfo); + SetDungeonRooms(other.dungeonRooms, other.dungeonRoomInfo); + SetDungeonIntraRoomTransitions(other.dungeonIntraRoomTransitions); + SetWorldMinimapTexture(other.worldMinimapTexture); +} + +SceneDB::Entry& SceneDB::Entry::operator=(const Entry& other) { + entry = other.entry; + SetName(other.name); + SetDesc(other.desc); + SetTitleCard(other.titleCard); + SetEponaSpawnPos(other.eponaSpawnPos); + SetDungeonPalettes(other.dungeonPalettes); + SetDungeonNameTextures(other.nameEngTexture, other.nameGerTexture, other.nameFraTexture); + SetDungeonFloors(other.dungeonFloors, other.dungeonFloorInfo); + SetDungeonRooms(other.dungeonRooms, other.dungeonRoomInfo); + SetDungeonIntraRoomTransitions(other.dungeonIntraRoomTransitions); + SetWorldMinimapTexture(other.worldMinimapTexture); + return *this; +} + +void SceneDB::Entry::SetName(const std::string& newName) { + name = newName; + entry.name = name.c_str(); +} + +void SceneDB::Entry::SetDesc(const std::string& newDesc) { + desc = newDesc; + entry.desc = desc.c_str(); +} + +void SceneDB::Entry::SetTitleCard(const std::string& newTitleCard) { + titleCard = newTitleCard; + entry.titleCard = titleCard.c_str(); +} + +void SceneDB::Entry::SetEponaSpawnPos(const std::vector& newSpawnPos) { + eponaSpawnPos = newSpawnPos; + entry.epona.spawnPos = eponaSpawnPos.data(); + entry.epona.numSpawns = eponaSpawnPos.size(); +} + +void SceneDB::Entry::SetDungeonPalettes(const std::vector& newDungeonPalettes) { + dungeonPalettes = newDungeonPalettes; + entry.dungeonData.palettes = dungeonPalettes.data(); + entry.dungeonData.numPalettes = dungeonPalettes.size(); +} + +void SceneDB::Entry::SetDungeonNameTextures(const std::string& newNameEngTexture, const std::string& newNameGerTexture, const std::string& newNameFraTexture) { + nameEngTexture = newNameEngTexture; + nameGerTexture = newNameGerTexture; + nameFraTexture = newNameFraTexture; + entry.dungeonData.nameEngTexture = nameEngTexture.c_str(); + entry.dungeonData.nameGerTexture = nameGerTexture.c_str(); + entry.dungeonData.nameFraTexture = nameFraTexture.c_str(); +} + +void SceneDB::Entry::SetDungeonFloors(const std::vector& newDungeonFloors) { + assert(newDungeonFloors.size() == 8 || newDungeonFloors.size() == 0); + + dungeonFloors.clear(); + dungeonFloorInfo.clear(); + + dungeonFloors.reserve(newDungeonFloors.size()); + dungeonFloorInfo.reserve(newDungeonFloors.size()); + + for (size_t i = 0; i < newDungeonFloors.size(); i++) { + dungeonFloors.push_back(SceneDBFloor{ static_cast(newDungeonFloors[i].id), newDungeonFloors[i].height, nullptr, 0, nullptr, nullptr, nullptr, 0, nullptr, 0 }); + dungeonFloorInfo.push_back(FloorInfo{ newDungeonFloors[i].palettes, newDungeonFloors[i].mapLeftTexture, newDungeonFloors[i].mapRightTexture, newDungeonFloors[i].chestMarks, newDungeonFloors[i].bossMarks }); + } + + for (size_t i = 0; i < dungeonFloors.size(); i++) { + dungeonFloors[i].rooms = dungeonFloorInfo[i].rooms.data(); + dungeonFloors[i].numRooms = dungeonFloorInfo[i].rooms.size(); + dungeonFloors[i].mapLeftTexture = dungeonFloorInfo[i].mapLeftTexture.c_str(); + dungeonFloors[i].mapRightTexture = dungeonFloorInfo[i].mapRightTexture.c_str(); + dungeonFloors[i].numChestMarks = dungeonFloorInfo[i].chestMarks.size(); + dungeonFloors[i].chestMarks = dungeonFloorInfo[i].chestMarks.data(); + dungeonFloors[i].numBossMarks = dungeonFloorInfo[i].bossMarks.size(); + dungeonFloors[i].bossMarks = dungeonFloorInfo[i].bossMarks.data(); + } + std::copy(dungeonFloors.begin(), dungeonFloors.end(), entry.dungeonData.floors); +} + +void SceneDB::Entry::SetDungeonFloors(const std::vector& newDungeonFloors, const std::vector& newDungeonFloorInfo) { + assert(newDungeonFloors.size() == 8 || newDungeonFloors.size() == 0); + assert(newDungeonFloorInfo.size() == 8 || newDungeonFloorInfo.size() == 0); + assert(newDungeonFloors.size() == newDungeonFloorInfo.size()); + dungeonFloors = newDungeonFloors; + dungeonFloorInfo = newDungeonFloorInfo; + for (size_t i = 0; i < dungeonFloors.size(); i++) { + dungeonFloors[i].rooms = dungeonFloorInfo[i].rooms.data(); + dungeonFloors[i].numRooms = dungeonFloorInfo[i].rooms.size(); + dungeonFloors[i].mapLeftTexture = dungeonFloorInfo[i].mapLeftTexture.c_str(); + dungeonFloors[i].mapRightTexture = dungeonFloorInfo[i].mapRightTexture.c_str(); + dungeonFloors[i].numChestMarks = dungeonFloorInfo[i].chestMarks.size(); + dungeonFloors[i].chestMarks = dungeonFloorInfo[i].chestMarks.data(); + dungeonFloors[i].numBossMarks = dungeonFloorInfo[i].bossMarks.size(); + dungeonFloors[i].bossMarks = dungeonFloorInfo[i].bossMarks.data(); + } + std::copy(dungeonFloors.begin(), dungeonFloors.end(), entry.dungeonData.floors); +} + +void SceneDB::Entry::SetDungeonRooms(const std::vector& newDungeonRooms) { + dungeonRooms.clear(); + dungeonRoomInfo.clear(); + + dungeonRooms.reserve(newDungeonRooms.size()); + dungeonRoomInfo.reserve(newDungeonRooms.size()); + + for (size_t i = 0; i < newDungeonRooms.size(); i++) { + dungeonRooms.push_back(SceneDBRoom{ newDungeonRooms[i].compassOffsetX, newDungeonRooms[i].compassOffsetY, nullptr, nullptr, 0, nullptr, 0 }); + dungeonRoomInfo.push_back(RoomInfo{ newDungeonRooms[i].minimapTexture, newDungeonRooms[i].chestMarks, newDungeonRooms[i].bossMarks }); + } + + for (size_t i = 0; i < dungeonRooms.size(); i++) { + dungeonRooms[i].minimapTexture = dungeonRoomInfo[i].minimapTexture.c_str(); + dungeonRooms[i].chestMarks = dungeonRoomInfo[i].chestMarks.data(); + dungeonRooms[i].numChestMarks = dungeonRoomInfo[i].chestMarks.size(); + dungeonRooms[i].bossMarks = dungeonRoomInfo[i].bossMarks.data(); + dungeonRooms[i].numBossMarks = dungeonRoomInfo[i].bossMarks.size(); + } + entry.dungeonData.rooms = dungeonRooms.data(); + entry.dungeonData.numRooms = dungeonRooms.size(); +} + +void SceneDB::Entry::SetDungeonRooms(const std::vector& newDungeonRooms, const std::vector& newDungeonRoomInfo) { + dungeonRooms = newDungeonRooms; + dungeonRoomInfo = newDungeonRoomInfo; + for (size_t i = 0; i < dungeonRooms.size(); i++) { + dungeonRooms[i].minimapTexture = dungeonRoomInfo[i].minimapTexture.c_str(); + dungeonRooms[i].chestMarks = dungeonRoomInfo[i].chestMarks.data(); + dungeonRooms[i].numChestMarks = dungeonRoomInfo[i].chestMarks.size(); + dungeonRooms[i].bossMarks = dungeonRoomInfo[i].bossMarks.data(); + dungeonRooms[i].numBossMarks = dungeonRoomInfo[i].bossMarks.size(); + } + entry.dungeonData.rooms = dungeonRooms.data(); + entry.dungeonData.numRooms = dungeonRooms.size(); +} + +void SceneDB::Entry::SetDungeonIntraRoomTransitions(const std::vector& newDungeonIntraRoomTransitions) { + dungeonIntraRoomTransitions.clear(); + + dungeonIntraRoomTransitions.reserve(newDungeonIntraRoomTransitions.size()); + + for (size_t i = 0; i < newDungeonIntraRoomTransitions.size(); i++) { + dungeonIntraRoomTransitions.push_back(SceneDBIntraRoomTransition{ newDungeonIntraRoomTransitions[i].fromRoom, newDungeonIntraRoomTransitions[i].toRoom, newDungeonIntraRoomTransitions[i].toFloor }); + } + entry.dungeonData.intraRoomTransitions = dungeonIntraRoomTransitions.data(); + entry.dungeonData.numIntraRoomTransitions = dungeonIntraRoomTransitions.size(); +} + +void SceneDB::Entry::SetDungeonIntraRoomTransitions(const std::vector& newDungeonIntraRoomTransitions) { + dungeonIntraRoomTransitions = newDungeonIntraRoomTransitions; + entry.dungeonData.intraRoomTransitions = dungeonIntraRoomTransitions.data(); + entry.dungeonData.numIntraRoomTransitions = dungeonIntraRoomTransitions.size(); +} + +void SceneDB::Entry::SetWorldMinimapTexture(const std::string& newWorldMinimapTexture) { + worldMinimapTexture = newWorldMinimapTexture; + entry.worldData.minimapTexture = worldMinimapTexture.empty() ? nullptr : worldMinimapTexture.c_str(); +} + +struct MqMapMarkInit { + struct Room { + std::vector chestMarks; + std::vector bossMarks; + }; + + std::vector rooms; +}; + +std::vector mqMapMarkInit = { + // Deku Tree + { + { + { { { 3, 71, 50 } }, {} }, + { {}, {} }, + { { { 1, 64, 62 } }, {} }, + { { { 4, 76, 37 } }, {} }, + { {}, {} }, + { { { 0, 46, 50 }, { 5, 76, 52 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, { { -1, 50, 23 } } }, + { { { 2, 46, 50 }, { 6, 58, 60 } }, {} }, + { {}, {} }, + { {}, {} } + }, + }, + // Dodongo's Cavern + { + { + { { { 0, 69, 14 }, { 4, 69, 30 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 5, 54, 54 } }, {} }, + { { { 2, 69, 54 } }, {} }, + { {}, { { -1, 37, 49 } } }, + { {}, {} }, + { { { 3, 59, 53 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 68, 54 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + } + }, + // Jabu-Jabu's Belly + { + { + { { { 3, 66, 50 }, { 5, 72, 47 } }, {} }, + { { { 7, 72, 54 } }, {} }, + { {}, {} }, + { { { 4, 64, 62 }, { 8, 79, 38 } }, {} }, + { {}, {} }, + { { { 10, 64, 45 } }, { { -1, 67, 32 } } }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 9, 68, 45 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 79, 33 }, { 6, 61, 41 } }, {} }, + { { { 0, 48, 57 }, { 2, 77, 55 } }, {} }, + // Jabu-Jabu's Belly minimap 16 + // SoH [General] - This entry corresponds to Big Octorok's room and is missing in the MQ game + // N64 hardware does an OoB read and lands on MQ Forest Temple room 0 + // To avoid UB with OoB for SoH, the correct entry is now added below + { {}, {} }, + } + }, + // Forest Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 0, 72, 57 } }, {} }, + { { { 1, 69, 39 }, { 9, 62, 65 } }, {} }, + { {}, {} }, + { { { 9, 71, 59 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 13, 80, 53 } }, {} }, + { { { 15, 49, 50 } }, {} }, + { {}, {} }, + { { { 6, 65, 53 } }, {} }, + { {}, {} }, + { { { 11, 39, 35 } }, { { -1, 53, 5 } } }, + { { { 2, 65, 54 } }, {} }, + { { { 14, 64, 31 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 3, 75, 53 } }, {} }, + { { { 12, 69, 52 } }, {} }, + { { { 5, 58, 27 } }, {} }, + { {}, {} }, + { {}, {} }, + } + }, + // Fire Temple + { + { + { {}, {} }, + { {}, {} }, + { { { 7, 53, 70 } }, { { -1, 40, 47 } } }, + { {}, {} }, + { { { 11, 57, 48 } }, {} }, + { { { 3, 67, 73 }, { 6, 58, 76 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 78, 62 }, { 12, 77, 58 } }, {} }, + { {}, {} }, + { { { 4, 60, 54 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 72, 68 } }, {} }, + { { { 8, 66, 57 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 5, 51, 61 } }, {} }, + { {}, {} }, + { {}, {} }, + } + }, + // Water Temple + { + { + { {}, {} }, + { {}, {} }, + { { { 6, 81, 68 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 5, 75, 55 } }, {} }, + { {}, {} }, + { {}, { { -1, 77, 40 } } }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 74, 61 } }, {} }, + { { { 2, 73, 65 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 0, 73, 63 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + } + }, + // Spirit Temple + { + { + { { { 26, 27, 35 }, { 27, 36, 35 }, { 30, 27, 28 }, { 31, 36, 28 } }, {} }, + { { { 29, 67, 63 } }, {} }, + { {}, {} }, + { { { 0, 71, 62 }, { 8, 71, 48 } }, {} }, + { {}, {} }, + { { { 3, 56, 54 }, { 15, 69, 42 } }, {} }, + { { { 28, 60, 54 } }, {} }, + { {}, {} }, + { { { 1, 76, 40 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 7, 70, 53 } }, {} }, + { {}, {} }, + { { { 4, 68, 42 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 25, 78, 58 } }, {} }, + { { { 24, 78, 58 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 5, 71, 55 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 18, 75, 54 } }, {} }, + { {}, {} }, + { { { 6, 78, 55 }, { 12, 70, 70 } }, {} }, + { { { 2, 76, 37 } }, { { -1, 57, 23 } } }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + } + }, + // Shadow Temple + { + { + { {}, {} }, + { { { 1, 77, 64 } }, {} }, + { {}, {} }, + { {}, { { -1, 77, 76 } } }, + { { { 7, 76, 65 } }, {} }, + { {}, {} }, + { { { 2, 83, 67 }, { 14, 84, 59 } }, {} }, + { { { 3, 76, 67 } }, {} }, + { {}, {} }, + { {}, {} }, + { { { 4, 78, 62 }, { 5, 74, 62 }, { 6, 71, 68 } }, {} }, + { { { 9, 77, 64 } }, {} }, + { {}, {} }, + { { { 10, 71, 65 }, { 11, 80, 65 } }, {} }, + { { { 16, 73, 64 } }, {} }, + { {}, {} }, + { { { 12, 87, 64 }, { 22, 87, 68 } }, {} }, + { { { 13, 77, 66 } }, {} }, + { {}, {} }, + { { { 21, 78, 66 } }, {} }, + { { { 8, 76, 66 }, { 20, 78, 68 } }, {} }, + { { { 14, 77, 62 } }, {} }, + { {}, {} }, + { { { 15, 56, 67 } }, {} }, + { {}, {} }, + { { { 16, 73, 64 } }, {} }, + { { { 14, 77, 62 } }, {} }, + } + }, + // Bottom of the Well + { + { + { { { 3, 60, 18 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 73, 61 } }, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 74, 66 } }, {} }, + } + }, + // Ice Cavern + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 71, 59 } }, {} }, + { {}, {} }, + { { { 0, 48, 36 } }, {} }, + { {}, {} }, + { { { 1, 73, 67 } }, {} }, + } + }, +}; + +// Sets a scene's dungeon map marks based on whether it should be MQ or not +void SceneDB::Entry::SetMapMarkData(const bool isMQ) { + if (isMQ) { + if (this->entry.id >= SCENE_DEKU_TREE && this->entry.id <= SCENE_ICE_CAVERN) { + s32 dungeonNum = this->entry.id - SCENE_DEKU_TREE; + for (size_t i = 0; i < mqMapMarkInit[dungeonNum].rooms.size(); i++) { + dungeonRoomInfo[i].chestMarks = mqMapMarkInit[dungeonNum].rooms[i].chestMarks; + dungeonRoomInfo[i].bossMarks = mqMapMarkInit[dungeonNum].rooms[i].bossMarks; + + dungeonRooms[i].chestMarks = dungeonRoomInfo[i].chestMarks.data(); + dungeonRooms[i].numChestMarks = dungeonRoomInfo[i].chestMarks.size(); + dungeonRooms[i].bossMarks = dungeonRoomInfo[i].bossMarks.data(); + dungeonRooms[i].numBossMarks = dungeonRoomInfo[i].bossMarks.size(); + } + } + } else { + SetDungeonRooms(sceneDBInit[this->entry.id].dungeonData.rooms); + } +} + +struct MqPauseMapMarkInit { + struct Floor { + std::vector chestMarks; + std::vector bossMarks; + }; + + Floor floors[8]; +}; + +std::vector mqPauseMapMarkInit = +{ + // Deku Tree + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 40.0f, -33.0f }, { 6, 49.0f, -42.0f } }, {} }, // 3F + { { { 1, 48.0f, -63.0f } }, {} }, // 2F + { { { 3, 84.0f, -39.0f } }, {} }, // 1F + { { { 0, 46.0f, -59.0f }, { 4, 77.0f, -26.0f }, { 5, 65.0f, -61.0f } }, {} }, // B1 + { {}, { { -1, 55.0f, 0.0f } } }, // B2 + } + }, + // Dodongo's Cavern + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 55.0f, -36.0f }, { 3, 54.0f, -51.0f }, { 5, 13.0f, -61.0f } }, {} }, // 2F + { { { 0, 47.0f, -40.0f }, { 1, 51.0f, -3.0f }, { 4, 47.0f, -47.0f } }, { { -1, 23.0f, -25.0f } } }, // 1F + } + }, + // Jabu-Jabu's Belly + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 3, 48.0f, -68.0f }, { 5, 50.0f, -66.0f }, { 7, 55.0f, -50.0f }, { 9, 58.0f, 1.0f }, { 10, 62.0f, -45.0f } }, { { -1, 65.0f, -37.0f } } }, // 1F + { { { 0, 37.0f, -49.0f }, { 1, 65.0f, -38.0f }, { 2, 52.0f, -48.0f }, { 4, 46.0f, -36.0f }, { 6, 59.0f, -41.0f }, { 8, 52.0f, -26.0f } }, {} }, // B1 + } + }, + // Forest Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 3, 53.0f, -64.0f }, { 5, 65.0f, -9.0f }, { 12, 49.0f, -1.0f }, { 13, 40.0f, 0.0f }, { 14, 18.0f, -2.0f }, { 15, 59.0f, 0.0f } }, {} }, // 2F + { { { 0, 49.0f, -1.0f }, { 1, 71.0f, -13.0f }, { 2, 11.0f, -25.0f }, { 6, 84.0f, -16.0f } }, {} }, // 1F + { { { 9, 65.0f, -30.0f } }, {} }, // B1 + { { { 11, 41.0f, -24.0f } }, { { -1, 50.0f, -11.0f } } }, // B2 + } + }, + // Fire Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 5, 24.0f, -40.0f } }, {} }, // 5F + { {}, {} }, // 4F + { { { 3, 75.0f, -47.0f }, { 6, 72.0f, -51.0f }, { 8, 65.0f, -12.0f } }, {} }, // 3F + { { { 11, 78.0f, -35.0f } }, {} }, // 2F + { { { 1, 67.0f, -58.0f }, { 2, 48.0f, -30.0f }, { 4, 63.0f, -14.0f }, { 7, 36.0f, -45.0f }, { 12, 47.0f, -26.0f } }, { { -1, 26.0f, -34.0f } } }, // 1F + } + }, + // Water Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 88.0f, -60.0f } }, { { -1, 62.0f, -23.0f } } }, // 3F + { { { 0, 88.0f, -60.0f } }, {} }, // 2F + { { { 1, 88.0f, -60.0f }, { 5, 49.0f, -43.0f } }, {} }, // 1F + { { { 6, 75.0f, -65.0f } }, {} }, // B1 + } + }, + // Spirit Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 18, 46.0f, -30.0f } }, {} }, // 4F + { { { 1, 23.0f, -33.0f }, { 2, 56.0f, -11.0f }, { 5, 83.0f, -25.0f }, { 24, 84.0f, -39.0f }, { 25, 74.0f, -37.0f } }, { { -1, 47.0f, 0.0f } } }, // 3F + { { { 3, 46.0f, -20.0f }, { 6, 28.0f, -19.0f }, { 12, 25.0f, -25.0f }, { 15, 50.0f, -13.0f }, { 28, 48.0f, -29.0f } }, {} }, // 2F + { { { 0, 14.0f, -24.0f }, { 4, 55.0f, -14.0f }, { 7, 78.0f, -2.0f }, { 8, 14.0f, -16.0f }, { 26, 42.0f, -43.0f }, { 27, 50.0f, -43.0f }, { 29, 25.0f, -35.0f }, { 30, 42.0f, -36.0f }, { 31, 50.0f, -36.0f } }, {} }, // 1F + } + }, + // Shadow Temple + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 1, 41.0f, -17.0f }, { 7, 27.0f, -24.0f } }, {} }, // B1 + { { { 2, 81.0f, -20.0f }, { 3, 74.0f, -37.0f } }, {} }, // B2 + { { { 12, 96.0f, -51.0f }, { 16, 46.0f, -42.0f }, { 22, 96.0f, -55.0f } }, {} }, // B3 + { { { 4, 43.0f, -66.0f }, { 5, 37.0f, -66.0f }, { 6, 33.0f, -72.0f }, { 8, 85.0f, -18.0f }, { 9, 61.0f, -42.0f }, { 10, 15.0f, -4.0f }, { 11, 25.0f, -4.0f }, { 13, 19.0f, -29.0f }, { 14, 78.0f, -15.0f }, { 15, 60.0f, -70.0f }, { 21, 92.0f, -29.0f }, { 20, 87.0f, -20.0f } }, { { -1, 31.0f, -45.0f } } }, // B4 + } + }, + // Bottom of the Well + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 2, 84.0f, -38.0f }, { 3, 57.0f, -18.0f } }, {} }, // B1 + { {}, {} }, // B2 + { { { 1, 72.0f, -32.0f } }, {} }, // B3 + } + }, + // Ice Cavern + { + { + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { {}, {} }, + { { { 0, 66.0f, -2.0f }, { 1, 77.0f, -46.0f }, { 2, 27.0f, -45.0f } }, {} }, // 1F + } + }, +}; + +// Sets a scene's pause map marks based on whether it should be MQ or not +void SceneDB::Entry::SetPauseMapMarkData(const bool isMQ) { + if (isMQ) { + if (this->entry.id >= SCENE_DEKU_TREE && this->entry.id <= SCENE_ICE_CAVERN) { + s32 dungeonNum = this->entry.id - SCENE_DEKU_TREE; + for (size_t i = 0; i < 8; i++) { + dungeonFloorInfo[i].chestMarks = mqPauseMapMarkInit[dungeonNum].floors[i].chestMarks; + dungeonFloorInfo[i].bossMarks = mqPauseMapMarkInit[dungeonNum].floors[i].bossMarks; + + dungeonFloors[i].numChestMarks = dungeonFloorInfo[i].chestMarks.size(); + dungeonFloors[i].chestMarks = dungeonFloorInfo[i].chestMarks.data(); + dungeonFloors[i].numBossMarks = dungeonFloorInfo[i].bossMarks.size(); + dungeonFloors[i].bossMarks = dungeonFloorInfo[i].bossMarks.data(); + } + } + } else { + SetDungeonFloors(sceneDBInit[this->entry.id].dungeonData.floors); + } +} + +// Returns is a scene is a boss scene +// A scene is a boss scene if it has the scene in the bossData is != -1 +bool SceneDB::Entry::isBoss() { + return SCENEDB_ISBOSS(&this->entry); +} + +// Returns is a scene is a boss dungeon +// A scene is a dungeon scene if it's number of rooms is != 0 +bool SceneDB::Entry::isDungeon() { + return SCENEDB_ISDUNGEON(&this->entry); +} + +// Returns is a scene is a overworld scene +// A scene is a world scene if it has a texture for a world minimap +bool SceneDB::Entry::isOverworld() { + return SCENEDB_ISOVERWORLD(&this->entry); +} + + +EntranceDB::EntranceDB() { + db.reserve(ENTR_MAX); // reserve size for all initial entries so we don't do it for each + for (const EntranceTableInit& init : entranceDBInit) { + Init nativeInit{ + init.name, + init.desc, + SceneDB::Instance->RetrieveEntry(init.scene).name, + init.spawn, + init.continueBgm, + init.displayTitleCard, + init.endTransition, + init.startTransition + }; + + AddEntry(nativeInit); + } +} + +EntranceDB::Entry& EntranceDB::AddEntry(const Init& init) { + Entry& entry = AddEntry(init.name, init.desc, nextFreeId); + // TODO handle errors + entry.entry.sceneId = SceneDB::Instance->RetrieveEntry(SceneDB::Instance->RetrieveId(init.scene)).entry.id; + entry.entry.spawn = init.spawn; + entry.entry.continueBgm = init.continueBgm; + entry.entry.displayTitleCard = init.displayTitleCard; + entry.entry.endTransition = init.endTransition; + entry.entry.startTransition = init.startTransition; + + // Add this entrance to the list of layers for the scene and spawn + NextLayerLookupKey nextLayerKey{ entry.entry.sceneId, entry.entry.spawn }; + auto nextLayer = nextLayerLookupTable.find(nextLayerKey); + if (nextLayer == nextLayerLookupTable.end()) { + entry.entry.layer = 0; + nextLayerLookupTable.insert({ nextLayerKey, 1 }); + } else { + entry.entry.layer = nextLayer->second++; + } + + // Add the entrance to the lookup of scene, spawn, and layer -> base scene + idLookupTable.insert({ { entry.entry.sceneId, entry.entry.spawn, entry.entry.layer }, entry.entry.id }); + + return entry; +} + +EntranceDB::Entry& EntranceDB::RetrieveEntry(const int id) { + static Entry invalid; + if ((id < 0) || (id >= db.size())) { + return invalid; + } + return db[id]; +} + +EntranceDB::Entry& EntranceDB::RetrieveEntry(const int id, const int layer) { + Entry& entry = RetrieveEntry(id); + Entry& ret = RetrieveEntry(CalcId(entry.entry.sceneId, entry.entry.spawn, layer)); + assert(ret.entry.valid); + return ret; +} + +int EntranceDB::RetrieveId(const std::string& name) { + auto entry = nameTable.find(name); + if (entry == nameTable.end()) { + return -1; + } + + return entry->second; +} + +size_t EntranceDB::GetNumEntries() { + return db.size(); +} + +s32 EntranceDB::CalcId(const s32 sceneId, const s32 spawn, const s32 layer) { + auto entrance = idLookupTable.find({ sceneId, spawn, layer }); + + // If the entrance does not exist, assume it is a wrong warp + // TODO WW CVar to force error for mod debugging + if (entrance == idLookupTable.end()) { + auto wwEntrance = idLookupTable.find({ sceneId, spawn, 0 }); + // We need to make sure that at least the scene and spawn are correct, it's just the layer which is an OOB + assert(wwEntrance != idLookupTable.end()); + return wwEntrance->second + layer; + } + + return entrance->second; +} + +s32 EntranceDB::CalcId(const s32 entrance, const s32 newLayer) { + Entry& entry = RetrieveEntry(entrance); + auto newEntrance = idLookupTable.find({ entry.entry.sceneId, entry.entry.spawn, newLayer }); + + // If the entrance does not exist, assume it is a wrong warp + // TODO WW CVar to force error for mod debugging + if (newEntrance == idLookupTable.end()) { + auto wwEntrance = idLookupTable.find({ entry.entry.sceneId, entry.entry.spawn, 0 }); + // We need to make sure that at least the scene and spawn are correct, it's just the layer which is an OOB + assert(wwEntrance != idLookupTable.end()); + return wwEntrance->second + newLayer; + } + + return newEntrance->second; +} + +// Resets all vanilla entrances (mostly to restore all modifications rando makes) +void EntranceDB::ResetVanillaEntrances() { + // Erase all instances of vanilla entrances in the lookup tables + for (size_t i = 0; i < ENTR_MAX; i++) { + // For this entrance, reset the next layer. This will cause problems with mods that add a new layer (like for a cutscene) + // However, we will treat this as fine for now because we don't have such mods + // A more robust solution is to use a local nextLayerLookupTable to reestablish the vanilla layers + NextLayerLookupKey nextLayerKey{ entranceDBInit[i].scene, entranceDBInit[i].spawn }; + nextLayerLookupTable.erase(nextLayerKey); + + for (auto iter = idLookupTable.begin(); iter != idLookupTable.end();) { + if (iter->second == i) { + idLookupTable.erase(iter++); + } else { + iter++; + } + } + } + + for (size_t i = 0; i < ENTR_MAX; i++) { + // This entrance should already exist. Look it up and set its values to vanilla + Entry& entry = RetrieveEntry(i); + const EntranceTableInit& init = entranceDBInit[i]; + + entry.entry.sceneId = SceneDB::Instance->RetrieveEntry(init.scene).entry.id; + entry.entry.spawn = init.spawn; + entry.entry.continueBgm = init.continueBgm; + entry.entry.displayTitleCard = init.displayTitleCard; + entry.entry.endTransition = init.endTransition; + entry.entry.startTransition = init.startTransition; + + // Add this entrance to the list of layers for the scene and spawn + NextLayerLookupKey nextLayerKey{ entry.entry.sceneId, entry.entry.spawn }; + auto nextLayer = nextLayerLookupTable.find(nextLayerKey); + if (nextLayer == nextLayerLookupTable.end()) { + entry.entry.layer = 0; + nextLayerLookupTable.insert({ nextLayerKey, 1 }); + } else { + entry.entry.layer = nextLayer->second++; + } + + // Add the entrance to the lookup + idLookupTable.insert({ { entry.entry.sceneId, entry.entry.spawn, entry.entry.layer }, entry.entry.id }); + } +} + +// Copies an entrance. Needed by rando when making changes to the scene, spawn, or layer +void EntranceDB::Copy(s32 from, s32 to) { + Entry& entryFrom = RetrieveEntry(from); + Entry& entryTo = RetrieveEntry(to); + + // Remove entrance that is about to be overridden + for (auto iter = idLookupTable.begin(); iter != idLookupTable.end();) { + if (iter->second == to) { + idLookupTable.erase(iter++); + } else { + iter++; + } + } + + // Add a lookup so that the overridden entrance returns the new one + idLookupTable.insert({ { entryTo.entry.sceneId, entryTo.entry.spawn, entryTo.entry.layer }, entryFrom.entry.id }); + + // Replace the entrance + entryTo.entry.sceneId = entryFrom.entry.sceneId; + entryTo.entry.spawn = entryFrom.entry.spawn; + entryTo.entry.layer = entryFrom.entry.layer; + entryTo.entry.continueBgm = entryFrom.entry.continueBgm; + entryTo.entry.displayTitleCard = entryFrom.entry.displayTitleCard; + entryTo.entry.endTransition = entryFrom.entry.endTransition; + entryTo.entry.startTransition = entryFrom.entry.startTransition; +} + +EntranceDB::Entry& EntranceDB::AddEntry(const std::string& name, const std::string& desc, size_t index) { + assert(!nameTable.contains(name)); // TODO this should maybe throw instead. We'll need to think about error handling + // for mods that try to declare the same entrance. + + if (db.size() < (index + 1)) { + db.resize(index + 1); + } + Entry& newEntry = db.at(index); + newEntry.entry.id = index; + + assert(!newEntry.entry.valid); + + nextFreeId = std::max(nextFreeId, index + 1); + + nameTable[name] = newEntry.entry.id; + newEntry.SetName(name); + newEntry.SetDesc(desc); + + newEntry.entry.valid = true; + + return newEntry; +} + +EntranceDB::Entry::Entry() { + entry.name = nullptr; + entry.desc = nullptr; + entry.valid = false; + entry.id = 0; + entry.sceneId = 0; + entry.spawn = 0; + entry.layer = 0; + entry.continueBgm = false; + entry.displayTitleCard = false; + entry.endTransition = 0; + entry.startTransition = 0; +} + +EntranceDB::Entry::Entry(const Entry& other) { + entry = other.entry; + SetName(other.name); + SetDesc(other.desc); +} + +EntranceDB::Entry& EntranceDB::Entry::operator=(const Entry& other) { + entry = other.entry; + SetName(other.name); + SetDesc(other.desc); + return *this; +} + +void EntranceDB::Entry::SetName(const std::string& newName) { + name = newName; + entry.name = name.c_str(); +} + +void EntranceDB::Entry::SetDesc(const std::string& newDesc) { + desc = newDesc; + entry.desc = desc.c_str(); +} + +extern "C" SceneDBEntry* SceneDB_Retrieve(const int id) { + return &SceneDB::Instance->RetrieveEntry(id).entry; +} + +extern "C" int SceneDB_RetrieveId(const char* name) { + return SceneDB::Instance->RetrieveId(name); +} + +extern "C" int SceneDB_IsBoss(const int id) { + return SceneDB::Instance->RetrieveEntry(id).isBoss(); +} + +extern "C" int SceneDB_IsDungeon(const int id) { + return SceneDB::Instance->RetrieveEntry(id).isDungeon(); +} + +extern "C" int SceneDB_IsOverworld(const int id) { + return SceneDB::Instance->RetrieveEntry(id).isOverworld(); +} + +extern "C" void SceneDB_SetMapMarkData(const int id, const int isMQ) { + SceneDB::Instance->RetrieveEntry(id).SetMapMarkData(isMQ); +} + +extern "C" void SceneDB_SetPauseMapMarkData(const int id, const int isMQ) { + SceneDB::Instance->RetrieveEntry(id).SetPauseMapMarkData(isMQ); +} + +extern "C" EntranceDBEntry* EntranceDB_Retrieve(const int id) { + return &EntranceDB::Instance->RetrieveEntry(id).entry; +} + +extern "C" EntranceDBEntry* EntranceDB_RetrieveLayer(const int id, const int layer) { + return &EntranceDB::Instance->RetrieveEntry(id, layer).entry; +} + +extern "C" int EntranceDB_RetrieveId(const char* name) { + return EntranceDB::Instance->RetrieveId(name); +} + +extern "C" int EntranceDB_CalcId(const int sceneId, const int spawn, const int layer) { + return EntranceDB::Instance->CalcId(sceneId, spawn, layer); +} + +extern "C" int EntranceDB_CalcIdWithEntrance(const int entrance, const int newLayer) { + return EntranceDB::Instance->CalcId(entrance, newLayer); +} + +extern "C" void EntranceDB_ResetVanillaEntrances(void) { + return EntranceDB::Instance->ResetVanillaEntrances(); +} + +extern "C" void EntranceDB_Copy(const int from, const int to) { + return EntranceDB::Instance->Copy(from, to); +} diff --git a/soh/soh/SceneDB.h b/soh/soh/SceneDB.h new file mode 100644 index 00000000000..9480ff907de --- /dev/null +++ b/soh/soh/SceneDB.h @@ -0,0 +1,367 @@ +#pragma once +#include +#include "z64scene.h" +#include "z64.h" + +typedef struct { + FloorID id; + f32 height; + s8* rooms; + u32 numRooms; + const char* mapLeftTexture; + const char* mapRightTexture; + PauseMapMarkPoint* chestMarks; + u32 numChestMarks; + PauseMapMarkPoint* bossMarks; + u32 numBossMarks; +} SceneDBFloor; + +typedef struct { + s16 compassOffsetX; + s16 compassOffsetY; + const char* minimapTexture; + MapMarkPoint* chestMarks; + u32 numChestMarks; + MapMarkPoint* bossMarks; + u32 numBossMarks; +} SceneDBRoom; + +typedef struct { + u8 fromRoom; + u8 toRoom; + u8 toFloor; +} SceneDBIntraRoomTransition; + +typedef struct { + const char* name; + const char* desc; + u32 valid; + s32 id; + const char* titleCard; + SceneDrawConfig sceneDrawConfig; + struct { + u8 hGauge; + u8 bButton; + u8 aButton; + u8 bottles; + u8 tradeItems; + u8 hookshot; + u8 ocarina; + u8 warpSongs; + u8 sunsSong; + u8 farores; + u8 dinsNayrus; + u8 all; + } restrictions; + struct { + u32 allowed; + Vec3s startingPos; + s16 angle; + Vec3s* spawnPos; + u32 numSpawns; + } epona; + struct { + s16 scaleX; + s16 scaleY; + s16 x; + s16 y; + } compassInfo; + struct { + s32 mapScene; + } bossData; + struct { + s32 bossFloor; + s16* palettes; + u32 numPalettes; + const char* nameEngTexture; + const char* nameGerTexture; + const char* nameFraTexture; + SceneDBFloor floors[8]; + SceneDBRoom* rooms; + u32 numRooms; + SceneDBIntraRoomTransition* intraRoomTransitions; + u32 numIntraRoomTransitions; + } dungeonData; + struct { + s16 minimapX; + s16 minimapY; + s16 minimapWidth; + s16 minimapHeight; + s16 iconX; + s16 iconY; + s16 entranceFlag; + const char* minimapTexture; + } worldData; +} SceneDBEntry; + +typedef struct { + const char* name; + const char* desc; + u32 valid; + s32 id; + s32 sceneId; + s32 spawn; + s32 layer; + u8 continueBgm; + u8 displayTitleCard; + u8 endTransition; + u8 startTransition; +} EntranceDBEntry; + +#define SCENEDB_ISBOSS(entry) ((entry)->bossData.mapScene != -1) +#define SCENEDB_ISDUNGEON(entry) ((entry)->dungeonData.numRooms != 0) +#define SCENEDB_ISOVERWORLD(entry) ((entry)->worldData.minimapTexture != NULL) + +#ifdef __cplusplus + +#include +#include +#include +#include + +class SceneDB { +public: + static SceneDB* Instance; + + struct Init { + struct FloorInit { + FloorID id = F_NA; + f32 height = 9999.0f; + std::vector palettes; + std::string mapLeftTexture; + std::string mapRightTexture; + std::vector chestMarks; + std::vector bossMarks; + }; + + struct RoomInit { + s16 compassOffsetX = 0; + s16 compassOffsetY = 0; + std::string minimapTexture; + std::vector chestMarks; + std::vector bossMarks; + }; + + struct IntraRoomTransitionInit { + u8 fromRoom = 0xFF; + u8 toRoom = 0xFF; + u8 toFloor = 0xFF; + }; + + std::string name; + std::string desc; + std::string titleCard; + SceneDrawConfig sceneDrawConfig = SDC_DEFAULT; + struct { + bool hGauge = false; + bool bButton = false; + bool aButton = false; + bool bottles = false; + bool tradeItems = false; + bool hookshot = false; + bool ocarina = false; + bool warpSongs = false; + bool sunsSong = false; + bool farores = false; + bool dinsNayrus = false; + bool all = false; + } restrictions; + struct { + bool allowed = false; + Vec3s startingPos = { 0, 0, 0 }; + s16 angle = 0; + std::vector spawnPos; + } epona; + struct { + s16 scaleX = 0; + s16 scaleY = 0; + s16 x = 0; + s16 y = 0; + } compassInfo; + struct { + std::string mapScene; + } bossData; + struct { + s32 bossFloor = -1; + std::vector palettes; + std::string nameEngTexture; + std::string nameGerTexture; + std::string nameFraTexture; + std::vector floors; + std::vector rooms; + std::vector intraRoomTransitions; + } dungeonData; + struct { + s16 minimapX = 0; + s16 minimapY = 0; + s16 minimapWidth = 0; + s16 minimapHeight = 0; + s16 iconX = 0; + s16 iconY = 0; + s16 entranceFlag = -1; + std::string minimapTexture; + } worldData; + }; + + SceneDB(); + + // Wrapper around SceneDBEntry so we get C++isms for the entries + struct Entry { + Entry(); + Entry(const Entry& other); + Entry& operator=(const Entry& other); + + struct FloorInfo { + std::vector rooms; + std::string mapLeftTexture; + std::string mapRightTexture; + std::vector chestMarks; + std::vector bossMarks; + }; + + struct RoomInfo { + std::string minimapTexture; + std::vector chestMarks; + std::vector bossMarks; + }; + + void SetName(const std::string& newName); + void SetDesc(const std::string& newDesc); + void SetTitleCard(const std::string& newTitleCard); + void SetEponaSpawnPos(const std::vector& newSpawnPos); + void SetDungeonPalettes(const std::vector& newDungeonPalettes); + void SetDungeonNameTextures(const std::string& newNameEngTexture, const std::string& newNameGerTexture, const std::string& newNameFraTexture); + void SetDungeonFloors(const std::vector& newDungeonFloors); + void SetDungeonFloors(const std::vector& newDungeonFloors, const std::vector& newDungeonFloorInfo); + void SetDungeonRooms(const std::vector& newDungeonRooms); + void SetDungeonRooms(const std::vector& newDungeonRooms, const std::vector& newDungeonRoomInfo); + void SetDungeonIntraRoomTransitions(const std::vector& newDungeonIntraRoomTransitions); + void SetDungeonIntraRoomTransitions(const std::vector& newDungeonIntraRoomTransitions); + void SetWorldMinimapTexture(const std::string& newWorldMinimapTexture); + void SetMapMarkData(const bool isMQ); + void SetPauseMapMarkData(const bool isMQ); + + bool isBoss(); + bool isDungeon(); + bool isOverworld(); + + std::string name; + std::string desc; + std::string titleCard; + std::vector eponaSpawnPos; + std::vector dungeonPalettes; + std::string nameEngTexture; + std::string nameGerTexture; + std::string nameFraTexture; + std::vector dungeonFloorInfo; + std::vector dungeonFloors; + std::vector dungeonRoomInfo; + std::vector dungeonRooms; + std::vector dungeonIntraRoomTransitions; + std::string worldMinimapTexture; + SceneDBEntry entry; + }; + Entry& AddEntry(const Init& init); + + Entry& RetrieveEntry(const int id); + int RetrieveId(const std::string& name); + + size_t GetNumEntries(); + +private: + Entry& AddEntry(const std::string& name, const std::string& desc, size_t index); + + std::vector db; + std::unordered_map nameTable; + size_t nextFreeId = 0; +}; + +class EntranceDB { +public: + static EntranceDB* Instance; + + struct Init { + std::string name; + std::string desc; + std::string scene; + s32 spawn; + bool continueBgm; + bool displayTitleCard; + u8 endTransition; + u8 startTransition; + }; + + EntranceDB(); + + // Wrapper around EntranceDBEntry so we get C++isms for the entries + struct Entry { + Entry(); + Entry(const Entry& other); + Entry& operator=(const Entry& other); + + void SetName(const std::string& newName); + void SetDesc(const std::string& newDesc); + + std::string name; + std::string desc; + EntranceDBEntry entry; + }; + Entry& AddEntry(const Init& init); + + void ResetVanillaEntrances(); + + Entry& RetrieveEntry(const int id); + Entry& RetrieveEntry(const int id, const int layer); + int RetrieveId(const std::string& name); + + size_t GetNumEntries(); + + s32 CalcId(s32 sceneId, s32 spawn, s32 layer); + s32 CalcId(s32 entrance, s32 newLayer); + + void Copy(s32 from, s32 to); +private: + Entry& AddEntry(const std::string& name, const std::string& desc, size_t index); + + std::vector db; + std::unordered_map nameTable; + size_t nextFreeId = 0; + + // This keeps a mapping of a scene, spawn, and layer to the resulting entrance ID, since we can assume no order about them + struct IdLookupKey { + s32 sceneId; + s32 spawn; + s32 layer; + auto operator<=>(const IdLookupKey&) const = default; + }; + std::map idLookupTable; + + // This keeps a mapping of a scene and spawn to the next avaliable layer + // When loading mods that add cutscenes, this will tell us the layer that cutscene's entrance is assigned + struct NextLayerLookupKey { + s32 sceneId; + s32 spawn; + auto operator<=>(const NextLayerLookupKey&) const = default; + }; + std::map nextLayerLookupTable; +}; + +#else + +SceneDBEntry* SceneDB_Retrieve(const int id); +int SceneDB_RetrieveId(const char* name); +int SceneDB_IsBoss(const int id); +int SceneDB_IsDungeon(const int id); +int SceneDB_IsOverworld(const int id); +void SceneDB_SetMapMarkData(const int id, const int isMQ); +void SceneDB_SetPauseMapMarkData(const int id, const int isMQ); + +EntranceDBEntry* EntranceDB_Retrieve(const int id); +EntranceDBEntry* EntranceDB_RetrieveLayer(const int id, const int layer); +int EntranceDB_RetrieveId(const char* name); +int EntranceDB_CalcId(const int sceneId, const int spawn, const int layer); +int EntranceDB_CalcIdWithEntrance(const int entrance, const int newLayer); +void EntranceDB_ResetVanillaEntrances(void); +void EntranceDB_Copy(const int from, const int to); + +#endif \ No newline at end of file diff --git a/soh/soh/SceneDB_Table.cpp b/soh/soh/SceneDB_Table.cpp new file mode 100644 index 00000000000..9c67a4f77b0 --- /dev/null +++ b/soh/soh/SceneDB_Table.cpp @@ -0,0 +1,1912 @@ +#include "SceneDB.h" + +#include "textures/map_48x85_static/map_48x85_static.h" +#include "textures/map_i_static/map_i_static.h" +#include "textures/icon_item_nes_static/icon_item_nes_static.h" +#include "textures/icon_item_ger_static/icon_item_ger_static.h" +#include "textures/icon_item_fra_static/icon_item_fra_static.h" +#include "textures/map_grand_static/map_grand_static.h" + +#include + +extern const std::vector sceneDBInit{ + { // SCENE_DEKU_TREE + "ydan_scene", + "Inside the Deku Tree", + "g_pn_06", + SDC_DEKU_TREE, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 3, 3, 1070, -690 }, + {}, + { + 7, + { 10, 1, 2, 10, 4, 5, 6, 7, 8, 10, 11 }, + std::string{gPauseDekuTitleENGTex}, + std::string{gPauseDekuTitleGERTex}, + std::string{gPauseDekuTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_3F, 760.0f, { 0, 10, }, std::string{gDekuTreePauseScreenMapFloor3LeftTex}, std::string{gDekuTreePauseScreenMapFloor3RightTex}, { { 2, 40.0f, -33.0f }, { 6, 49.0f, -42.0f } }, {}, }, + { F_2F, 360.0f, { 0, 1, 2, }, std::string{gDekuTreePauseScreenMapFloor2LeftTex}, std::string{gDekuTreePauseScreenMapFloor2RightTex}, { { 1, 48.0f, -63.0f }, { 5, 52.0f, -68.0f } }, {}, }, + { F_1F, -40.0f, { 0, }, std::string{gDekuTreePauseScreenMapFloor1LeftTex}, std::string{gDekuTreePauseScreenMapFloor1RightTex}, { { 3, 84.0f, -39.0f } }, {}, }, + { F_B1, -1000.0f, { 3, 4, 5, 6, 7, 8, }, std::string{gDekuTreePauseScreenMapBasement1LeftTex}, std::string{gDekuTreePauseScreenMapBasement1RightTex}, { { 4, 77.0f, -26.0f } }, {}, }, + { F_B2, -2000.0f, { 9, }, std::string{gDekuTreePauseScreenMapBasement2LeftTex}, std::string{gDekuTreePauseScreenMapBasement2RightTex}, {}, { { -1, 55.0f, 0.0f } }, }, + }, + { + { 1090, -660, std::string{gDekuTreeRoom0Floor1MinimapTex}, { { 3, 71, 50 }, }, {} }, + { 1390, -570, std::string{gDekuTreeRoom1MinimapTex}, {}, {} }, + { 1560, -410, std::string{gDekuTreeRoom2MinimapTex}, { { 1, 64, 62 }, { 5, 71, 69 }, }, {} }, + { 1220, -690, std::string{gDekuTreeRoom3MinimapTex}, { { 4, 76, 37 }, }, {} }, + { 1200, -500, std::string{gDekuTreeRoom4MinimapTex}, {}, {} }, + { 1390, -380, std::string{gDekuTreeRoom5MinimapTex}, {}, {} }, + { 1770, -470, std::string{gDekuTreeRoom6MinimapTex}, {}, {} }, + { 1610, -630, std::string{gDekuTreeRoom7MinimapTex}, {}, {} }, + { 2000, -990, std::string{gDekuTreeRoom8MinimapTex}, {}, {} }, + { 1290, -870, std::string{gDekuTreeRoom9MinimapTex}, {}, { { -1, 50, 23 }, } }, + { 1420, -720, std::string{gDekuTreeRoom10MinimapTex}, { { 2, 46, 50 }, { 6, 58, 60 }, }, {} }, + { 1110, -630, std::string{gDekuTreeRoom0Floor2MinimapTex}, {}, {} }, + { 1040, -660, std::string{gDekuTreeRoom0Floor3MinimapTex}, {}, {} }, + }, + { + { 11, 12, 3 }, + { 0, 11, 4 }, + { 0, 12, 3 }, + { 12, 11, 4 }, + { 11, 0, 5 }, + }, + }, + {} + }, + { // SCENE_DODONGOS_CAVERN + "ddan_scene", + "Dodongo's Cavern", + "g_pn_08", + SDC_DODONGOS_CAVERN, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 4, 4, 1070, -690 }, + {}, + { + 7, + { 1, 3, 5, 6, 10, 3, 9, 2, 4, 2, 4, 7, 7, 8, 13, 11 }, + std::string{gPauseDodongoTitleENGTex}, + std::string{gPauseDodongoTitleGERTex}, + std::string{gPauseDodongoTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_2F, 280.0f, { 0, 2, 3, 5, 6, 9, 10, 12, }, std::string{gDodongosCavernPauseScreenMapFloor2LeftTex}, std::string{gDodongosCavernPauseScreenMapFloor2RightTex}, { { 10, 25.0f, -41.0f }, { 4, 53.0f, -47.0f }, { 6, 58.0f, -59.0f } }, {}, }, + { F_1F, -440.0f, { 0, 1, 2, 3, 4, 7, 8, 11, 13, 14, 15, }, std::string{gDodongosCavernPauseScreenMapFloor1LeftTex}, std::string{gDodongosCavernPauseScreenMapFloor1RightTex}, { { 5, 13.0f, -60.0f }, { 8, 20.0f, -49.0f } }, { { -1, 23.0f, -25.0f } }, }, + }, + { + { 940, -780, std::string{gDodongosCavernRoom0MinimapTex}, { { 8, 22, 32 }, }, {} }, + { 320, -800, std::string{gDodongosCavernRoom1MinimapTex}, {}, {} }, + { 1500, -1090, std::string{gDodongosCavernRoom2MinimapTex}, {}, {} }, + { 240, -1230, std::string{gDodongosCavernRoom3MinimapTex}, {}, {} }, + { 580, -1140, std::string{gDodongosCavernRoom4MinimapTex}, {}, {} }, + { 1510, -820, std::string{gDodongosCavernRoom5MinimapTex}, {}, {} }, + { 720, -1210, std::string{gDodongosCavernRoom6MinimapTex}, {}, {} }, + { 1030, -1430, std::string{gDodongosCavernRoom7MinimapTex}, {}, { { -1, 37, 49 }, } }, + { 800, -1580, std::string{gDodongosCavernRoom8MinimapTex}, {}, {} }, + { 660, -920, std::string{gDodongosCavernRoom9MinimapTex}, { { 4, 58, 40 }, { 6, 65, 64 }, }, {} }, + { 180, -830, std::string{gDodongosCavernRoom10MinimapTex}, {}, {} }, + { 520, -730, std::string{gDodongosCavernRoom11MinimapTex}, {}, {} }, + { 310, -950, std::string{gDodongosCavernRoom12MinimapTex}, {}, {} }, + { 550, -1580, std::string{gDodongosCavernRoom13MinimapTex}, {}, {} }, + { 790, -1910, std::string{gDodongosCavernRoom14MinimapTex}, {}, {} }, + { 1650, -950, std::string{gDodongosCavernRoom15MinimapTex}, { { 5, 68, 64 }, }, {} }, + { 1000, -860, std::string{gDodongosCavernRoom0Floor3MinimapTex}, { { 10, 31, 27 }, }, {} }, + { 1570, -1070, std::string{gDodongosCavernRoom2Floor3MinimapTex}, {}, {} }, + { 80, -1070, std::string{gDodongosCavernRoom3Floor3MinimapTex}, {}, {} }, + }, + { + { 0, 16, 6 }, + { 2, 17, 6 }, + { 3, 18, 6 }, + { 16, 0, 7 }, + { 17, 2, 7 }, + { 18, 3, 7 }, + }, + }, + {} + }, + { // SCENE_JABU_JABU + "bdan_scene", + "Inside Jabu-Jabu's Belly", + "g_pn_07", + SDC_JABU_JABU, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 3, 3, 1070, -690 }, + {}, + { + 6, + { 3, 1, 2, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 3 }, + std::string{gPauseJabuTitleENGTex}, + std::string{gPauseJabuTitleGERTex}, + std::string{gPauseJabuTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_1F, -640.0f, { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, std::string{gJabuPauseScreenMapFloor1LeftTex}, std::string{gJabuPauseScreenMapFloor1RightTex}, { { 1, 67.0f, -13.0f }, { 2, 28.0f, -13.0f }, { 4, 38.0f, 0.0f } }, { { -1, 65.0f, -37.0f } }, }, + { F_B1, -3000.0f, { 1, 3, 6, 13, 14, }, std::string{gJabuPauseScreenMapBasement1LeftTex}, std::string{gJabuPauseScreenMapBasement1RightTex}, {}, {}, }, + }, + { + { 1130, -770, std::string{gJabuRoom0MinimapTex}, {}, {} }, + { 1070, -1320, std::string{gJabuRoom1MinimapTex}, {}, {} }, + { 1090, -1750, std::string{gJabuRoom2MinimapTex}, {}, {} }, + { 1160, -1800, std::string{gJabuRoom3MinimapTex}, {}, {} }, + { 1500, -1360, std::string{gJabuRoom4MinimapTex}, {}, {} }, + { 690, -1330, std::string{gJabuRoom5MinimapTex}, {}, { { -1, 67, 32 }, } }, + { 1540, -1700, std::string{gJabuRoom6MinimapTex}, {}, {} }, + { 920, -2280, std::string{gJabuRoom7MinimapTex}, {}, {} }, + { 1160, -2700, std::string{gJabuRoom8MinimapTex}, {}, {} }, + { 700, -2360, std::string{gJabuRoom9MinimapTex}, { { 1, 74, 57 }, }, {} }, + { 1650, -2360, std::string{gJabuRoom10MinimapTex}, { { 2, 59, 57 }, }, {} }, + { 950, -2650, std::string{gJabuRoom11MinimapTex}, {}, {} }, + { 1380, -2650, std::string{gJabuRoom12MinimapTex}, { { 4, 68, 51 }, }, {} }, + { 1460, -1600, std::string{gJabuRoom13MinimapTex}, {}, {} }, + { 830, -1445, std::string{gJabuRoom14MinimapTex}, {}, {} }, + { 1170, -1370, std::string{gJabuRoom1Basement1MinimapTex}, {}, {} }, + { 1620, -1910, std::string{gJabuRoom6Basement1MinimapTex}, {}, {} }, + }, + { + { 1, 15, 7 }, + { 6, 16, 7 }, + { 15, 1, 6 }, + { 16, 6, 6 }, + }, + }, + {} + }, + { // SCENE_FOREST_TEMPLE + "Bmori1_scene", + "Forest Temple", + "g_pn_01", + SDC_FOREST_TEMPLE, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 4, 4, 1070, -690 }, + {}, + { + 7, + { 9, 1, 2, 3, 6, 5, 6, 7, 8, 8, 5, 4, 3, 13, 11, 10, 11, 2, 13, 12, 10, 12, 13 }, + std::string{gPauseForestTitleENGTex}, + std::string{gPauseForestTitleGERTex}, + std::string{gPauseForestTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_2F, 760.0f, { 0, 6, 7, 8, 10, 11, 12, 13, 14, 19, 20, }, std::string{gForestTemplePauseScreenMapFloor2LeftTex}, std::string{gForestTemplePauseScreenMapFloor2RightTex}, { { 0, 49.0f, -3.0f }, { 2, 12.0f, -26.0f }, { 5, 74.0f, -13.0f }, { 7, 82.0f, -22.0f } }, {}, }, + { F_1F, -40.0f, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 15, 16, 18, 21, }, std::string{gForestTemplePauseScreenMapFloor1LeftTex}, std::string{gForestTemplePauseScreenMapFloor1RightTex}, { { 0, 49.0f, -3.0f }, { 2, 12.0f, -26.0f }, { 5, 74.0f, -13.0f }, { 7, 82.0f, -22.0f } }, {}, }, + { F_B1, -440.0f, { 9, }, std::string{gForestTemplePauseScreenMapBasement1LeftTex}, std::string{gForestTemplePauseScreenMapBasement1RightTex}, { { 9, 31.0f, -29.0f } }, {}, }, + { F_B2, -3000.0f, { 17, }, std::string{gForestTemplePauseScreenMapBasement2LeftTex}, std::string{gForestTemplePauseScreenMapBasement2RightTex}, { { 11, 40.0f, -41.0f } }, { { -1, 50.0f, -11.0f } }, }, + }, + { + { 1130, -660, std::string{gForestTempleRoom0Floor1MinimapTex}, {}, {} }, + { 1170, -900, std::string{gForestTempleRoom1MinimapTex}, {}, {} }, + { 965, -1040, std::string{gForestTempleRoom2MinimapTex}, {}, {} }, + { 890, -1210, std::string{gForestTempleRoom3MinimapTex}, {}, {} }, + { 1170, -1520, std::string{gForestTempleRoom4MinimapTex}, {}, {} }, + { 1460, -1190, std::string{gForestTempleRoom5MinimapTex}, {}, {} }, + { 1170, -1670, std::string{gForestTempleRoom6Floor1MinimapTex}, { { 0, 72, 60 }, }, {} }, + { 800, -1320, std::string{gForestTempleRoom7Floor1MinimapTex}, { { 5, 76, 38 }, }, {} }, + { 1320, -1310, std::string{gForestTempleRoom8Floor1MinimapTex}, { { 9, 59, 66 }, }, {} }, + { 880, -1260, std::string{gForestTempleRoom9MinimapTex}, { { 9, 15, 58 }, }, {} }, + { 1130, -1500, std::string{gForestTempleRoom10MinimapTex}, { { 1, 69, 56 }, }, {} }, + { 1590, -1080, std::string{gForestTempleRoom11Floor1MinimapTex}, {}, {} }, + { 1390, -1650, std::string{gForestTempleRoom12MinimapTex}, { { 13, 80, 54 }, }, {} }, + { 830, -1620, std::string{gForestTempleRoom13MinimapTex}, { { 15, 49, 50 }, }, {} }, + { 610, -1090, std::string{gForestTempleRoom14MinimapTex}, {}, {} }, + { 580, -1390, std::string{gForestTempleRoom15MinimapTex}, { { 7, 61, 61 }, }, {} }, + { 710, -1220, std::string{gForestTempleRoom16MinimapTex}, {}, {} }, + { 980, -1090, std::string{gForestTempleRoom17MinimapTex}, { { 11, 39, 63 }, }, { { -1, 53, 5 }, } }, + { 1640, -1290, std::string{gForestTempleRoom18MinimapTex}, { { 2, 66, 57 }, }, {} }, + { 1510, -1410, std::string{gForestTempleRoom19MinimapTex}, { { 14, 64, 31 }, }, {} }, + { 590, -1390, std::string{gForestTempleRoom20MinimapTex}, {}, {} }, + { 1610, -1600, std::string{gForestTempleRoom21MinimapTex}, {}, {} }, + { 1130, -660, std::string{gForestTempleRoom0Floor3MinimapTex}, { { 3, 63, 56 }, }, {} }, + { 1130, -1630, std::string{gForestTempleRoom6Floor3MinimapTex}, { { 12, 69, 59 }, }, {} }, + { 820, -1290, std::string{gForestTempleRoom7Floor3MinimapTex}, {}, {} }, + { 1320, -1290, std::string{gForestTempleRoom8Floor3MinimapTex}, {}, {} }, + { 1620, -1080, std::string{gForestTempleRoom11Floor3MinimapTex}, { { 4, 73, 54 }, }, {} }, + }, + { + { 0, 22, 4 }, + { 6, 23, 4 }, + { 7, 24, 4 }, + { 8, 25, 4 }, + { 11, 26, 4 }, + { 22, 0, 5 }, + { 23, 6, 5 }, + { 24, 7, 5 }, + { 25, 8, 5 }, + { 26, 11, 5 }, + }, + }, + {} + }, + { // SCENE_FIRE_TEMPLE + "HIDAN_scene", + "Fire Temple", + "g_pn_03", + SDC_FIRE_TEMPLE, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 4, 4, 1070, -690 }, + {}, + { + 7, + { 1, 6, 7, 2, 3, 4, 6, 10, 6, 10, 7, 9, 11, 1, 12, 3, 11, 4, 5, 8, 9, 10, 11, 12, 13, 2 }, + std::string{gPauseFireTitleENGTex}, + std::string{gPauseFireTitleGERTex}, + std::string{gPauseFireTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_5F, 4360.0f, { 7, 8, 12, 13, }, std::string{gFireTemplePauseScreenMapFloor5LeftTex}, std::string{gFireTemplePauseScreenMapFloor5RightTex}, { { 5, 22.0f, -41.0f }, { 13, 74.0f, -29.0f } }, {}, }, + { F_4F, 3640.0f, { 5, 6, 7, 10, 11, 12, 13, 14, 24, }, std::string{gFireTemplePauseScreenMapFloor4LeftTex}, std::string{gFireTemplePauseScreenMapFloor4RightTex}, {}, {}, }, + { F_3F, 2760.0f, { 4, 5, 6, 9, 10, 11, 16, 23, 24, 25, }, std::string{gFireTemplePauseScreenMapFloor3LeftTex}, std::string{gFireTemplePauseScreenMapFloor3RightTex}, { { 3, 76.0f, -48.0f }, { 6, 72.0f, -50.0f }, { 7, 44.0f, -17.0f }, { 8, 63.0f, -12.0f }, { 9, 30.0f, -34.0f }, { 10, 61.0f, -31.0f } }, {}, }, + { F_2F, 2020.0f, { 4, 6, 10, 21, }, std::string{gFireTemplePauseScreenMapFloor2LeftTex}, std::string{gFireTemplePauseScreenMapFloor2RightTex}, { { 11, 78.0f, -34.0f } }, {}, }, + { F_1F, -140.0f, { 0, 1, 2, 3, 15, 17, 18, 19, 20, 21, 22, }, std::string{gFireTemplePauseScreenMapFloor1LeftTex}, std::string{gFireTemplePauseScreenMapFloor1RightTex}, { { 0, 48.0f, -17.0f }, { 1, 35.0f, -45.0f }, { 2, 67.0f, -58.0f }, { 4, 74.0f, -15.0f }, { 12, 47.0f, -27.0f } }, { { -1, 26.0f, -34.0f } }, }, + }, + { + { 1160, -580, std::string{gFireTempleRoom0MinimapTex}, {}, {} }, + { 620, -620, std::string{gFireTempleRoom1MinimapTex}, {}, {} }, + { 1330, -700, std::string{gFireTempleRoom2MinimapTex}, { { 1, 53, 70 }, }, { { -1, 40, 47 }, } }, + { 1280, -1150, std::string{gFireTempleRoom3MinimapTex}, { { 0, 71, 60 }, }, {} }, + { 440, -710, std::string{gFireTempleRoom4Floor1MinimapTex}, { { 11, 59, 46 }, }, {} }, + { 600, -670, std::string{gFireTempleRoom5Floor1MinimapTex}, { { 6, 57, 73 }, { 3, 66, 71 }, }, {} }, + { 810, -850, std::string{gFireTempleRoom6Floor1MinimapTex}, {}, {} }, + { 830, -1000, std::string{gFireTempleRoom7Floor1MinimapTex}, {}, {} }, + { 720, -720, std::string{gFireTempleRoom8MinimapTex}, { { 13, 72, 38 }, }, {} }, + { 1170, -840, std::string{gFireTempleRoom9MinimapTex}, {}, {} }, + { 1490, -870, std::string{gFireTempleRoom10Floor1MinimapTex}, {}, {} }, + { 1640, -840, std::string{gFireTempleRoom11Floor1MinimapTex}, { { 9, 80, 61 }, }, {} }, + { 1870, -790, std::string{gFireTempleRoom12Floor1MinimapTex}, {}, {} }, + { 1800, -1000, std::string{gFireTempleRoom13Floor1MinimapTex}, {}, {} }, + { 1610, -980, std::string{gFireTempleRoom14MinimapTex}, {}, {} }, + { 1130, -900, std::string{gFireTempleRoom15MinimapTex}, {}, {} }, + { 860, -660, std::string{gFireTempleRoom16MinimapTex}, { { 10, 71, 36 }, }, {} }, + { 1310, -910, std::string{gFireTempleRoom17MinimapTex}, { { 12, 77, 58 }, }, {} }, + { 1140, -1130, std::string{gFireTempleRoom18MinimapTex}, {}, {} }, + { 850, -1230, std::string{gFireTempleRoom19MinimapTex}, {}, {} }, + { 760, -1300, std::string{gFireTempleRoom20MinimapTex}, { { 4, 78, 59 }, }, {} }, + { 380, -810, std::string{gFireTempleRoom21Floor1MinimapTex}, {}, {} }, + { 800, -380, std::string{gFireTempleRoom22MinimapTex}, { { 2, 71, 68 }, }, {} }, + { 800, -1270, std::string{gFireTempleRoom23MinimapTex}, { { 8, 66, 58 }, }, {} }, + { 1930, -820, std::string{gFireTempleRoom24Floor1MinimapTex}, {}, {} }, + { 1410, -1120, std::string{gFireTempleRoom25MinimapTex}, { { 7, 77, 54 }, }, {} }, + { 640, -880, std::string{gFireTempleRoom4Floor3MinimapTex}, {}, {} }, + { 845, -1070, std::string{gFireTempleRoom5Floor3MinimapTex}, {}, {} }, + { 810, -850, std::string{gFireTempleRoom6Floor2MinimapTex}, {}, {} }, + { 810, -850, std::string{gFireTempleRoom6Floor3MinimapTex}, {}, {} }, + { 850, -1060, std::string{gFireTempleRoom7Floor3MinimapTex}, {}, {} }, + { 1390, -640, std::string{gFireTempleRoom10Floor2MinimapTex}, {}, {} }, + { 1540, -900, std::string{gFireTempleRoom10Floor3MinimapTex}, {}, {} }, + { 1650, -850, std::string{gFireTempleRoom11Floor3MinimapTex}, {}, {} }, + { 1880, -890, std::string{gFireTempleRoom12Floor3MinimapTex}, {}, {} }, + { 1530, -740, std::string{gFireTempleRoom13Floor3MinimapTex}, { { 5, 49, 62 }, }, {} }, + { 420, -880, std::string{gFireTempleRoom21Floor3MinimapTex}, {}, {} }, + { 1950, -840, std::string{gFireTempleRoom24Floor3MinimapTex}, {}, {} }, + }, + { + { 21, 36, 6 }, + { 4, 26, 5 }, + { 6, 28, 5 }, + { 10, 31, 5 }, + { 5, 27, 4 }, + { 11, 33, 4 }, + { 24, 37, 4 }, + { 28, 29, 4 }, + { 31, 32, 4 }, + { 10, 32, 4 }, + { 7, 30, 3 }, + { 12, 34, 3 }, + { 13, 35, 3 }, + { 30, 7, 4 }, + { 34, 12, 4 }, + { 35, 13, 4 }, + { 27, 5, 5 }, + { 33, 11, 5 }, + { 37, 24, 5 }, + { 29, 28, 5 }, + { 32, 31, 5 }, + { 26, 4, 6 }, + { 28, 6, 6 }, + { 31, 10, 6 }, + { 36, 21, 7 }, + }, + }, + {} + }, + { // SCENE_WATER_TEMPLE + "MIZUsin_scene", + "Water Temple", + "g_pn_04", + SDC_WATER_TEMPLE, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 4, 4, 900, -640 }, + {}, + { + 4, + { 1, 2, 10, 3, 3, 4, 5, 13, 5, 6, 7, 8, 7, 9, 8, 9, 11, 10, 12, 11, 12, 13, 9, 7, 8, 12 }, + std::string{gPauseWaterTitleENGTex}, + std::string{gPauseWaterTitleGERTex}, + std::string{gPauseWaterTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_3F, 690.0f, { 0, 1, 4, 5, 6, 7, 10, 11, 13, 17, 19, 20, }, std::string{gWaterTemplePauseScreenMapFloor3LeftTex}, std::string{gWaterTemplePauseScreenMapFloor3RightTex}, { { 2, 88.0f, -60.0f }, { 7, 23.0f, -2.0f }, { 9, 84.0f, -45.0f } }, { { -1, 62.0f, -23.0f } }, }, + { F_2F, 330.0f, { 0, 1, 4, 5, 6, 10, 17, 20, 21, }, std::string{gWaterTemplePauseScreenMapFloor2LeftTex}, std::string{gWaterTemplePauseScreenMapFloor2RightTex}, { { 0, 86.0f, -60.0f }, { 8, 76.0f, -72.0f } }, {}, }, + { F_1F, -160.0f, { 0, 1, 3, 5, 8, 9, 12, 14, 15, 16, 17, 18, 21, }, std::string{gWaterTemplePauseScreenMapFloor1LeftTex}, std::string{gWaterTemplePauseScreenMapFloor1RightTex}, { { 1, 88.0f, -60.0f }, { 3, 42.0f, -21.0f }, { 5, 47.0f, -15.0f }, { 10, 33.0f, -31.0f } }, {}, }, + { F_B1, -3000.0f, { 0, 1, 2, 3, 5, 8, 9, 12, 14, 15, }, std::string{gWaterTemplePauseScreenMapBasement1LeftTex}, std::string{gWaterTemplePauseScreenMapBasement1RightTex}, { { 6, 77.0f, -66.0f } }, {}, }, + }, + { + { 1120, -610, std::string{gWaterTempleRoom0Floor3MinimapTex}, {}, {} }, + { 1290, -930, std::string{gWaterTempleRoom1Floor3MinimapTex}, {}, {} }, + { 1120, -770, std::string{gWaterTempleRoom2MinimapTex}, { { 6, 79, 68 }, }, {} }, + { 1380, -680, std::string{gWaterTempleRoom3Floor3MinimapTex}, {}, {} }, + { 930, -1060, std::string{gWaterTempleRoom4Floor3MinimapTex}, { { 9, 81, 62 }, }, {} }, + { 1520, -930, std::string{gWaterTempleRoom5Floor3MinimapTex}, {}, {} }, + { 1980, -980, std::string{gWaterTempleRoom6MinimapTex}, {}, {} }, + { 2010, -1860, std::string{gWaterTempleRoom7MinimapTex}, { { 7, 74, 62 }, }, {} }, + { 1590, -1380, std::string{gWaterTempleRoom8Floor3MinimapTex}, { { 10, 57, 66 }, }, {} }, + { 1510, -1050, std::string{gWaterTempleRoom9Floor3MinimapTex}, {}, {} }, + { 1500, -830, std::string{gWaterTempleRoom10Floor3MinimapTex}, {}, {} }, + { 1300, -1230, std::string{gWaterTempleRoom11MinimapTex}, {}, { { -1, 77, 40 }, } }, + { 1240, -1380, std::string{gWaterTempleRoom12Floor3MinimapTex}, {}, {} }, + { 1800, -1330, std::string{gWaterTempleRoom13MinimapTex}, {}, {} }, + { 1290, -1750, std::string{gWaterTempleRoom14Floor3MinimapTex}, {}, {} }, + { 1450, -1610, std::string{gWaterTempleRoom15Floor3MinimapTex}, {}, {} }, + { 1560, -1600, std::string{gWaterTempleRoom16MinimapTex}, { { 5, 76, 64 }, }, {} }, + { 880, -830, std::string{gWaterTempleRoom17Floor3MinimapTex}, {}, {} }, + { 820, -800, std::string{gWaterTempleRoom18MinimapTex}, { { 1, 74, 61 }, }, {} }, + { 820, -820, std::string{gWaterTempleRoom19MinimapTex}, { { 2, 74, 63 }, }, {} }, + { 1060, -690, std::string{gWaterTempleRoom20Floor3MinimapTex}, {}, {} }, + { 1670, -1540, std::string{gWaterTempleRoom21Floor3MinimapTex}, {}, {} }, + { 1120, -620, std::string{gWaterTempleRoom0Floor2MinimapTex}, {}, {} }, + { 1130, -790, std::string{gWaterTempleRoom0Floor1MinimapTex}, {}, {} }, + { 1130, -780, std::string{gWaterTempleRoom0Basement1MinimapTex}, {}, {} }, + { 1290, -930, std::string{gWaterTempleRoom1Floor2MinimapTex}, {}, {} }, + { 1290, -930, std::string{gWaterTempleRoom1Floor1MinimapTex}, {}, {} }, + { 1280, -870, std::string{gWaterTempleRoom1Basement1MinimapTex}, {}, {} }, + { 1390, -690, std::string{gWaterTempleRoom3Basement1MinimapTex}, {}, {} }, + { 940, -1050, std::string{gWaterTempleRoom4Floor2MinimapTex}, {}, {} }, + { 1520, -930, std::string{gWaterTempleRoom5Floor2MinimapTex}, {}, {} }, + { 1520, -930, std::string{gWaterTempleRoom5Floor1MinimapTex}, {}, {} }, + { 1980, -980, std::string{gWaterTempleRoom6Floor2MinimapTex}, {}, {} }, + { 1620, -1370, std::string{gWaterTempleRoom8Basement1MinimapTex}, {}, {} }, + { 1510, -1050, std::string{gWaterTempleRoom9Basement1MinimapTex}, {}, {} }, + { 1490, -800, std::string{gWaterTempleRoom10Floor2MinimapTex}, {}, {} }, + { 1240, -1380, std::string{gWaterTempleRoom12Basement1MinimapTex}, {}, {} }, + { 1290, -1750, std::string{gWaterTempleRoom14Basement1MinimapTex}, {}, {} }, + { 1450, -1610, std::string{gWaterTempleRoom15Basement1MinimapTex}, {}, {} }, + { 880, -840, std::string{gWaterTempleRoom17Floor2MinimapTex}, { { 0, 74, 64 }, }, {} }, + { 880, -830, std::string{gWaterTempleRoom17Floor1MinimapTex}, {}, {} }, + { 1060, -690, std::string{gWaterTempleRoom20Floor2MinimapTex}, { { 8, 75, 67 }, }, {} }, + { 1670, -1540, std::string{gWaterTempleRoom21Floor1MinimapTex}, { { 3, 82, 65 }, }, {} }, + { 1520, -930, std::string{gWaterTempleRoom5Basement1MinimapTex}, {}, {} }, + }, + { + { 0, 22, 5 }, + { 1, 25, 5 }, + { 4, 29, 5 }, + { 5, 30, 5 }, + { 6, 32, 5 }, + { 10, 35, 5 }, + { 17, 39, 5 }, + { 20, 41, 5 }, + { 0, 23, 6 }, + { 1, 26, 6 }, + { 22, 23, 6 }, + { 25, 26, 6 }, + { 30, 31, 6 }, + { 39, 40, 6 }, + { 21, 42, 6 }, + { 17, 40, 6 }, + { 0, 24, 7 }, + { 1, 27, 7 }, + { 23, 24, 7 }, + { 26, 27, 7 }, + { 3, 28, 7 }, + { 9, 34, 7 }, + { 12, 36, 7 }, + { 14, 37, 7 }, + { 15, 38, 7 }, + { 31, 43, 7 }, + { 8, 33, 7 }, + { 24, 23, 6 }, + { 27, 26, 6 }, + { 28, 3, 6 }, + { 33, 8, 6 }, + { 36, 12, 6 }, + { 37, 14, 6 }, + { 38, 15, 6 }, + { 43, 31, 6 }, + { 34, 9, 6 }, + { 23, 22, 5 }, + { 26, 25, 5 }, + { 31, 30, 5 }, + { 40, 39, 5 }, + { 42, 21, 5 }, + { 17, 39, 5 }, + { 22, 0, 4 }, + { 25, 1, 4 }, + { 29, 4, 4 }, + { 30, 5, 4 }, + { 32, 6, 4 }, + { 35, 10, 4 }, + { 39, 17, 4 }, + { 41, 20, 4 }, + }, + }, + {} + }, + { // SCENE_SPIRIT_TEMPLE + "jyasinzou_scene", + "Spirit Temple", + "g_pn_05", + SDC_SPIRIT_TEMPLE, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 3, 3, 900, -640 }, + {}, + { + 5, + { 10, 1, 2, 3, 4, 5, 10, 7, 8, 9, 10, 6, 12, 13, 11, 8, 13, 1, 2, 3, 4, 11, 6, 12, 8, 5, 10, 9, 6 }, + std::string{gPauseSpiritTitleENGTex}, + std::string{gPauseSpiritTitleGERTex}, + std::string{gPauseSpiritTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_4F, 1480.0f, { 22, 23, 24, 25, 26, }, std::string{gSpiritTemplePauseScreenMapFloor4LeftTex}, std::string{gSpiritTemplePauseScreenMapFloor4RightTex}, { { 10, 59.0f, -9.0f }, { 18, 32.0f, -20.0f } }, {}, }, + { F_3F, 760.0f, { 5, 7, 8, 9, 10, 11, 16, 17, 18, 19, 20, 21, 23, }, std::string{gSpiritTemplePauseScreenMapFloor3LeftTex}, std::string{gSpiritTemplePauseScreenMapFloor3RightTex}, { { 1, 20.0f, -43.0f }, { 5, 83.0f, -26.0f }, { 15, 57.0f, -14.0f }, { 20, 81.0f, -55.0f }, { 21, 87.0f, -55.0f } }, { { -1, 47.0f, 0.0f } }, }, + { F_2F, 280.0f, { 4, 5, 6, 15, }, std::string{gSpiritTemplePauseScreenMapFloor2LeftTex}, std::string{gSpiritTemplePauseScreenMapFloor2RightTex}, { { 2, 41.0f, -16.0f }, { 3, 47.0f, -17.0f }, { 6, 27.0f, -16.0f }, { 12, 29.0f, -20.0f }, { 13, 70.0f, -22.0f }, { 14, 70.0f, -25.0f } }, {}, }, + { F_1F, -3000.0f, { 0, 1, 2, 3, 4, 12, 13, 14, 15, 27, }, std::string{gSpiritTemplePauseScreenMapFloor1LeftTex}, std::string{gSpiritTemplePauseScreenMapFloor1RightTex}, { { 0, 38.0f, -17.0f }, { 4, 55.0f, -14.0f }, { 8, 15.0f, -14.0f }, { 7, 78.0f, -3.0f } }, {}, }, + }, + { + { 800, -570, std::string{gSpiritTempleRoom0MinimapTex}, {}, {} }, + { 1500, -900, std::string{gSpiritTempleRoom1MinimapTex}, {}, {} }, + { 1370, -1070, std::string{gSpiritTempleRoom2MinimapTex}, { { 0, 78, 43 }, }, {} }, + { 1730, -1090, std::string{gSpiritTempleRoom3MinimapTex}, { { 8, 69, 40 }, }, {} }, + { 1590, -1280, std::string{gSpiritTempleRoom4Floor1MinimapTex}, {}, {} }, + { 1020, -1160, std::string{gSpiritTempleRoom5Floor2MinimapTex}, { { 2, 43, 50 }, { 3, 56, 54 }, }, {} }, + { 1060, -920, std::string{gSpiritTempleRoom6MinimapTex}, {}, {} }, + { 1470, -980, std::string{gSpiritTempleRoom7MinimapTex}, {}, {} }, + { 1600, -780, std::string{gSpiritTempleRoom8MinimapTex}, { { 1, 70, 67 }, }, {} }, + { 1830, -530, std::string{gSpiritTempleRoom9MinimapTex}, {}, {} }, + { 1630, -350, std::string{gSpiritTempleRoom10MinimapTex}, {}, {} }, + { 2000, -1000, std::string{gBlankSpiritTempleRoom11MinimapTex}, {}, {} }, + { 650, -1440, std::string{gSpiritTempleRoom12MinimapTex}, { { 7, 70, 58 }, }, {} }, + { 660, -1080, std::string{gSpiritTempleRoom13MinimapTex}, {}, {} }, + { 1020, -1100, std::string{gSpiritTempleRoom14MinimapTex}, { { 4, 68, 42 }, }, {} }, + { 880, -1110, std::string{gSpiritTempleRoom15Floor1MinimapTex}, {}, {} }, + { 940, -980, std::string{gSpiritTempleRoom16MinimapTex}, {}, {} }, + { 720, -860, std::string{gSpiritTempleRoom17MinimapTex}, {}, {} }, + { 570, -790, std::string{gSpiritTempleRoom18MinimapTex}, {}, {} }, + { 620, -540, std::string{gSpiritTempleRoom19MinimapTex}, { { 20, 75, 58 }, { 21, 83, 58 }, }, {} }, + { 570, -350, std::string{gSpiritTempleRoom20MinimapTex}, {}, {} }, + { 550, -1000, std::string{gSpiritTempleRoom21MinimapTex}, { { 5, 71, 55 }, }, {} }, + { 970, -1250, std::string{gSpiritTempleRoom22MinimapTex}, { { 10, 72, 49 }, }, {} }, + { 920, -820, std::string{gSpiritTempleRoom23Floor3MinimapTex}, {}, {} }, + { 1040, -1070, std::string{gSpiritTempleRoom24MinimapTex}, {}, {} }, + { 1150, -1180, std::string{gSpiritTempleRoom25MinimapTex}, {}, {} }, + { 1200, -950, std::string{gSpiritTempleRoom26MinimapTex}, { { 18, 50, 41 }, }, {} }, + { 1550, -1380, std::string{gSpiritTempleRoom27MinimapTex}, {}, {} }, + { 1520, -1160, std::string{gSpiritTempleRoom4Floor2MinimapTex}, { { 6, 73, 49 }, { 12, 79, 55 }, }, {} }, + { 1020, -1100, std::string{gSpiritTempleRoom5Floor3MinimapTex}, { { 15, 77, 42 }, }, { { -1, 57, 23 }, } }, + { 820, -1150, std::string{gSpiritTempleRoom15Floor2MinimapTex}, { { 13, 77, 63 }, { 14, 77, 68 }, }, {} }, + { 1010, -830, std::string{gSpiritTempleRoom23Floor4MinimapTex}, {}, {} }, + }, + { + { 4, 28, 6 }, + { 15, 30, 6 }, + { 5, 29, 5 }, + { 23, 31, 4 }, + { 31, 23, 5 }, + { 29, 5, 6 }, + { 28, 4, 7 }, + { 30, 15, 7 }, + }, + }, + {} + }, + { // SCENE_SHADOW_TEMPLE + "HAKAdan_scene", + "Shadow Temple", + "g_pn_02", + SDC_SHADOW_TEMPLE_AND_WELL, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 10, 10, 900, -640 }, + {}, + { + 7, + { 13, 1, 5, 4, 4, 5, 3, 7, 8, 9, 10, 11, 12, 13, 2, 5, 1, 1, 6, 7, 8, 3, 9, 7, 8, 12 }, + std::string{gPauseShadowTitleENGTex}, + std::string{gPauseShadowTitleGERTex}, + std::string{gPauseShadowTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_B1, -343.3f, { 0, 1, 2, 4, }, std::string{gShadowTemplePauseScreenMapBasement1LeftTex}, std::string{gShadowTemplePauseScreenMapBasement1RightTex}, { { 1, 41.0f, -17.0f }, { 7, 27.0f, -24.0f } }, {}, }, + { F_B2, -863.3f, { 5, 6, 7, 8, }, std::string{gShadowTemplePauseScreenMapBasement2LeftTex}, std::string{gShadowTemplePauseScreenMapBasement2RightTex}, { { 2, 81.0f, -20.0f }, { 3, 74.0f, -37.0f } }, {}, }, + { F_B3, -1143.3f, { 8, 9, 12, 14, 16, 21, }, std::string{gShadowTemplePauseScreenMapBasement3LeftTex}, std::string{gShadowTemplePauseScreenMapBasement3RightTex}, { { 12, 96.0f, -51.0f }, { 22, 96.0f, -55.0f } }, {}, }, + { F_B4, -3000.0f, { 3, 9, 10, 11, 12, 13, 14, 15, 17, 18, 19, 20, 21, }, std::string{gShadowTemplePauseScreenMapBasement4LeftTex}, std::string{gShadowTemplePauseScreenMapBasement4RightTex}, { { 4, 43.0f, -66.0f }, { 5, 37.0f, -66.0f }, { 6, 33.0f, -72.0f }, { 8, 85.0f, -18.0f }, { 9, 61.0f, -42.0f }, { 10, 15.0f, -4.0f }, { 11, 25.0f, -4.0f }, { 13, 19.0f, -29.0f }, { 21, 92.0f, -29.0f }, { 20, 87.0f, -20.0f } }, { { -1, 31.0f, -45.0f } }, }, + }, + { + { 1320, -940, std::string{gShadowTempleRoom0MinimapTex}, {}, {} }, + { 1320, -960, std::string{gShadowTempleRoom1MinimapTex}, { { 1, 77, 64 }, }, {} }, + { 1090, -860, std::string{gShadowTempleRoom2MinimapTex}, {}, {} }, + { 1510, -870, std::string{gShadowTempleRoom3MinimapTex}, {}, { { -1, 77, 76 }, } }, + { 1480, -920, std::string{gShadowTempleRoom4MinimapTex}, { { 7, 76, 65 }, }, {} }, + { 940, -870, std::string{gShadowTempleRoom5MinimapTex}, {}, {} }, + { 920, -980, std::string{gShadowTempleRoom6MinimapTex}, { { 2, 83, 67 }, }, {} }, + { 910, -820, std::string{gShadowTempleRoom7MinimapTex}, { { 3, 76, 67 }, }, {} }, + { 800, -860, std::string{gShadowTempleRoom8Basement2MinimapTex}, {}, {} }, + { 820, -520, std::string{gShadowTempleRoom9Basement3MinimapTex}, {}, {} }, + { 1150, -500, std::string{gShadowTempleRoom10MinimapTex}, { { 4, 78, 62 }, { 5, 74, 62 }, { 6, 71, 68 }, }, {} }, + { 1000, -780, std::string{gShadowTempleRoom11MinimapTex}, { { 9, 77, 64 }, }, {} }, + { 1800, -1050, std::string{gShadowTempleRoom12Basement3MinimapTex}, {}, {} }, + { 1660, -1130, std::string{gShadowTempleRoom13MinimapTex}, { { 10, 71, 65 }, { 11, 80, 65 }, }, {} }, + { 1090, -770, std::string{gShadowTempleRoom14Basement3MinimapTex}, {}, {} }, + { 1630, -1010, std::string{gShadowTempleRoom15MinimapTex}, {}, {} }, + { 710, -680, std::string{gShadowTempleRoom16MinimapTex}, { { 12, 87, 64 }, { 22, 87, 68 }, }, {} }, + { 1670, -930, std::string{gShadowTempleRoom17MinimapTex}, { { 13, 77, 66 }, }, {} }, + { 830, -880, std::string{gShadowTempleRoom18MinimapTex}, {}, {} }, + { 770, -900, std::string{gShadowTempleRoom19MinimapTex}, { { 21, 78, 66 }, }, {} }, + { 800, -980, std::string{gShadowTempleRoom20MinimapTex}, { { 8, 76, 66 }, { 20, 78, 68 }, }, {} }, + { 850, -990, std::string{gShadowTempleRoom21Basement3MinimapTex}, {}, {} }, + { 830, -770, std::string{gShadowTempleRoom8Basement3MinimapTex}, {}, {} }, + { 820, -520, std::string{gShadowTempleRoom9Basement4MinimapTex}, {}, {} }, + { 1800, -1050, std::string{gShadowTempleRoom12Basement4MinimapTex}, {}, {} }, + { 1090, -770, std::string{gShadowTempleRoom14Basement4MinimapTex}, {}, {} }, + { 850, -990, std::string{gShadowTempleRoom21Basement4MinimapTex}, {}, {} }, + }, + { + { 8, 22, 6 }, + { 9, 23, 7 }, + { 12, 24, 7 }, + { 14, 25, 7 }, + { 21, 26, 7 }, + { 23, 9, 6 }, + { 24, 12, 6 }, + { 25, 14, 6 }, + { 26, 21, 6 }, + { 22, 8, 5 }, + }, + }, + {} + }, + { // SCENE_BOTTOM_OF_THE_WELL + "HAKAdanCH_scene", + "Bottom of the Well", + "g_pn_54", + SDC_SHADOW_TEMPLE_AND_WELL, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 5, 5, 900, -640 }, + {}, + { + -1, + { 13, 1, 2, 3, 4, 5, 6 }, + std::string{gPauseBotWTitleENGTex}, + std::string{gPauseBotWTitleGERTex}, + std::string{gPauseBotWTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_B1, -100.0f, { 0, 1, 2, 3, 4, 5, 6, }, std::string{gBottomOfTheWellPauseScreenMapBasement1LeftTex}, std::string{gBottomOfTheWellPauseScreenMapBasement1RightTex}, { { 1, 51.0f, -24.0f }, { 3, 84.0f, -38.0f }, { 4, 31.0f, -2.0f }, { 5, 67.0f, -27.0f }, { 8, 46.0f, -27.0f }, { 10, 82.0f, -12.0f }, { 12, 80.0f, -16.0f }, { 14, 62.0f, -24.0f }, { 20, 89.0f, -38.0f } }, {}, }, + { F_B2, -520.0f, { 0, 1, }, std::string{gBottomOfTheWellPauseScreenMapBasement2LeftTex}, std::string{gBottomOfTheWellPauseScreenMapBasement2RightTex}, { { 2, 54.0f, -27.0f }, { 9, 28.0f, -17.0f }, { 16, 56.0f, -38.0f } }, {}, }, + { F_B3, -3000.0f, { 1, }, std::string{gBottomOfTheWellPauseScreenMapBasement3LeftTex}, std::string{gBottomOfTheWellPauseScreenMapBasement3RightTex}, { { 7, 71.0f, -33.0f } }, {}, }, + }, + { + { 1080, -570, std::string{gBottomOfTheWellRoom0Basement1MinimapTex}, { { 1, 56, 26 }, { 4, 39, 3 }, { 5, 69, 30 }, { 8, 53, 30 }, { 12, 83, 16 }, { 14, 67, 26 }, }, {} }, + { 1420, -930, std::string{gBottomOfTheWellRoom1Basement1MinimapTex}, {}, {} }, + { 1620, -1040, std::string{gBottomOfTheWellRoom2MinimapTex}, {}, {} }, + { 1040, -1100, std::string{gBottomOfTheWellRoom3MinimapTex}, { { 10, 79, 67 }, }, {} }, + { 940, -800, std::string{gBottomOfTheWellRoom4MinimapTex}, { { 3, 73, 62 }, { 20, 81, 62 }, }, {} }, + { 1190, -1100, std::string{gBottomOfTheWellRoom5MinimapTex}, {}, {} }, + { 1310, -1100, std::string{gBottomOfTheWellRoom6MinimapTex}, {}, {} }, + { 1090, -570, std::string{gBottomOfTheWellRoom0Basement2MinimapTex}, { { 2, 59, 28 }, { 9, 36, 19 }, { 16, 62, 38 }, }, {} }, + { 1380, -930, std::string{gBottomOfTheWellRoom1Basement2MinimapTex}, {}, {} }, + { 1080, -890, std::string{gBottomOfTheWellRoom1Basement3MinimapTex}, { { 7, 75, 66 }, }, {} }, + }, + { + { 0, 7, 6 }, + { 1, 8, 6 }, + { 8, 9, 7 }, + { 9, 8, 6 }, + { 7, 0, 5 }, + { 8, 1, 5 }, + }, + }, + {} + }, + { // SCENE_ICE_CAVERN + "ice_doukutu_scene", + "Ice Cavern", + "g_pn_10", + SDC_ICE_CAVERN, + { false, false, false, false, false, false, false, false, true, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 3, 3, 900, -640 }, + {}, + { + -1, + { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }, + std::string{gPauseIceCavernTitleENGTex}, + std::string{gPauseIceCavernTitleGERTex}, + std::string{gPauseIceCavernTitleFRATex}, + { + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_NA, 9999.0f, { }, std::string{}, std::string{}, {}, {}, }, + { F_1F, -3000.0f, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, }, std::string{gIceCavernPauseScreenMapFloor1LeftTex}, std::string{gIceCavernPauseScreenMapFloor1RightTex}, { { 0, 66.0f, -2.0f }, { 1, 77.0f, -46.0f }, { 2, 27.0f, -45.0f } }, {}, }, + }, + { + { 1070, 100, std::string{gIceCavernRoom0MinimapTex}, {}, {} }, + { 1180, -280, std::string{gIceCavernRoom1MinimapTex}, {}, {} }, + { 1270, -690, std::string{gIceCavernRoom2MinimapTex}, {}, {} }, + { 990, -840, std::string{gIceCavernRoom3MinimapTex}, {}, {} }, + { 1280, -1010, std::string{gIceCavernRoom4MinimapTex}, {}, {} }, + { 1450, -950, std::string{gIceCavernRoom5MinimapTex}, {}, {} }, + { 1680, -730, std::string{gIceCavernRoom6MinimapTex}, {}, {} }, + { 1530, -470, std::string{gIceCavernRoom7MinimapTex}, { { 2, 71, 59 }, }, {} }, + { 760, -1130, std::string{gIceCavernRoom8MinimapTex}, {}, {} }, + { 860, -1440, std::string{gIceCavernRoom9MinimapTex}, { { 0, 48, 36 }, }, {} }, + { 1500, -420, std::string{gIceCavernRoom10MinimapTex}, {}, {} }, + { 800, -700, std::string{gIceCavernRoom11MinimapTex}, { { 1, 73, 67 }, }, {} }, + }, + {}, + }, + {} + }, + { // SCENE_GANONS_TOWER + "ganon_scene", + "Ganon's Tower", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GERUDO_TRAINING_GROUND + "men_scene", + "Gerudo Training Ground", + "g_pn_11", + SDC_GERUDO_TRAINING_GROUND, + { false, false, false, false, false, false, false, true, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_THIEVES_HIDEOUT + "gerudoway_scene", + "Thieves' Hideout", + "g_pn_49", + SDC_THIEVES_HIDEOUT, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_INSIDE_GANONS_CASTLE + "ganontika_scene", + "Inside Ganon's Castle", + "g_pn_09", + SDC_INSIDE_GANONS_CASTLE, + { false, false, false, false, false, false, false, true, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GANONS_TOWER_COLLAPSE_INTERIOR + "ganon_sonogo_scene", + "Ganon's Tower (Collapsing)", + "none", + SDC_GANONS_TOWER_COLLAPSE_INTERIOR, + { false, false, false, false, false, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_INSIDE_GANONS_CASTLE_COLLAPSE + "ganontikasonogo_scene", + "Inside Ganon's Castle (Collapsing)", + "none", + SDC_INSIDE_GANONS_CASTLE_COLLAPSE, + { false, false, false, false, false, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TREASURE_BOX_SHOP + "takaraya_scene", + "Treasure Box Shop", + "g_pn_51", + SDC_DEFAULT, + { false, true, false, false, false, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_DEKU_TREE_BOSS + "ydan_boss_scene", + "Gohma's Lair", + "none", + SDC_DEKU_TREE_BOSS, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "ydan_scene" }, + {}, + {} + }, + { // SCENE_DODONGOS_CAVERN_BOSS + "ddan_boss_scene", + "King Dodongo's Lair", + "none", + SDC_DEFAULT, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "ddan_scene" }, + {}, + {} + }, + { // SCENE_JABU_JABU_BOSS + "bdan_boss_scene", + "Barinade's Lair", + "none", + SDC_JABU_JABU, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "bdan_scene" }, + {}, + {} + }, + { // SCENE_FOREST_TEMPLE_BOSS + "moribossroom_scene", + "Phantom Ganon's Lair", + "none", + SDC_DEFAULT, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "Bmori1_scene" }, + {}, + {} + }, + { // SCENE_FIRE_TEMPLE_BOSS + "FIRE_bs_scene", + "Volvagia's Lair", + "none", + SDC_FIRE_TEMPLE, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "HIDAN_scene" }, + {}, + {} + }, + { // SCENE_WATER_TEMPLE_BOSS + "MIZUsin_bs_scene", + "Morpha's Lair", + "none", + SDC_WATER_TEMPLE_BOSS, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "MIZUsin_scene" }, + {}, + {} + }, + { // SCENE_SPIRIT_TEMPLE_BOSS + "jyasinboss_scene", + "Twinrova's Lair & Nabooru's Mini-Boss Room", + "none", + SDC_DEFAULT, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "jyasinzou_scene" }, + {}, + {} + }, + { // SCENE_SHADOW_TEMPLE_BOSS + "HAKAdan_bs_scene", + "Bongo Bongo's Lair", + "none", + SDC_SHADOW_TEMPLE_AND_WELL, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "HAKAdan_scene" }, + {}, + {} + }, + { // SCENE_GANONDORF_BOSS + "ganon_boss_scene", + "Ganondorf's Lair", + "none", + SDC_DEFAULT, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "" }, + {}, + {} + }, + { // SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR + "ganon_final_scene", + "Tower Collapse Exterior", + "none", + SDC_GANONS_TOWER_COLLAPSE_EXTERIOR, + { false, false, false, false, false, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + { "" }, + {}, + {} + }, + { // SCENE_MARKET_ENTRANCE_DAY + "entra_scene", + "Market Entrance (Child - Day)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_ENTRANCE_NIGHT + "entra_n_scene", + "Market Entrance (Child - Night)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_ENTRANCE_RUINS + "enrui_scene", + "Market Entrance (Ruins)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, true, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BACK_ALLEY_DAY + "market_alley_scene", + "Back Alley (Child - Day)", + "g_pn_18", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BACK_ALLEY_NIGHT + "market_alley_n_scene", + "Back Alley (Child - Night)", + "g_pn_18", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_DAY + "market_day_scene", + "Market (Child - Day)", + "g_pn_17", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_NIGHT + "market_night_scene", + "Market (Child - Night)", + "g_pn_17", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_RUINS + "market_ruins_scene", + "Market (Ruins)", + "g_pn_17", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, true, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TEMPLE_OF_TIME_EXTERIOR_DAY + "shrine_scene", + "Temple of Time Exterior (Child - Day)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TEMPLE_OF_TIME_EXTERIOR_NIGHT + "shrine_n_scene", + "Temple of Time Exterior (Child - Night)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TEMPLE_OF_TIME_EXTERIOR_RUINS + "shrine_r_scene", + "Temple of Time Exterior (Ruins)", + "none", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, true, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_KNOW_IT_ALL_BROS_HOUSE + "kokiri_home_scene", + "Know-It-All Brothers' House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TWINS_HOUSE + "kokiri_home3_scene", + "House of Twins", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MIDOS_HOUSE + "kokiri_home4_scene", + "Mido's House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SARIAS_HOUSE + "kokiri_home5_scene", + "Saria's House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_KAKARIKO_CENTER_GUEST_HOUSE + "kakariko_scene", + "Carpenter Boss's House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BACK_ALLEY_HOUSE + "kakariko3_scene", + "Back Alley House (Man in Green)", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BAZAAR + "shop1_scene", + "Bazaar", + "g_pn_23", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_KOKIRI_SHOP + "kokiri_shop_scene", + "Kokiri Shop", + "g_pn_19", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GORON_SHOP + "golon_scene", + "Goron Shop", + "g_pn_20", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_ZORA_SHOP + "zoora_scene", + "Zora Shop", + "g_pn_21", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_POTION_SHOP_KAKARIKO + "drag_scene", + "Kakariko Potion Shop", + "g_pn_24", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_POTION_SHOP_MARKET + "alley_shop_scene", + "Market Potion Shop", + "g_pn_24", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BOMBCHU_SHOP + "night_shop_scene", + "Bombchu Shop", + "g_pn_56", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_HAPPY_MASK_SHOP + "face_shop_scene", + "Happy Mask Shop", + "g_pn_50", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_LINKS_HOUSE + "link_home_scene", + "Link's House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_DOG_LADY_HOUSE + "impa_scene", + "Back Alley House (Dog Lady)", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_STABLE + "malon_stable_scene", + "Stable", + "g_pn_48", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_IMPAS_HOUSE + "labo_scene", + "Impa's House", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_LAKESIDE_LABORATORY + "hylia_labo_scene", + "Lakeside Laboratory", + "g_pn_26", + SDC_LAKESIDE_LABORATORY, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CARPENTERS_TENT + "tent_scene", + "Carpenters' Tent", + "none", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GRAVEKEEPERS_HUT + "hut_scene", + "Gravekeeper's Hut", + "g_pn_25", + SDC_DEFAULT, + { false, true, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GREAT_FAIRYS_FOUNTAIN_MAGIC + "daiyousei_izumi_scene", + "Great Fairy's Fountain (Upgrades)", + "g_pn_13", + SDC_GREAT_FAIRYS_FOUNTAIN, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_FAIRYS_FOUNTAIN + "yousei_izumi_tate_scene", + "Fairy's Fountain", + "g_pn_45", + SDC_FAIRYS_FOUNTAIN, + { false, false, false, false, false, false, false, false, true, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GREAT_FAIRYS_FOUNTAIN_SPELLS + "yousei_izumi_yoko_scene", + "Great Fairy's Fountain (Spells)", + "g_pn_13", + SDC_GREAT_FAIRYS_FOUNTAIN, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GROTTOS + "kakusiana_scene", + "Grottos", + "none", + SDC_GROTTOS, + { false, false, false, false, false, false, false, false, true, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_REDEAD_GRAVE + "hakaana_scene", + "Grave (Redead)", + "none", + SDC_GRAVE_EXIT_LIGHT_SHINING, + { false, false, false, false, false, false, false, false, true, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GRAVE_WITH_FAIRYS_FOUNTAIN + "hakaana2_scene", + "Grave (Fairy's Fountain)", + "none", + SDC_FAIRYS_FOUNTAIN, + { false, false, false, false, false, false, false, false, true, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_ROYAL_FAMILYS_TOMB + "hakaana_ouke_scene", + "Royal Family's Tomb", + "g_pn_44", + SDC_ROYAL_FAMILYS_TOMB, + { false, false, false, false, false, false, false, false, true, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SHOOTING_GALLERY + "syatekijyou_scene", + "Shooting Gallery", + "g_pn_15", + SDC_SHOOTING_GALLERY, + { false, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TEMPLE_OF_TIME + "tokinoma_scene", + "Temple of Time", + "g_pn_16", + SDC_TEMPLE_OF_TIME, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CHAMBER_OF_THE_SAGES + "kenjyanoma_scene", + "Chamber of the Sages", + "g_pn_14", + SDC_CHAMBER_OF_THE_SAGES, + { true, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CASTLE_COURTYARD_GUARDS_DAY + "hairal_niwa_scene", + "Castle Hedge Maze (Day)", + "g_pn_12", + SDC_CASTLE_COURTYARD_GUARDS, + { false, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CASTLE_COURTYARD_GUARDS_NIGHT + "hairal_niwa_n_scene", + "Castle Hedge Maze (Night)", + "g_pn_12", + SDC_CASTLE_COURTYARD_GUARDS, + { false, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CUTSCENE_MAP + "hiral_demo_scene", + "Cutscene Map", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_WINDMILL_AND_DAMPES_GRAVE + "hakasitarelay_scene", + "Damp's Grave & Windmill", + "g_pn_57", + SDC_GRAVE_EXIT_LIGHT_SHINING, + { false, false, false, false, false, false, false, true, false, true, true, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_FISHING_POND + "turibori_scene", + "Fishing Pond", + "g_pn_46", + SDC_FISHING_POND, + { false, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_CASTLE_COURTYARD_ZELDA + "nakaniwa_scene", + "Castle Courtyard", + "g_pn_12", + SDC_CALM_WATER, + { false, false, false, false, false, false, true, false, false, true, true, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BOMBCHU_BOWLING_ALLEY + "bowling_scene", + "Bombchu Bowling Alley", + "g_pn_47", + SDC_BOMBCHU_BOWLING_ALLEY, + { false, true, false, true, true, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_LON_LON_BUILDINGS + "souko_scene", + "Ranch House & Silo", + "none", + SDC_LON_LON_BUILDINGS, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_MARKET_GUARD_HOUSE + "miharigoya_scene", + "Guard House", + "none", + SDC_MARKET_GUARD_HOUSE, + { false, false, false, false, false, true, false, false, false, true, true, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_POTION_SHOP_GRANNY + "mahouya_scene", + "Granny's Potion Shop", + "g_pn_24", + SDC_POTION_SHOP_GRANNY, + { false, true, false, false, false, true, true, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_GANON_BOSS + "ganon_demo_scene", + "Ganon's Tower Collapse & Battle Arena", + "none", + SDC_OUTSIDE_GANONS_CASTLE, + { false, false, false, false, true, false, true, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_HOUSE_OF_SKULLTULA + "kinsuta_scene", + "House of Skulltula", + "g_pn_22", + SDC_DEFAULT, + { false, false, false, false, false, true, false, false, false, true, true, true }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_HYRULE_FIELD + "spot00_scene", + "Spot 00 - Hyrule Field", + "g_pn_27", + SDC_HYRULE_FIELD, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { true, {-460, 100, 6640}, 0, + { { 16, 0, 1341 }, { -1297, 0, 1459 }, { -5416, -300, 1296 }, { -4667, -300, 3620 }, { -3837, 81, 5537 }, { -5093, -226, 6661 }, { -6588, -79, 5053 }, { -7072, -500, 7538 }, { -6139, -500, 8910 }, { -8497, -300, 7802 }, { -5481, -499, 12127 }, { -4808, -700, 13583 }, { -3416, -490, 12092 }, { -2915, 100, 8339 }, { -2277, -500, 13247 }, { -1026, -500, 12101 }, { 1427, -500, 13341 }, { -200, -486, 10205 }, { -1469, 100, 7496 }, { -995, 168, 5652 }, { 1938, 89, 6232 }, { 1387, -105, 9206 }, { 1571, -223, 7701 }, { 3893, -121, 7068 }, { 3179, 373, 5221 }, { 4678, -20, 3869 }, { 3460, 246, 4207 }, { 3686, 128, 2366 }, { 1791, 18, 152 }, { 3667, -16, 1399 }, { 1827, -15, 983 }, { 1574, 399, 4318 }, { 716, 95, 3391 }, { -1189, -41, 4739 }, { -1976, -171, 4172 }, { 1314, 391, 5665 }, { 112, 0, 1959 }, { -3011, -111, 9397 }, { -5674, -270, 8585 }, { -8861, -300, 7836 }, { -6056, -500, 7810 }, { -7306, -500, 5994 }, { -7305, -500, 7605 }, { -7439, -300, 7600 }, { -7464, -300, 6268 }, { -8080, -300, 7553 }, { -8091, -300, 7349 }, { -8785, -300, 7383 }, { -8745, -300, 7508 }, { -8777, -300, 7788 }, { -8048, -299, 7738 }, { -7341, -184, 7730 }, { -6410, -288, 7824 }, { -6326, -290, 8205 }, { -6546, -292, 8400 }, { -7533, -180, 8459 }, { -8024, -295, 7903 }, { -8078, -308, 7994 }, { -9425, -287, 7696 }, { -9322, -292, 7577 }, { -9602, -199, 7160 }, { -9307, -300, 7758 }, { -9230, -300, 7642 }, { -7556, -499, 8695 }, { -6438, -500, 8606 }, { -6078, -500, 8258 }, { -6233, -500, 7613 }, { -5035, -205, 7814 }, { -5971, -500, 8501 }, { -5724, -498, 10123 }, { -5094, -392, 11106 }, { -5105, -393, 11312 }, { -4477, -314, 11132 }, { -3867, -380, 11419 }, { -2952, -500, 11944 }, { -2871, -488, 11743 }, { -3829, -372, 11327 }, { -4439, -293, 10989 }, { -5014, -381, 11086 }, { -5113, -188, 10968 }, { -5269, -188, 11156 }, { -5596, -178, 9972 }, { -5801, -288, 8518 }, { -4910, -178, 7931 }, { -3586, 73, 8140 }, { -4487, -106, 9362 }, { -4339, -112, 6412 }, { -3417, 105, 8194 }, { -4505, -20, 6608 }, { -5038, -199, 6603 }, { -4481, 1, 6448 }, { -5032, -168, 6418 }, { -5256, -700, 14329 }, { -5749, -820, 15380 }, { -3122, -700, 13608 }, { -3758, -525, 13228 }, { -3670, -500, 13123 }, { -2924, -500, 13526 }, { 1389, -115, 9370 }, { 548, -116, 8889 }, { -106, -107, 8530 }, { -1608, 85, 7646 }, { -5300, -700, 13772 }, { -5114, -700, 13400 }, { -4561, -700, 13700 }, { -4762, -700, 14084 }, { -2954, 100, 8216 }, { 1460, -104, 9246 }, { 629, -105, 8791 }, { -10, -90, 8419 }, { -1462, 100, 7504 }, { -3018, -500, 12493 }, { -2994, -311, 10331 }, { -4006, -700, 14152 }, { -4341, -500, 12743 }, { -5879, -497, 6799 }, { 22, -473, 10103 }, { -1389, -192, 8874 }, { -4, 92, 6866 }, { 483, 104, 6637 }, { 1580, 183, 5987 }, { 1548, 308, 5077 }, { 1511, 399, 4267 }, { 1358, 385, 4271 }, { 1379, 395, 5063 }, { 1360, 394, 5870 }, { 813, 283, 6194 }, { -57, 101, 6743 }, { 91, 325, 5143 }, { 1425, -214, 7659 }, { 3487, -19, 880 }, { 2933, 152, 2094 }, { 2888, -145, 6862 }, { 1511, 67, 6471 }, { 4051, -47, 1722 }, { -7335, -500, 8627 }, { -7728, -462, 8498 }, { -7791, -446, 8832 }, { -2915, -435, 11334 }, { 165, -278, 3352 } } }, + { 25, 25, 1080, -360 }, + {}, + {}, + { 216, 150, 80, 73, 1, 0, -1, std::string{gHyruleFieldMinimapTex} } + }, + { // SCENE_KAKARIKO_VILLAGE + "spot01_scene", + "Spot 01 - Kakariko Village", + "g_pn_28", + SDC_KAKARIKO_VILLAGE, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 7, 6, 1000, -650 }, + {}, + {}, + { 216, 158, 80, 64, 269, -833, 8, std::string{gKakarikoVillageMinimapTex} } + }, + { // SCENE_GRAVEYARD + "spot02_scene", + "Spot 02 - Graveyard", + "g_pn_29", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 6, 6, 890, -800 }, + {}, + {}, + { 218, 184, 80, 39, 1, 0, 7, std::string{gGraveyardMinimapTex} } + }, + { // SCENE_ZORAS_RIVER + "spot03_scene", + "Spot 03 - Zora's River", + "g_pn_30", + SDC_ZORAS_RIVER, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 7, 7, 720, -730 }, + {}, + {}, + { 202, 164, 96, 58, 1, 0, -1, std::string{gZorasRiverMinimapTex} } + }, + { // SCENE_KOKIRI_FOREST + "spot04_scene", + "Spot 04 - Kokiri Forest", + "g_pn_31", + SDC_KOKIRI_FOREST, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 8, 8, 660, -730 }, + {}, + {}, + { 202, 160, 96, 62, 273, -850, 0, std::string{gKokiriForestMinimapTex} } + }, + { // SCENE_SACRED_FOREST_MEADOW + "spot05_scene", + "Spot 05 - Sacred Forest Meadow", + "g_pn_52", + SDC_CALM_WATER, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 5, 7, 1220, -660 }, + {}, + {}, + { 250, 138, 48, 85, 279, -889, 3, std::string{gSacredMeadowMinimapTex} } + }, + { // SCENE_LAKE_HYLIA + "spot06_scene", + "Spot 06 - Lake Hylia", + "g_pn_32", + SDC_LAKE_HYLIA, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { true, {-1929, -1025, 768}, 0, + { { -2109, -882, 1724 }, { -328, -1238, 2705 }, { -3092, -1033, 3527 } } }, + { 13, 13, 1080, -260 }, + {}, + {}, + { 216, 140, 80, 81, 259, -829, 5, std::string{gLakeHyliaMinimapTex} } + }, + { // SCENE_ZORAS_DOMAIN + "spot07_scene", + "Spot 07 - Zora's Domain", + "g_pn_33", + SDC_ZORAS_DOMAIN, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 5, 5, 1120, -880 }, + {}, + {}, + { 234, 150, 64, 73, 1, 0, -1, std::string{gZorasDomainMinimapTex} } + }, + { // SCENE_ZORAS_FOUNTAIN + "spot08_scene", + "Spot 08 - Zora's Fountain", + "g_pn_34", + SDC_ZORAS_FOUNTAIN, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 8, 8, 1150, -630 }, + {}, + {}, + { 234, 156, 64, 65, 260, -844, 2, std::string{gZorasFountainMinimapTex} } + }, + { // SCENE_GERUDO_VALLEY + "spot09_scene", + "Spot 09 - Gerudo Valley", + "g_pn_35", + SDC_GERUDO_VALLEY, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { true, {2566, -259, 767}, 0, + { { 2687, -269, 753 }, { 2066, -132, 317 }, { 523, -8, 635 }, { 558, 36, -323 }, { 615, 51, -839 }, { -614, 32, 29 }, { -639, -3, 553 }, { -540, 10, -889 }, { -1666, 58, 378 }, { -3044, 210, -648 } } }, + { 11, 11, 1060, -680 }, + {}, + {}, + { 216, 158, 80, 65, 1, 0, -1, std::string{gGerudoValleyMinimapTex} } + }, + { // SCENE_LOST_WOODS + "spot10_scene", + "Spot 10 - Lost Woods", + "g_pn_36", + SDC_LOST_WOODS, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 12, 12, 1100, -720 }, + {}, + {}, + { 234, 168, 64, 56, 1, 0, -1, std::string{gHauntedWastelandMinimapTex} } + }, + { // SCENE_DESERT_COLOSSUS + "spot11_scene", + "Spot 11 - Desert Colossus", + "g_pn_55", + SDC_DESERT_COLOSSUS, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 11, 11, 930, -710 }, + {}, + {}, + { 234, 162, 64, 59, 235, -836, 6, std::string{gDesertColossusMinimapTex} } + }, + { // SCENE_GERUDOS_FORTRESS + "spot12_scene", + "Spot 12 - Gerudo's Fortress", + "g_pn_53", + SDC_GERUDOS_FORTRESS, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { true, {-328, 10, 953}, 0, + { { -678, 21, -623 }, { 149, 333, -2499 }, { 499, 581, -547 }, { 3187, 1413, -3775 }, { 3198, 1413, 307 }, { 3380, 1413, -1200 }, { -966, 1, -56 }, { -966, 24, -761 }, { -694, 174, -2820 } } }, + { 9, 9, 850, -830 }, + {}, + {}, + { 216, 138, 80, 85, 1, 0, 11, std::string{gGerudosFortessMinimapTex} } + }, + { // SCENE_HAUNTED_WASTELAND + "spot13_scene", + "Spot 13 - Haunted Wasteland", + "g_pn_37", + SDC_HAUNTED_WASTELAND, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 15, 15, 1100, -780 }, + {}, + {}, + { 234, 168, 64, 56, 1, 0, -1, std::string{gLostWoodsMinimapTex} } + }, + { // SCENE_HYRULE_CASTLE + "spot15_scene", + "Spot 15 - Hyrule Castle", + "g_pn_38", + SDC_HYRULE_CASTLE, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 10, 10, 1030, -540 }, + {}, + {}, + { 234, 162, 64, 59, 1, 0, -1, std::string{gHyruleCastleAreaMinimapTex} } + }, + { // SCENE_DEATH_MOUNTAIN_TRAIL + "spot16_scene", + "Spot 16 - Death Mountain Trail", + "g_pn_39", + SDC_DEATH_MOUNTAIN_TRAIL, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 10, 9, 1240, -700 }, + {}, + {}, + { 250, 138, 48, 85, 267, -852, 1, std::string{gDeathMountainTrailMinimapTex} } + }, + { // SCENE_DEATH_MOUNTAIN_CRATER + "spot17_scene", + "Spot 17 - Death Mountain Crater", + "g_pn_40", + SDC_DEATH_MOUNTAIN_CRATER, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 6, 6, 1030, -620 }, + {}, + {}, + { 216, 146, 80, 78, 261, -873, 4, std::string{gDeathMountainCraterMinimapTex} } + }, + { // SCENE_GORON_CITY + "spot18_scene", + "Spot 18 - Goron City", + "g_pn_41", + SDC_GORON_CITY, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 5, 5, 1100, -660 }, + {}, + {}, + { 234, 150, 64, 72, 1, 0, -1, std::string{gGoronCityMinimapTex} } + }, + { // SCENE_LON_LON_RANCH + "spot20_scene", + "Spot 20 - Lon Lon Ranch", + "g_pn_42", + SDC_LON_LON_RANCH, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { true, {928, 0, -2280}, 0, + { { 1039, 0, 2051 }, { -1443, 0, 1429 }, { 856, 0, -918 }, { 882, 0, -2256 }, { -1003, 0, -755 }, { -2254, 0, -629 }, { 907, 0, -2336 } } }, + { 11, 11, 1120, -750 }, + {}, + {}, + { 234, 154, 64, 68, 1, 0, -1, std::string{gLonLonRanchMinimapTex} } + }, + { // SCENE_OUTSIDE_GANONS_CASTLE + "ganon_tou_scene", + "Ganon's Castle Exterior", + "g_pn_43", + SDC_OUTSIDE_GANONS_CASTLE, + { false, false, false, false, false, false, false, false, false, true, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 10, 10, 1070, -580 }, + {}, + {}, + {} + }, + { // SCENE_TEST01 + "test01_scene", + "Jungle Gym", + "none", + SDC_CALM_WATER, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_BESITU + "besitu_scene", + "Ganondorf Test Room", + "none", + SDC_BESITU, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_DEPTH_TEST + "depth_test_scene", + "Depth Test", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SYOTES + "syotes_scene", + "Stalfos Mini-Boss Room", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SYOTES2 + "syotes2_scene", + "Stalfos Boss Room", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SUTARU + "sutaru_scene", + "Sutaru", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_HAIRAL_NIWA2 + "hairal_niwa2_scene", + "Castle Hedge Maze (Early)", + "g_pn_12", + SDC_CASTLE_COURTYARD_GUARDS, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_SASATEST + "sasatest_scene", + "Sasa Test", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // SCENE_TESTROOM + "testroom_scene", + "Treasure Chest Room", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, + { // The entrance table has an entrance for a scene that does not exist. This entry makes a scene that they can be accounted to it. + "SCENE_UNUSED_6E", + "Unused scene that has an entrance for it", + "none", + SDC_DEFAULT, + { false, false, false, false, false, false, false, false, false, false, false, false }, + { false, {0, 0, 0}, 0, {} }, + { 0, 0, 0, 0 }, + {}, + {}, + {} + }, +}; \ No newline at end of file diff --git a/soh/soh/SohMenuBar.cpp b/soh/soh/SohMenuBar.cpp index a6cbd2d816a..b6a9b67f194 100644 --- a/soh/soh/SohMenuBar.cpp +++ b/soh/soh/SohMenuBar.cpp @@ -1551,10 +1551,10 @@ void DrawEnhancementsMenu() { UIWidgets::Tooltip("Restore pre-release behavior where defeating a Gold Skulltula will play a cutscene showing it die."); UIWidgets::PaddedEnhancementCheckbox("Quick Bongo Kill", CVAR_ENHANCEMENT("QuickBongoKill"), true, false); UIWidgets::Tooltip("Restore a bug from NTSC 1.0 that allows bypassing Bongo Bongo's intro cutscene to quickly kill him"); - UIWidgets::PaddedEnhancementCheckbox("Original RBA Values", CVAR_ENHANCEMENT("RestoreRBAValues"), true, false); - UIWidgets::Tooltip("Restores the original outcomes when performing Reverse Bottle Adventure."); UIWidgets::PaddedEnhancementCheckbox("Early Eyeball Frog", CVAR_ENHANCEMENT("EarlyEyeballFrog"), true, false); UIWidgets::Tooltip("Restores a bug from NTSC 1.0/1.1 that allows you to obtain the eyeball frog from King Zora instead of the Zora Tunic by holding shield."); + UIWidgets::PaddedEnhancementCheckbox("Pulsate boss icon", CVAR_ENHANCEMENT("PulsateBossIcon"), true, false); + UIWidgets::Tooltip("Restores an unfinished feature to pulsate the boss room icon when you are in the boss room."); ImGui::EndMenu(); } diff --git a/soh/soh/z_play_otr.cpp b/soh/soh/z_play_otr.cpp index 279b4e696cb..cd68391c222 100644 --- a/soh/soh/z_play_otr.cpp +++ b/soh/soh/z_play_otr.cpp @@ -4,6 +4,7 @@ #include "soh/resource/type/Scene.h" #include #include "soh/Enhancements/game-interactor/GameInteractor.h" +#include "soh/SceneDB.h" #include "global.h" #include "vt.h" #include @@ -21,14 +22,10 @@ Ship::IResource* OTRPlay_LoadFile(PlayState* play, const char* fileName) } extern "C" void OTRPlay_SpawnScene(PlayState* play, s32 sceneId, s32 spawn) { - SceneTableEntry* scene = &gSceneTable[sceneId]; + SceneDB::Entry& entry = SceneDB::Instance->RetrieveEntry(sceneId); - scene->unk_13 = 0; - play->loadedScene = scene; play->sceneNum = sceneId; - play->sceneConfig = scene->config; - - //osSyncPrintf("\nSCENE SIZE %fK\n", (scene->sceneFile.vromEnd - scene->sceneFile.vromStart) / 1024.0f); + play->sceneConfig = entry.entry.sceneDrawConfig; // Scenes considered "dungeon" with a MQ variant int16_t inNonSharedScene = (sceneId >= SCENE_DEKU_TREE && sceneId <= SCENE_ICE_CAVERN) || @@ -38,7 +35,7 @@ extern "C" void OTRPlay_SpawnScene(PlayState* play, s32 sceneId, s32 spawn) { if (inNonSharedScene) { sceneVersion = ResourceMgr_IsGameMasterQuest() ? "mq" : "nonmq"; } - std::string scenePath = StringHelper::Sprintf("scenes/%s/%s/%s", sceneVersion.c_str(), scene->sceneFile.fileName, scene->sceneFile.fileName); + std::string scenePath = StringHelper::Sprintf("scenes/%s/%s/%s", sceneVersion.c_str(), entry.name.c_str(), entry.name.c_str()); play->sceneSegment = OTRPlay_LoadFile(play, scenePath.c_str()); @@ -51,12 +48,8 @@ extern "C" void OTRPlay_SpawnScene(PlayState* play, s32 sceneId, s32 spawn) { return; } - scene->unk_13 = 0; - - //gSegments[2] = VIRTUAL_TO_PHYSICAL(play->sceneSegment); - OTRPlay_InitScene(play, spawn); - auto roomSize = func_80096FE8(play, &play->roomCtx); + uint32_t roomSize = func_80096FE8(play, &play->roomCtx); osSyncPrintf("ROOM SIZE=%fK\n", roomSize / 1024.0f); diff --git a/soh/src/code/z_actor.c b/soh/src/code/z_actor.c index 4cd4d758421..1123ac5b59a 100644 --- a/soh/src/code/z_actor.c +++ b/soh/src/code/z_actor.c @@ -861,6 +861,7 @@ void TitleCard_InitBossName(PlayState* play, TitleCardContext* titleCtx, void* t titleCtx->delayTimer = 0; } +// SceneDB TODO: this needs to be parameterized with a good multi-language solution for the textures void TitleCard_InitPlaceName(PlayState* play, TitleCardContext* titleCtx, void* texture, s32 x, s32 y, s32 width, s32 height, s32 delay) { SceneTableEntry* loadedScene = play->loadedScene; diff --git a/soh/src/code/z_demo.c b/soh/src/code/z_demo.c index 2129dbf1014..9d852d9db7c 100644 --- a/soh/src/code/z_demo.c +++ b/soh/src/code/z_demo.c @@ -35,6 +35,7 @@ #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/SceneDB.h" u16 D_8011E1C0 = 0; u16 D_8011E1C4 = 0; @@ -2203,6 +2204,7 @@ void Cutscene_HandleConditionalTriggers(PlayState* play) { return; } + s32 scene = EntranceDB_Retrieve(gSaveContext.entranceIndex)->sceneId; if ((gSaveContext.gameMode == 0) && (gSaveContext.respawnFlag <= 0) && (gSaveContext.cutsceneIndex < 0xFFF0)) { if ((gSaveContext.entranceIndex == ENTR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) && !Flags_GetEventChkInf(EVENTCHKINF_LEARNED_REQUIEM_OF_SPIRIT)) { Flags_SetEventChkInf(EVENTCHKINF_LEARNED_REQUIEM_OF_SPIRIT); @@ -2230,13 +2232,13 @@ void Cutscene_HandleConditionalTriggers(PlayState* play) { CHECK_QUEST_ITEM(QUEST_MEDALLION_SHADOW) && LINK_IS_ADULT && !Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS) && - (gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_TEMPLE_OF_TIME) + (scene == SCENE_TEMPLE_OF_TIME) ))) { Flags_SetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS); gSaveContext.entranceIndex = ENTR_TEMPLE_OF_TIME_ENTRANCE; gSaveContext.cutsceneIndex = 0xFFF8; } else if (!Flags_GetEventChkInf(EVENTCHKINF_WATCHED_GANONS_CASTLE_COLLAPSE_CAUGHT_BY_GERUDO) && - (gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_GANON_BOSS)) { + (scene == SCENE_GANON_BOSS)) { Flags_SetEventChkInf(EVENTCHKINF_WATCHED_GANONS_CASTLE_COLLAPSE_CAUGHT_BY_GERUDO); gSaveContext.entranceIndex = ENTR_GANON_BOSS_0; gSaveContext.cutsceneIndex = 0xFFF0; diff --git a/soh/src/code/z_horse.c b/soh/src/code/z_horse.c index de50eac4aa8..701e519bcd7 100644 --- a/soh/src/code/z_horse.c +++ b/soh/src/code/z_horse.c @@ -3,8 +3,10 @@ #include #include "soh/Enhancements/game-interactor/GameInteractor.h" #include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h" +#include "soh/SceneDB.h" s32 func_8006CFC0(s32 scene) { +#if 0 s32 validScenes[] = { SCENE_HYRULE_FIELD, SCENE_LAKE_HYLIA, SCENE_GERUDO_VALLEY, SCENE_GERUDOS_FORTRESS, SCENE_LON_LON_RANCH }; s32 i; @@ -15,6 +17,8 @@ s32 func_8006CFC0(s32 scene) { } return 0; +#endif + return SceneDB_Retrieve(scene)->epona.allowed; } void func_8006D074(PlayState* play) { @@ -105,19 +109,13 @@ void func_8006D0EC(PlayState* play, Player* player) { Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, 0.0f, 0.0f, -500.0f, 0, 0, 0, 1, true); assert(horseActor != NULL); } else if (Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) || (DREG(1) != 0)) { - for (i = 0; i < ARRAY_COUNT(horseSpawns); i++) { - HorseSpawn* horseSpawn = &horseSpawns[i]; - if (horseSpawn->scene == play->sceneNum) { - Actor* horseActor = - Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, horseSpawn->pos.x, horseSpawn->pos.y, - horseSpawn->pos.z, 0, horseSpawn->angle, 0, horseSpawn->type, true); - assert(horseActor != NULL); - if (play->sceneNum == SCENE_GERUDOS_FORTRESS) { - horseActor->room = -1; - } - - break; - } + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); + Actor* horseActor = + Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, entry->epona.startingPos.x, entry->epona.startingPos.y, + entry->epona.startingPos.z, 0, entry->epona.angle, 0, 2, true); + assert(horseActor != NULL); + if (play->sceneNum == SCENE_GERUDOS_FORTRESS) { + horseActor->room = -1; } } else if (!Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED)) { if ((DREG(1) == 0) && (play->sceneNum == SCENE_LON_LON_BUILDINGS) && !IS_DAY) { diff --git a/soh/src/code/z_kaleido_scope_call.c b/soh/src/code/z_kaleido_scope_call.c index d958191877a..196e20041f9 100644 --- a/soh/src/code/z_kaleido_scope_call.c +++ b/soh/src/code/z_kaleido_scope_call.c @@ -4,7 +4,7 @@ void (*sKaleidoScopeUpdateFunc)(PlayState* play); void (*sKaleidoScopeDrawFunc)(PlayState* play); -f32 gBossMarkScale; +f32 gBossMarkScale = 1.0f; u32 D_8016139C; PauseMapMarksData* gLoadedPauseMarkDataTable; diff --git a/soh/src/code/z_kaleido_setup.c b/soh/src/code/z_kaleido_setup.c index 69ea3030f91..37f98164eca 100644 --- a/soh/src/code/z_kaleido_setup.c +++ b/soh/src/code/z_kaleido_setup.c @@ -1,4 +1,6 @@ #include "global.h" +#include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" s16 sKaleidoSetupKscpPos0[] = { PAUSE_QUEST, PAUSE_EQUIP, PAUSE_ITEM, PAUSE_MAP }; f32 sKaleidoSetupEyeX0[] = { 0.0f, 64.0f, 0.0f, -64.0f }; @@ -136,6 +138,10 @@ void KaleidoSetup_Init(PlayState* play) { pauseCtx->randoQuestMode = 0; View_Init(&pauseCtx->view, play->state.gfxCtx); + + if (SceneDB_IsDungeon(play->sceneNum)) { + SceneDB_SetPauseMapMarkData(play->sceneNum, ResourceMgr_IsGameMasterQuest()); + } } void KaleidoSetup_Destroy(PlayState* play) { diff --git a/soh/src/code/z_map_data.c b/soh/src/code/z_map_data.c index f76a3b4ce08..a350e60474d 100644 --- a/soh/src/code/z_map_data.c +++ b/soh/src/code/z_map_data.c @@ -134,7 +134,7 @@ static s16 sPaletteRoom[10][8][14] = { static s16 sRoomCompassOffsetX[10][44] = { { 1090, 1390, 1560, 1220, 1200, 1390, 1770, 1610, 2000, 1290, 1420, - 1110, 1040, 470, 790, 1570, 720, 1000, 1580, 70, 0 }, + 1110, 1040, 470, 790, 1570, 720, 1000, 1580, 70 }, { 940, 320, 1500, 240, 580, 1510, 720, 1030, 800, 660, 180, 520, 310, 550, 790, 1650, 1000, 1570, 80, 70 }, { 1130, 1070, 1090, 1160, 1500, 690, 1540, 920, 1160, 700, 1650, 950, 1380, 1460, 830, 1170, 1620 }, { 1130, 1170, 965, 890, 1170, 1460, 1170, 800, 1320, 880, 1130, 1590, 1390, 830, 610, 580, 710, @@ -277,7 +277,7 @@ static u8 sSwitchFromFloor[10][51] = { }; static u8 sSwitchToRoom[10][51] = { - { 12, 11, 12, 11 }, + { 12, 11, 12, 11, 0 }, { 16, 17, 18, 0, 2, 3 }, { 15, 16, 1, 6 }, { 22, 23, 24, 25, 26, 0, 6, 7, 8, 11 }, diff --git a/soh/src/code/z_map_exp.c b/soh/src/code/z_map_exp.c index be358f07521..149323b7b6a 100644 --- a/soh/src/code/z_map_exp.c +++ b/soh/src/code/z_map_exp.c @@ -4,6 +4,8 @@ #include "textures/parameter_static/parameter_static.h" #include "textures/map_i_static/map_i_static.h" #include "textures/map_grand_static/map_grand_static.h" +#include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" #include #include "soh/OTRGlobals.h" @@ -13,6 +15,8 @@ s16 sPlayerInitialPosX = 0; s16 sPlayerInitialPosZ = 0; s16 sPlayerInitialDirection = 0; s16 sEntranceIconMapIndex = 0; +s16 sOwEntranceIconPosX = 0; +s16 sOwEntranceIconPosY = 0; s16 Top_MM_Margin = 0; s16 Left_MM_Margin = 0; @@ -30,7 +34,8 @@ void Map_SavePlayerInitialInfo(PlayState* play) { void Map_SetPaletteData(PlayState* play, s16 room) { s32 mapIndex = gSaveContext.mapIndex; InterfaceContext* interfaceCtx = &play->interfaceCtx; - s16 paletteIndex = gMapData->roomPalette[mapIndex][room]; + SceneDBEntry* entry = SceneDB_Retrieve(mapIndex); + s16 paletteIndex = entry->dungeonData.palettes[room]; if (interfaceCtx->mapRoomNum == room) { interfaceCtx->mapPaletteIndex = paletteIndex; @@ -51,6 +56,7 @@ void Map_SetFloorPalettesData(PlayState* play, s16 floor) { InterfaceContext* interfaceCtx = &play->interfaceCtx; s16 room; s16 i; + SceneDBEntry* entry = SceneDB_Retrieve(mapIndex); for (i = 0; i < 16; i++) { interfaceCtx->mapPalette[i] = 0; @@ -62,32 +68,13 @@ void Map_SetFloorPalettesData(PlayState* play, s16 floor) { interfaceCtx->mapPalette[31] = 1; } - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - for (i = 0; i < gMapData->maxPaletteCount[mapIndex]; i++) { - room = gMapData->paletteRoom[mapIndex][floor][i]; - if ((room != 0xFF) && (gSaveContext.sceneFlags[mapIndex].rooms & gBitFlags[room])) { - Map_SetPaletteData(play, room); - } + if (SCENEDB_ISDUNGEON(entry)) { + for (i = 0; i < entry->dungeonData.floors[floor].numRooms; i++) { + room = entry->dungeonData.floors[floor].rooms[i]; + if ((room != 0xFF) && (gSaveContext.sceneFlags[mapIndex].rooms & gBitFlags[room])) { + Map_SetPaletteData(play, room); } - break; + } } } @@ -366,100 +353,49 @@ void Map_InitData(PlayState* play, s16 room) { s32 mapIndex = gSaveContext.mapIndex; InterfaceContext* interfaceCtx = &play->interfaceCtx; s16 extendedMapIndex; - - switch (play->sceneNum) { - case SCENE_HYRULE_FIELD: - case SCENE_KAKARIKO_VILLAGE: - case SCENE_GRAVEYARD: - case SCENE_ZORAS_RIVER: - case SCENE_KOKIRI_FOREST: - case SCENE_SACRED_FOREST_MEADOW: - case SCENE_LAKE_HYLIA: - case SCENE_ZORAS_DOMAIN: - case SCENE_ZORAS_FOUNTAIN: - case SCENE_GERUDO_VALLEY: - case SCENE_LOST_WOODS: - case SCENE_DESERT_COLOSSUS: - case SCENE_GERUDOS_FORTRESS: - case SCENE_HAUNTED_WASTELAND: - case SCENE_HYRULE_CASTLE: - case SCENE_DEATH_MOUNTAIN_TRAIL: - case SCENE_DEATH_MOUNTAIN_CRATER: - case SCENE_GORON_CITY: - case SCENE_LON_LON_RANCH: - case SCENE_OUTSIDE_GANONS_CASTLE: - extendedMapIndex = mapIndex; - if (play->sceneNum == SCENE_GRAVEYARD) { - if (CHECK_QUEST_ITEM(QUEST_SONG_NOCTURNE)) { - extendedMapIndex = 0x14; - } - } else if (play->sceneNum == SCENE_LAKE_HYLIA) { - if ((LINK_AGE_IN_YEARS == YEARS_ADULT) && - ((!IS_RANDO && !CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER)) || - (IS_RANDO && !Flags_GetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP)))) { - extendedMapIndex = 0x15; - } - } else if (play->sceneNum == SCENE_GERUDO_VALLEY) { - if ((LINK_AGE_IN_YEARS == YEARS_ADULT) && !GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) { - extendedMapIndex = 0x16; - } - } else if (play->sceneNum == SCENE_GERUDOS_FORTRESS) { - if ((!IS_RANDO && GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) || - (IS_RANDO && CHECK_QUEST_ITEM(QUEST_GERUDO_CARD))) { - extendedMapIndex = 0x17; - } - } - osSyncPrintf(VT_FGCOL(BLUE)); - osSyncPrintf("KKK=%d\n", extendedMapIndex); - osSyncPrintf(VT_RST); - sEntranceIconMapIndex = extendedMapIndex; - //DmaMgr_SendRequest1(interfaceCtx->mapSegment, - //(uintptr_t)_map_grand_staticSegmentRomStart + gMapData->owMinimapTexOffset[extendedMapIndex], - //gMapData->owMinimapTexSize[mapIndex], __FILE__, __LINE__); - - if (sEntranceIconMapIndex < 24) { - play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(minimapTableOW[sEntranceIconMapIndex]); - play->interfaceCtx.mapSegmentName[0] = minimapTableOW[sEntranceIconMapIndex]; - } - - interfaceCtx->unk_258 = mapIndex; - break; - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - osSyncPrintf(VT_FGCOL(YELLOW)); - // "Deku Tree Dungeon MAP Texture DMA" - osSyncPrintf("デクの樹ダンジョンMAP テクスチャDMA(%x) scene_id_offset=%d VREG(30)=%d\n", room, - mapIndex, VREG(30)); - osSyncPrintf(VT_RST); - //DmaMgr_SendRequest1(play->interfaceCtx.mapSegment, - //(uintptr_t)_map_i_staticSegmentRomStart + - //((gMapData->dgnMinimapTexIndexOffset[mapIndex] + room) * 0xFF0), - //0xFF0, __FILE__, __LINE__); - - play->interfaceCtx.mapSegment[0] = ResourceGetDataByName( - minimapTableDangeon[gMapData->dgnMinimapTexIndexOffset[mapIndex] + room]); - play->interfaceCtx.mapSegmentName[0] = minimapTableDangeon[gMapData->dgnMinimapTexIndexOffset[mapIndex] + room]; - R_COMPASS_OFFSET_X = gMapData->roomCompassOffsetX[mapIndex][room]; - R_COMPASS_OFFSET_Y = gMapData->roomCompassOffsetY[mapIndex][room]; - Map_SetFloorPalettesData(play, VREG(30)); - osSyncPrintf("MAP 各階ONチェック\n"); // "MAP Individual Floor ON Check" - break; + SceneDBEntry* entry = SceneDB_Retrieve(mapIndex); + + if (SCENEDB_ISOVERWORLD(entry)) { + if (play->sceneNum == SCENE_GRAVEYARD && CHECK_QUEST_ITEM(QUEST_SONG_NOCTURNE)) { + sOwEntranceIconPosX = 294; + sOwEntranceIconPosY = -825; + play->interfaceCtx.mapSegmentName[0] = gExploredShadowGraveyardMinimapTex; + } else if (play->sceneNum == SCENE_LAKE_HYLIA && (LINK_AGE_IN_YEARS == YEARS_ADULT) && + ((!IS_RANDO && !CHECK_QUEST_ITEM(QUEST_MEDALLION_WATER)) || + (IS_RANDO && !Flags_GetEventChkInf(EVENTCHKINF_USED_WATER_TEMPLE_BLUE_WARP)))) { + sOwEntranceIconPosX = 259; + sOwEntranceIconPosY = -829; + play->interfaceCtx.mapSegmentName[0] = gDrainedLakeHyliaMinimapTex; + } else if (play->sceneNum == SCENE_GERUDO_VALLEY && (LINK_AGE_IN_YEARS == YEARS_ADULT) && !GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) { + sOwEntranceIconPosX = 1; + sOwEntranceIconPosY = 0; + play->interfaceCtx.mapSegmentName[0] = gGerudoValleyWithBrokenBridgeMinimapTex; + } else if (play->sceneNum == SCENE_GERUDOS_FORTRESS && (!IS_RANDO && GET_EVENTCHKINF_CARPENTERS_FREE_ALL()) || + (IS_RANDO && CHECK_QUEST_ITEM(QUEST_GERUDO_CARD))) { + sOwEntranceIconPosX = 243; + sOwEntranceIconPosY = -833; + play->interfaceCtx.mapSegmentName[0] = gGerudosFortressMinimapTex; + } else { + sOwEntranceIconPosX = entry->worldData.iconX; + sOwEntranceIconPosY = entry->worldData.iconY; + play->interfaceCtx.mapSegmentName[0] = entry->worldData.minimapTexture; + } + play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(play->interfaceCtx.mapSegmentName[0]); + + interfaceCtx->unk_258 = mapIndex; + } else if (SCENEDB_ISDUNGEON(entry)) { + osSyncPrintf(VT_FGCOL(YELLOW)); + // "Deku Tree Dungeon MAP Texture DMA" + osSyncPrintf("デクの樹ダンジョンMAP テクスチャDMA(%x) scene_id_offset=%d VREG(30)=%d\n", room, + mapIndex, VREG(30)); + osSyncPrintf(VT_RST); + + play->interfaceCtx.mapSegmentName[0] = entry->dungeonData.rooms[room].minimapTexture; + play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(play->interfaceCtx.mapSegmentName[0]); + R_COMPASS_OFFSET_X = entry->dungeonData.rooms[room].compassOffsetX; + R_COMPASS_OFFSET_Y = entry->dungeonData.rooms[room].compassOffsetY; + Map_SetFloorPalettesData(play, VREG(30)); + osSyncPrintf("MAP 各階ONチェック\n"); // "MAP Individual Floor ON Check" } } @@ -470,37 +406,16 @@ void Map_InitRoomData(PlayState* play, s16 room) { osSyncPrintf("*******\n*******\nroom_no=%d (%d)(%d)\n*******\n*******\n", room, mapIndex, play->sceneNum); - if (room >= 0) { - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - gSaveContext.sceneFlags[mapIndex].rooms |= gBitFlags[room]; - osSyncPrintf("ROOM_INF=%d\n", gSaveContext.sceneFlags[mapIndex].rooms); - interfaceCtx->mapRoomNum = room; - interfaceCtx->unk_25A = mapIndex; - Map_SetPaletteData(play, room); - osSyncPrintf(VT_FGCOL(YELLOW)); - osSyncPrintf("部屋部屋=%d\n", room); // "Room Room = %d" - osSyncPrintf(VT_RST); - Map_InitData(play, room); - break; - } + if ((room >= 0) && (SceneDB_IsDungeon(play->sceneNum) || SceneDB_IsBoss(play->sceneNum))) { + gSaveContext.sceneFlags[mapIndex].rooms |= gBitFlags[room]; + osSyncPrintf("ROOM_INF=%d\n", gSaveContext.sceneFlags[mapIndex].rooms); + interfaceCtx->mapRoomNum = room; + interfaceCtx->unk_25A = mapIndex; + Map_SetPaletteData(play, room); + osSyncPrintf(VT_FGCOL(YELLOW)); + osSyncPrintf("部屋部屋=%d\n", room); // "Room Room = %d" + osSyncPrintf(VT_RST); + Map_InitData(play, room); } else { interfaceCtx->mapRoomNum = 0; } @@ -521,6 +436,8 @@ void Map_Init(PlayState* play) { gMapData = &gMapDataTable; + SceneDB_SetMapMarkData(play->sceneNum, ResourceMgr_IsGameMasterQuest()); + interfaceCtx->unk_258 = -1; interfaceCtx->unk_25A = -1; @@ -530,75 +447,30 @@ void Map_Init(PlayState* play) { interfaceCtx->mapSegment, play); assert(interfaceCtx->mapSegment != NULL); - switch (play->sceneNum) { - case SCENE_HYRULE_FIELD: - case SCENE_KAKARIKO_VILLAGE: - case SCENE_GRAVEYARD: - case SCENE_ZORAS_RIVER: - case SCENE_KOKIRI_FOREST: - case SCENE_SACRED_FOREST_MEADOW: - case SCENE_LAKE_HYLIA: - case SCENE_ZORAS_DOMAIN: - case SCENE_ZORAS_FOUNTAIN: - case SCENE_GERUDO_VALLEY: - case SCENE_LOST_WOODS: - case SCENE_DESERT_COLOSSUS: - case SCENE_GERUDOS_FORTRESS: - case SCENE_HAUNTED_WASTELAND: - case SCENE_HYRULE_CASTLE: - case SCENE_DEATH_MOUNTAIN_TRAIL: - case SCENE_DEATH_MOUNTAIN_CRATER: - case SCENE_GORON_CITY: - case SCENE_LON_LON_RANCH: - case SCENE_OUTSIDE_GANONS_CASTLE: - mapIndex = play->sceneNum - SCENE_HYRULE_FIELD; - R_MAP_INDEX = gSaveContext.mapIndex = mapIndex; - R_COMPASS_SCALE_X = gMapData->owCompassInfo[mapIndex][0]; - R_COMPASS_SCALE_Y = gMapData->owCompassInfo[mapIndex][1]; - R_COMPASS_OFFSET_X = gMapData->owCompassInfo[mapIndex][2]; - R_COMPASS_OFFSET_Y = gMapData->owCompassInfo[mapIndex][3]; - Map_InitData(play, mapIndex); - R_OW_MINIMAP_X = gMapData->owMinimapPosX[mapIndex]; - R_OW_MINIMAP_Y = gMapData->owMinimapPosY[mapIndex]; - break; - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_GANONS_TOWER: - case SCENE_GERUDO_TRAINING_GROUND: - case SCENE_THIEVES_HIDEOUT: - case SCENE_INSIDE_GANONS_CASTLE: - case SCENE_GANONS_TOWER_COLLAPSE_INTERIOR: - case SCENE_INSIDE_GANONS_CASTLE_COLLAPSE: - case SCENE_TREASURE_BOX_SHOP: - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - mapIndex = - (play->sceneNum >= SCENE_DEKU_TREE_BOSS) ? play->sceneNum - SCENE_DEKU_TREE_BOSS : play->sceneNum; - R_MAP_INDEX = gSaveContext.mapIndex = mapIndex; - if ((play->sceneNum <= SCENE_ICE_CAVERN) || (play->sceneNum >= SCENE_DEKU_TREE_BOSS)) { - R_COMPASS_SCALE_X = gMapData->dgnCompassInfo[mapIndex][0]; - R_COMPASS_SCALE_Y = gMapData->dgnCompassInfo[mapIndex][1]; - R_COMPASS_OFFSET_X = gMapData->dgnCompassInfo[mapIndex][2]; - R_COMPASS_OFFSET_Y = gMapData->dgnCompassInfo[mapIndex][3]; - R_MAP_TEX_INDEX = R_MAP_TEX_INDEX_BASE = gMapData->dgnMinimapTexIndexBase[mapIndex]; - Map_InitRoomData(play, play->roomCtx.curRoom.num); - MapMark_Init(play); - } - break; + + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); + + if (SCENEDB_ISBOSS(entry)) { + gSaveContext.mapIndex = entry->bossData.mapScene; + } else { + gSaveContext.mapIndex = play->sceneNum; + } + + if (SCENEDB_ISOVERWORLD(entry)) { + R_COMPASS_SCALE_X = entry->compassInfo.scaleX; + R_COMPASS_SCALE_Y = entry->compassInfo.scaleY; + R_COMPASS_OFFSET_X = entry->compassInfo.x; + R_COMPASS_OFFSET_Y = entry->compassInfo.y; + Map_InitData(play, 0); + R_OW_MINIMAP_X = sOwEntranceIconPosX; + R_OW_MINIMAP_Y = sOwEntranceIconPosY; + } else if (SCENEDB_ISDUNGEON(entry) || SCENEDB_ISBOSS(entry)) { + R_COMPASS_SCALE_X = entry->compassInfo.scaleX; + R_COMPASS_SCALE_Y = entry->compassInfo.scaleY; + R_COMPASS_OFFSET_X = entry->compassInfo.x; + R_COMPASS_OFFSET_Y = entry->compassInfo.y; + Map_InitRoomData(play, play->roomCtx.curRoom.num); + MapMark_Init(play); } } @@ -607,6 +479,7 @@ void Minimap_DrawCompassIcons(PlayState* play) { Player* player = GET_PLAYER(play); s16 tempX, tempZ; Color_RGB8 lastEntranceColor = { 200, 0, 0 }; + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); if (CVarGetInteger(CVAR_COSMETIC("HUD.MinimapEntrance.Changed"), 0)) { lastEntranceColor = CVarGetColor24(CVAR_COSMETIC("HUD.MinimapEntrance.Value"), lastEntranceColor); } @@ -638,10 +511,10 @@ void Minimap_DrawCompassIcons(PlayState* play) { s16 mapWidth = 0; s16 mapStartPosX = 0; - if (play->sceneNum >= SCENE_HYRULE_FIELD && play->sceneNum <= SCENE_OUTSIDE_GANONS_CASTLE) { // Overworld - mapStartPosX = R_OW_MINIMAP_X; - mapWidth = gMapData->owMinimapWidth[R_MAP_INDEX]; - } else if (play->sceneNum >= SCENE_DEKU_TREE && play->sceneNum <= SCENE_ICE_CAVERN) { // Dungeons + if (SCENEDB_ISOVERWORLD(entry)) { + mapStartPosX = entry->worldData.minimapX; + mapWidth = entry->worldData.minimapWidth; + } else if (SCENEDB_ISDUNGEON(entry)) { mapStartPosX = R_DGN_MINIMAP_X; mapWidth = 96; } @@ -727,6 +600,7 @@ void Minimap_Draw(PlayState* play) { s32 pad[2]; InterfaceContext* interfaceCtx = &play->interfaceCtx; s32 mapIndex = gSaveContext.mapIndex; + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); Color_RGB8 minimapColor = {0, 255, 255}; if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.Changed"), 0)) { minimapColor = CVarGetColor24(CVAR_COSMETIC("HUD.Minimap.Value"), minimapColor); @@ -751,230 +625,196 @@ void Minimap_Draw(PlayState* play) { Y_Margins_Minimap = 0; } - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - if (!R_MINIMAP_DISABLED && CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 4) { // Not Hidden - Gfx_SetupDL_39Overlay(play->state.gfxCtx); - gDPSetCombineLERP(OVERLAY_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, - TEXEL0, 0, PRIMITIVE, 0); - - if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) { - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); - - u8 mirrorMode = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? G_TX_MIRROR : G_TX_NOMIRROR; - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_I, 96, 85, 0, - mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, - G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - - s16 dgnMiniMapX = OTRGetRectDimensionFromRightEdge(R_DGN_MINIMAP_X + X_Margins_Minimap); - s16 dgnMiniMapY = R_DGN_MINIMAP_Y + Y_Margins_Minimap; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { - dgnMiniMapY = R_DGN_MINIMAP_Y+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0)+Y_Margins_Minimap; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; - dgnMiniMapX = OTRGetDimensionFromLeftEdge(R_DGN_MINIMAP_X+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+X_Margins_Minimap); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; - dgnMiniMapX = OTRGetDimensionFromRightEdge(R_DGN_MINIMAP_X+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+X_Margins_Minimap); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None - dgnMiniMapX = CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); - } - } - - s32 sValue = 0; - if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) { - // Flip the minimap on the x-axis (s-axis) by setting s to the textures mirror boundary - sValue = 96 << 5; - } + if (SCENEDB_ISDUNGEON(entry)) { + if (!R_MINIMAP_DISABLED && CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 4) { // Not Hidden + Gfx_SetupDL_39Overlay(play->state.gfxCtx); + gDPSetCombineLERP(OVERLAY_DISP++, 1, 0, PRIMITIVE, 0, TEXEL0, 0, PRIMITIVE, 0, 1, 0, PRIMITIVE, 0, + TEXEL0, 0, PRIMITIVE, 0); - gSPWideTextureRectangle(OVERLAY_DISP++, dgnMiniMapX << 2, dgnMiniMapY << 2, - (dgnMiniMapX + 96) << 2, (dgnMiniMapY + 85) << 2, G_TX_RENDERTILE, - sValue, 0, 1 << 10, 1 << 10); - } - - if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, mapIndex)) { - Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position - Gfx_SetupDL_39Overlay(play->state.gfxCtx); - MapMark_Draw(play); - } - } - - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { - osSyncPrintf("Game_play_demo_mode_check=%d\n", Play_InCsMode(play)); - // clang-format off - if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &gSfxDefaultPos, 4, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } - else { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_DOWN, &gSfxDefaultPos, 4, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } - // clang-format on - R_MINIMAP_DISABLED ^= 1; - } - - break; - case SCENE_HYRULE_FIELD: - case SCENE_KAKARIKO_VILLAGE: - case SCENE_GRAVEYARD: - case SCENE_ZORAS_RIVER: - case SCENE_KOKIRI_FOREST: - case SCENE_SACRED_FOREST_MEADOW: - case SCENE_LAKE_HYLIA: - case SCENE_ZORAS_DOMAIN: - case SCENE_ZORAS_FOUNTAIN: - case SCENE_GERUDO_VALLEY: - case SCENE_LOST_WOODS: - case SCENE_DESERT_COLOSSUS: - case SCENE_GERUDOS_FORTRESS: - case SCENE_HAUNTED_WASTELAND: - case SCENE_HYRULE_CASTLE: - case SCENE_DEATH_MOUNTAIN_TRAIL: - case SCENE_DEATH_MOUNTAIN_CRATER: - case SCENE_GORON_CITY: - case SCENE_LON_LON_RANCH: - case SCENE_OUTSIDE_GANONS_CASTLE: - if (!R_MINIMAP_DISABLED && CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 4) { // Not Hidden - Gfx_SetupDL_39Overlay(play->state.gfxCtx); - - gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) { gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); u8 mirrorMode = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? G_TX_MIRROR : G_TX_NOMIRROR; - gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_IA, - gMapData->owMinimapWidth[mapIndex], gMapData->owMinimapHeight[mapIndex], 0, - mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, - G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_I, 96, 85, 0, + mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - s16 oWMiniMapX = OTRGetRectDimensionFromRightEdge(R_OW_MINIMAP_X + X_Margins_Minimap); - s16 oWMiniMapY = R_OW_MINIMAP_Y + Y_Margins_Minimap; + s16 dgnMiniMapX = OTRGetRectDimensionFromRightEdge(R_DGN_MINIMAP_X + X_Margins_Minimap); + s16 dgnMiniMapY = R_DGN_MINIMAP_Y + Y_Margins_Minimap; if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { - oWMiniMapY = R_OW_MINIMAP_Y+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0)+Y_Margins_Minimap; + dgnMiniMapY = R_DGN_MINIMAP_Y + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) + Y_Margins_Minimap; if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; - oWMiniMapX = OTRGetDimensionFromLeftEdge(R_OW_MINIMAP_X+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+X_Margins_Minimap); + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Left_MM_Margin; }; + dgnMiniMapX = OTRGetDimensionFromLeftEdge(R_DGN_MINIMAP_X + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + X_Margins_Minimap); } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; - oWMiniMapX = OTRGetDimensionFromRightEdge(R_OW_MINIMAP_X+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+X_Margins_Minimap); + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Right_MM_Margin; }; + dgnMiniMapX = OTRGetDimensionFromRightEdge(R_DGN_MINIMAP_X + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + X_Margins_Minimap); } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None - oWMiniMapX = CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); + dgnMiniMapX = CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); } } s32 sValue = 0; if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) { // Flip the minimap on the x-axis (s-axis) by setting s to the textures mirror boundary - sValue = gMapData->owMinimapWidth[mapIndex] << 5; + sValue = 96 << 5; } - gSPWideTextureRectangle(OVERLAY_DISP++, oWMiniMapX << 2, oWMiniMapY << 2, - (oWMiniMapX + gMapData->owMinimapWidth[mapIndex]) << 2, - (oWMiniMapY + gMapData->owMinimapHeight[mapIndex]) << 2, G_TX_RENDERTILE, sValue, - 0, 1 << 10, 1 << 10); + gSPWideTextureRectangle(OVERLAY_DISP++, dgnMiniMapX << 2, dgnMiniMapY << 2, + (dgnMiniMapX + 96) << 2, (dgnMiniMapY + 85) << 2, G_TX_RENDERTILE, + sValue, 0, 1 << 10, 1 << 10); + } - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); + if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, mapIndex)) { + Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position + Gfx_SetupDL_39Overlay(play->state.gfxCtx); + MapMark_Draw(play); + } + } - s16 iconSize = 8; - - if (((play->sceneNum != SCENE_KAKARIKO_VILLAGE) && (play->sceneNum != SCENE_KOKIRI_FOREST) && - (play->sceneNum != SCENE_ZORAS_FOUNTAIN)) || - (LINK_AGE_IN_YEARS != YEARS_ADULT)) { - s16 origX = gMapData->owEntranceIconPosX[sEntranceIconMapIndex]; - - // Compute the distance of the center of the original texture location to the center of the map - // Then duplicate that and right-align the texture (extra 2 pixels are due to the texture being a 6px left-aligned in a 8px tex) - s16 distFromCenter = (R_OW_MINIMAP_X + (gMapData->owMinimapWidth[mapIndex] / 2)) - (origX + (iconSize / 2)); - s16 mirrorOffset = distFromCenter * 2 + (iconSize / 2) - 2; - s16 newX = origX + (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? mirrorOffset : 0); - - // The game authentically uses larger negative values for the entrance icon Y pos value. Normally only the first 12 bits - // would be read when the final value is passed into `gSPTextureRectangle`, but our cosmetic hud placements requires using - // `gSPWideTextureRectangle` which reads the first 24 bits instead. This caused the icon to be placed off screen. - // To address this, we take only the first 10 bits (which are later left-shifted by 2 to get our final 12 bits) - // to fix the entrance icon position when used with `gSPWideTextureRectangle` - s16 newY = gMapData->owEntranceIconPosY[sEntranceIconMapIndex] & 0x3FF; - - s16 entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap); - s16 entranceY = newY + Y_Margins_Minimap; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { - entranceY = newY + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) + Y_Margins_Minimap; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) { // Anchor Left - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; - entranceX = OTRGetRectDimensionFromLeftEdge(newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) { // Anchor Right - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; - entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) { // Anchor None - entranceX = newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); - } - } + if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + osSyncPrintf("Game_play_demo_mode_check=%d\n", Play_InCsMode(play)); + // clang-format off + if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &gSfxDefaultPos, 4, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + else { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_DOWN, &gSfxDefaultPos, 4, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + // clang-format on + R_MINIMAP_DISABLED ^= 1; + } + } else if (SCENEDB_ISOVERWORLD(entry)) { + if (!R_MINIMAP_DISABLED && CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 4) { // Not Hidden + Gfx_SetupDL_39Overlay(play->state.gfxCtx); + + gDPSetCombineMode(OVERLAY_DISP++, G_CC_MODULATEIA_PRIM, G_CC_MODULATEIA_PRIM); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); + + u8 mirrorMode = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? G_TX_MIRROR : G_TX_NOMIRROR; + gDPLoadTextureBlock_4b(OVERLAY_DISP++, interfaceCtx->mapSegmentName[0], G_IM_FMT_IA, + entry->worldData.minimapWidth, entry->worldData.minimapHeight, 0, + mirrorMode | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + + s16 oWMiniMapX = OTRGetRectDimensionFromRightEdge(entry->worldData.minimapX + X_Margins_Minimap); + s16 oWMiniMapY = entry->worldData.minimapY + Y_Margins_Minimap; + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { + oWMiniMapY = entry->worldData.minimapY + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) + Y_Margins_Minimap; + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Left_MM_Margin; }; + oWMiniMapX = OTRGetDimensionFromLeftEdge(entry->worldData.minimapX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + X_Margins_Minimap); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Right_MM_Margin; }; + oWMiniMapX = OTRGetDimensionFromRightEdge(entry->worldData.minimapX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + X_Margins_Minimap); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None + oWMiniMapX = CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); + } + } - // For icons that normally would be placed in 0,0 leave them there based on the left edge dimension - // or hide them entirely if the fix is applied - if (gMapData->owEntranceIconPosY[sEntranceIconMapIndex] == 0) { - entranceY = 0; - entranceX = CVarGetInteger(CVAR_ENHANCEMENT("FixDungeonMinimapIcon"), 0) ? -9999 : OTRGetRectDimensionFromLeftEdge(0); - } + s32 sValue = 0; + if (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0)) { + // Flip the minimap on the x-axis (s-axis) by setting s to the textures mirror boundary + sValue = entry->worldData.minimapWidth << 5; + } - //! @bug UB: sEntranceIconMapIndex can be up to 23 and is accessing owEntranceFlag which is size 20 - if ((gMapData->owEntranceFlag[sEntranceIconMapIndex] == 0xFFFF) || - ((gMapData->owEntranceFlag[sEntranceIconMapIndex] != 0xFFFF) && - ((gSaveContext.infTable[26] & gBitFlags[gMapData->owEntranceFlag[mapIndex]]) || - CVarGetInteger(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon"), 0)))) { - gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, - iconSize, iconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + iconSize) << 2, - (entranceY + iconSize) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); - } - } + gSPWideTextureRectangle(OVERLAY_DISP++, oWMiniMapX << 2, oWMiniMapY << 2, + (oWMiniMapX + entry->worldData.minimapWidth) << 2, + (oWMiniMapY + entry->worldData.minimapHeight) << 2, G_TX_RENDERTILE, sValue, + 0, 1 << 10, 1 << 10); + + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, minimapColor.r, minimapColor.g, minimapColor.b, interfaceCtx->minimapAlpha); + + s16 iconSize = 8; + + if (((play->sceneNum != SCENE_KAKARIKO_VILLAGE) && (play->sceneNum != SCENE_KOKIRI_FOREST) && + (play->sceneNum != SCENE_ZORAS_FOUNTAIN)) || + (LINK_AGE_IN_YEARS != YEARS_ADULT)) { + s16 origX = R_OW_MINIMAP_X; - s16 origX = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? 256 : 270; - s16 entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap); - s16 entranceY = 154 + Y_Margins_Minimap; + // Compute the distance of the center of the original texture location to the center of the map + // Then duplicate that and right-align the texture (extra 2 pixels are due to the texture being a 6px left-aligned in a 8px tex) + s16 distFromCenter = (entry->worldData.minimapX + (entry->worldData.minimapWidth / 2)) - (origX + (iconSize / 2)); + s16 mirrorOffset = distFromCenter * 2 + (iconSize / 2) - 2; + s16 newX = origX + (CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? mirrorOffset : 0); + + // The game authentically uses larger negative values for the entrance icon Y pos value. Normally only the first 12 bits + // would be read when the final value is passed into `gSPTextureRectangle`, but our cosmetic hud placements requires using + // `gSPWideTextureRectangle` which reads the first 24 bits instead. This caused the icon to be placed off screen. + // To address this, we take only the first 10 bits (which are later left-shifted by 2 to get our final 12 bits) + // to fix the entrance icon position when used with `gSPWideTextureRectangle` + s16 newY = R_OW_MINIMAP_Y & 0x3FF; + + s16 entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap); + s16 entranceY = newY + Y_Margins_Minimap; if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { - entranceY = 154 + Y_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0); - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Left_MM_Margin;}; - entranceX = OTRGetRectDimensionFromLeftEdge(origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap = Right_MM_Margin;}; - entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None - entranceX = origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); + entranceY = newY + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) + Y_Margins_Minimap; + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) { // Anchor Left + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Left_MM_Margin; }; + entranceX = OTRGetRectDimensionFromLeftEdge(newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) { // Anchor Right + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Right_MM_Margin; }; + entranceX = OTRGetRectDimensionFromRightEdge(newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) { // Anchor None + entranceX = newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); } } - // Ice Cavern entrance icon - if ((play->sceneNum == SCENE_ZORAS_FOUNTAIN) && ((gSaveContext.infTable[26] & gBitFlags[9]) || - CVarGetInteger(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon"), 0))) { - gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, iconSize, - iconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, - G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + // For icons that normally would be placed in 0,0 leave them there based on the left edge dimension + // or hide them entirely if the fix is applied + if (R_OW_MINIMAP_Y == 0) { + entranceY = 0; + entranceX = CVarGetInteger(CVAR_ENHANCEMENT("FixDungeonMinimapIcon"), 0) ? -9999 : OTRGetRectDimensionFromLeftEdge(0); + } + + if ((entry->worldData.entranceFlag == -1) || + ((entry->worldData.entranceFlag != -1) && + ((gSaveContext.infTable[26] & gBitFlags[entry->worldData.entranceFlag]) || + CVarGetInteger(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon"), 0)))) { + gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, + iconSize, iconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + iconSize) << 2, - (entranceY + iconSize) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); + (entranceY + iconSize) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } + } - Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position + s16 origX = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? 256 : 270; + s16 entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap); + s16 entranceY = 154 + Y_Margins_Minimap; + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { + entranceY = 154 + Y_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0); + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Left_MM_Margin; }; + entranceX = OTRGetRectDimensionFromLeftEdge(origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { X_Margins_Minimap = Right_MM_Margin; }; + entranceX = OTRGetRectDimensionFromRightEdge(origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)); + } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None + entranceX = origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0); + } } - if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { - // clang-format off - if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &gSfxDefaultPos, 4, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } - else { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_DOWN, &gSfxDefaultPos, 4, - &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } - // clang-format on - R_MINIMAP_DISABLED ^= 1; + // Ice Cavern entrance icon + if ((play->sceneNum == SCENE_ZORAS_FOUNTAIN) && ((gSaveContext.infTable[26] & gBitFlags[9]) || + CVarGetInteger(CVAR_ENHANCEMENT("AlwaysShowDungeonMinimapIcon"), 0))) { + gDPLoadTextureBlock(OVERLAY_DISP++, gMapDungeonEntranceIconTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, iconSize, + iconSize, 0, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, + G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + gSPWideTextureRectangle(OVERLAY_DISP++, entranceX << 2, entranceY << 2, (entranceX + iconSize) << 2, + (entranceY + iconSize) << 2, G_TX_RENDERTILE, 0, 0, 1 << 10, 1 << 10); } - break; + Minimap_DrawCompassIcons(play); // Draw icons for the player spawn and current position + } + + if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) && enableMapToggle) { + // clang-format off + if (!R_MINIMAP_DISABLED) { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_UP, &gSfxDefaultPos, 4, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + else { Audio_PlaySoundGeneral(NA_SE_SY_CAMERA_ZOOM_DOWN, &gSfxDefaultPos, 4, + &gSfxDefaultFreqAndVolScale, &gSfxDefaultFreqAndVolScale, &gSfxDefaultReverb); } + // clang-format on + R_MINIMAP_DISABLED ^= 1; + } } } @@ -992,6 +832,7 @@ void Map_Update(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; s16 floor; s16 i; + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); Top_MM_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.T"), 0); Left_MM_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.L"), 0); @@ -999,71 +840,47 @@ void Map_Update(PlayState* play) { Bottom_MM_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.B"), 0); if ((play->pauseCtx.state == 0) && (play->pauseCtx.debugState == 0)) { - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - interfaceCtx->mapPalette[30] = 0; - if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) { - interfaceCtx->mapPalette[31] = 1; - } else { - interfaceCtx->mapPalette[31] = 0; - } + if (SCENEDB_ISDUNGEON(entry)) { + interfaceCtx->mapPalette[30] = 0; + if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, play->sceneNum)) { + interfaceCtx->mapPalette[31] = 1; + } else { + interfaceCtx->mapPalette[31] = 0; + } - for (floor = 0; floor < 8; floor++) { - if (player->actor.world.pos.y > gMapData->floorCoordY[mapIndex][floor]) { - break; - } + for (floor = 0; floor < 8; floor++) { + if (player->actor.world.pos.y > entry->dungeonData.floors[floor].height) { + break; } + } - gSaveContext.sceneFlags[mapIndex].floors |= gBitFlags[floor]; - VREG(30) = floor; - if (R_MAP_TEX_INDEX != (R_MAP_TEX_INDEX_BASE + Map_GetFloorTextIndexOffset(mapIndex, floor))) { - R_MAP_TEX_INDEX = R_MAP_TEX_INDEX_BASE + Map_GetFloorTextIndexOffset(mapIndex, floor); - } + gSaveContext.sceneFlags[play->sceneNum].floors |= gBitFlags[floor]; + VREG(30) = floor; - if (interfaceCtx->mapRoomNum != sLastRoomNum) { - // "Current floor = %d Current room = %x Number of rooms = %d" - osSyncPrintf("現在階=%d 現在部屋=%x 部屋数=%d\n", floor, interfaceCtx->mapRoomNum, - gMapData->switchEntryCount[mapIndex]); - sLastRoomNum = interfaceCtx->mapRoomNum; - } + if (interfaceCtx->mapRoomNum != sLastRoomNum) { + // "Current floor = %d Current room = %x Number of rooms = %d" + osSyncPrintf("現在階=%d 現在部屋=%x 部屋数=%d\n", floor, interfaceCtx->mapRoomNum, + entry->dungeonData.numRooms); + sLastRoomNum = interfaceCtx->mapRoomNum; + } - for (i = 0; i < gMapData->switchEntryCount[mapIndex]; i++) { - if ((interfaceCtx->mapRoomNum == gMapData->switchFromRoom[mapIndex][i]) && - (floor == gMapData->switchFromFloor[mapIndex][i])) { - interfaceCtx->mapRoomNum = gMapData->switchToRoom[mapIndex][i]; - osSyncPrintf(VT_FGCOL(YELLOW)); - // "Layer switching = %x" - osSyncPrintf("階層切替=%x\n", interfaceCtx->mapRoomNum); - osSyncPrintf(VT_RST); - Map_InitData(play, interfaceCtx->mapRoomNum); - gSaveContext.sunsSongState = SUNSSONG_INACTIVE; - Map_SavePlayerInitialInfo(play); - } + for (i = 0; i < entry->dungeonData.numIntraRoomTransitions; i++) { + if ((interfaceCtx->mapRoomNum == entry->dungeonData.intraRoomTransitions[i].fromRoom) && + (floor == entry->dungeonData.intraRoomTransitions[i].toFloor)) { + interfaceCtx->mapRoomNum = entry->dungeonData.intraRoomTransitions[i].toRoom; + osSyncPrintf(VT_FGCOL(YELLOW)); + // "Layer switching = %x" + osSyncPrintf("階層切替=%x\n", interfaceCtx->mapRoomNum); + osSyncPrintf(VT_RST); + Map_InitData(play, interfaceCtx->mapRoomNum); + gSaveContext.sunsSongState = SUNSSONG_INACTIVE; + Map_SavePlayerInitialInfo(play); } + } - VREG(10) = interfaceCtx->mapRoomNum; - break; - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - VREG(30) = gMapData->bossFloor[play->sceneNum - SCENE_DEKU_TREE_BOSS]; - R_MAP_TEX_INDEX = R_MAP_TEX_INDEX_BASE + - gMapData->floorTexIndexOffset[play->sceneNum - SCENE_DEKU_TREE_BOSS][VREG(30)]; - break; + VREG(10) = interfaceCtx->mapRoomNum; + } else if (SCENEDB_ISBOSS(entry)) { + VREG(30) = SceneDB_Retrieve(entry->bossData.mapScene)->dungeonData.bossFloor; } } } diff --git a/soh/src/code/z_map_mark.c b/soh/src/code/z_map_mark.c index 1831b8fddf8..e86e79b2a51 100644 --- a/soh/src/code/z_map_mark.c +++ b/soh/src/code/z_map_mark.c @@ -1,5 +1,6 @@ #include "global.h" #include "vt.h" +#include "soh/SceneDB.h" #include "textures/parameter_static/parameter_static.h" #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" @@ -94,122 +95,92 @@ void MapMark_DrawForDungeon(PlayState* play) { interfaceCtx = &play->interfaceCtx; - if ((gMapData != NULL) && (play->interfaceCtx.mapRoomNum >= gMapData->dgnMinimapCount[dungeon])) { - // "Room number exceeded, yikes %d/%d MapMarkDraw processing interrupted" - osSyncPrintf(VT_COL(RED, WHITE) "部屋番号がオーバーしてるで,ヤバイで %d/%d \nMapMarkDraw の処理を中断します\n", - VT_RST, play->interfaceCtx.mapRoomNum, gMapData->dgnMinimapCount[dungeon]); - return; - } + SceneDBEntry* entry = SceneDB_Retrieve(dungeon); + SceneDBRoom* room = &entry->dungeonData.rooms[interfaceCtx->mapRoomNum]; + + s32 Top_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.T"), 0); + s32 Left_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.L"), 0); + s32 Right_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.R"), 0); + s32 Bottom_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.B"), 0); - mapMarkIconData = &sLoadedMarkDataTable[dungeon][interfaceCtx->mapRoomNum][0]; + s32 X_Margins_Minimap_ic; + s32 Y_Margins_Minimap_ic; + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { + if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 0) { X_Margins_Minimap_ic = Right_MC_Margin; }; + Y_Margins_Minimap_ic = Bottom_MC_Margin; + } else { + X_Margins_Minimap_ic = 0; + Y_Margins_Minimap_ic = 0; + } OPEN_DISPS(play->state.gfxCtx); - while (true) { - if (mapMarkIconData->markType == MAP_MARK_NONE) { - break; + gDPPipeSync(OVERLAY_DISP++); + gDPSetTextureLUT(OVERLAY_DISP++, G_TT_NONE); + gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->minimapAlpha); + gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, interfaceCtx->minimapAlpha); + + // Chest and boss icon code is nearly identical, so let's draw them in the same loop + for (i = 0; i < room->numChestMarks + room->numBossMarks; i++) { + if (i < room->numChestMarks) { + if (Flags_GetTreasure(play, markPoint->chestFlag)) { + continue; + } + + markPoint = &room->chestMarks[i]; + markInfo = &sMapMarkInfoTable[MAP_MARK_CHEST]; + } else { // This is a boss icon + markPoint = &room->bossMarks[i - room->numChestMarks]; + markInfo = &sMapMarkInfoTable[MAP_MARK_BOSS]; } - gDPPipeSync(OVERLAY_DISP++); - gDPSetTextureLUT(OVERLAY_DISP++, G_TT_NONE); - gDPSetPrimColor(OVERLAY_DISP++, 0, 0, 255, 255, 255, interfaceCtx->minimapAlpha); - gDPSetEnvColor(OVERLAY_DISP++, 0, 0, 0, interfaceCtx->minimapAlpha); - - s32 Top_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.T"), 0); - s32 Left_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.L"), 0); - s32 Right_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.R"), 0); - s32 Bottom_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.B"), 0); - - s32 X_Margins_Minimap_ic; - s32 Y_Margins_Minimap_ic; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) { - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 0) {X_Margins_Minimap_ic = Right_MC_Margin;}; - Y_Margins_Minimap_ic = Bottom_MC_Margin; + int height = markInfo->textureHeight * 1.0f; //Adjust Height with scale + int width = markInfo->textureWidth * 1.0f; //Adjust Width with scale + int height_factor = (1 << 10) * markInfo->textureHeight / height; + int width_factor = (1 << 10) * markInfo->textureWidth / width; + + // The original mark point X originates from the left edge of the map + // For mirror mode, we compute the new mark point X by subtracting it from the right side of the + // dungeon map and the textures width + s16 markPointX = CVarGetInteger("gMirroredWorld", 0) ? 96 - markPoint->x - width : markPoint->x; + + //Minimap chest / boss icon + const s32 PosX_Minimap_ori = GREG(94) + OTRGetRectDimensionFromRightEdge(markPointX + X_Margins_Minimap_ic) + 204; + const s32 PosY_Minimap_ori = GREG(95) + markPoint->y + Y_Margins_Minimap_ic + 140; + if (CVarGetInteger("gMinimapPosType", 0) != 0) { + rectTop = (markPoint->y + Y_Margins_Minimap_ic + 140 + CVarGetInteger("gMinimapPosY", 0)); + if (CVarGetInteger("gMinimapPosType", 0) == 1) {//Anchor Left + if (CVarGetInteger("gMinimapUseMargins", 0) != 0) { X_Margins_Minimap_ic = Left_MC_Margin; }; + rectLeft = OTRGetRectDimensionFromLeftEdge(markPointX + CVarGetInteger("gMinimapPosX", 0) + 204 + X_Margins_Minimap_ic); + } else if (CVarGetInteger("gMinimapPosType", 0) == 2) {//Anchor Right + if (CVarGetInteger("gMinimapUseMargins", 0) != 0) { X_Margins_Minimap_ic = Right_MC_Margin; }; + rectLeft = OTRGetRectDimensionFromRightEdge(markPointX + CVarGetInteger("gMinimapPosX", 0) + 204 + X_Margins_Minimap_ic); + } else if (CVarGetInteger("gMinimapPosType", 0) == 3) {//Anchor None + rectLeft = markPointX + CVarGetInteger("gMinimapPosX", 0) + 204 + X_Margins_Minimap_ic; + } else if (CVarGetInteger("gMinimapPosType", 0) == 4) {//Hidden + rectLeft = -9999; + } } else { - X_Margins_Minimap_ic = 0; - Y_Margins_Minimap_ic = 0; + rectLeft = PosX_Minimap_ori; + rectTop = PosY_Minimap_ori; } - markPoint = &mapMarkIconData->points[0]; - //Place each chest / boss room icon - for (i = 0; i < mapMarkIconData->count; i++) { - if ((mapMarkIconData->markType != MAP_MARK_CHEST) || !Flags_GetTreasure(play, markPoint->chestFlag)) { - markInfo = &sMapMarkInfoTable[mapMarkIconData->markType]; - int height = markInfo->textureHeight * 1.0f; //Adjust Height with scale - int width = markInfo->textureWidth * 1.0f; //Adjust Width with scale - int height_factor = (1 << 10) * markInfo->textureHeight / height; - int width_factor = (1 << 10) * markInfo->textureWidth / width; - - // The original mark point X originates from the left edge of the map - // For mirror mode, we compute the new mark point X by subtracting it from the right side of the - // dungeon map and the textures width - s16 markPointX = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? 96 - markPoint->x - width : markPoint->x; - - //Minimap chest / boss icon - const s32 PosX_Minimap_ori = GREG(94) + OTRGetRectDimensionFromRightEdge(markPointX+X_Margins_Minimap_ic) + 204; - const s32 PosY_Minimap_ori = GREG(95) + markPoint->y + Y_Margins_Minimap_ic + 140; - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != 0) { - rectTop = (markPoint->y + Y_Margins_Minimap_ic + 140 + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0)); - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 1) {//Anchor Left - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap_ic = Left_MC_Margin;}; - if (play->sceneNum == SCENE_DEKU_TREE || play->sceneNum == SCENE_DODONGOS_CAVERN || play->sceneNum == SCENE_JABU_JABU || - play->sceneNum == SCENE_FOREST_TEMPLE || play->sceneNum == SCENE_FIRE_TEMPLE || play->sceneNum == SCENE_WATER_TEMPLE || - play->sceneNum == SCENE_SPIRIT_TEMPLE || play->sceneNum == SCENE_SHADOW_TEMPLE || play->sceneNum == SCENE_BOTTOM_OF_THE_WELL || - play->sceneNum == SCENE_ICE_CAVERN) { - rectLeft = OTRGetRectDimensionFromLeftEdge(markPointX+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+204+X_Margins_Minimap_ic); - } else { - rectLeft = OTRGetRectDimensionFromLeftEdge(markPointX+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+204+X_Margins_Minimap_ic); - } - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 2) {//Anchor Right - if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {X_Margins_Minimap_ic = Right_MC_Margin;}; - rectLeft = OTRGetRectDimensionFromRightEdge(markPointX+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+204+X_Margins_Minimap_ic); - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 3) {//Anchor None - rectLeft = markPointX+CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0)+204+X_Margins_Minimap_ic; - } else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 4) {//Hidden - rectLeft = -9999; - } - } else { - rectLeft = PosX_Minimap_ori; - rectTop = PosY_Minimap_ori; - } - - gDPPipeSync(OVERLAY_DISP++); - - gDPLoadTextureBlock(OVERLAY_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK, - markInfo->textureWidth, markInfo->textureHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); - //Changed to a Wide texture to support Left anchor. - gSPWideTextureRectangle(OVERLAY_DISP++, rectLeft << 2, rectTop << 2, rectLeft + width << 2, - rectTop + height << 2, G_TX_RENDERTILE, 0, 0, width_factor, - height_factor); - } + gDPPipeSync(OVERLAY_DISP++); - markPoint++; - } - mapMarkIconData++; + gDPLoadTextureBlock(OVERLAY_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK, + markInfo->textureWidth, markInfo->textureHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + //Changed to a Wide texture to support Left anchor. + gSPWideTextureRectangle(OVERLAY_DISP++, rectLeft << 2, rectTop << 2, rectLeft + width << 2, + rectTop + height << 2, G_TX_RENDERTILE, 0, 0, width_factor, + height_factor); } CLOSE_DISPS(play->state.gfxCtx); } void MapMark_Draw(PlayState* play) { - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - MapMark_DrawForDungeon(play); - break; + if (SceneDB_IsDungeon(play->sceneNum) || SceneDB_IsBoss(play->sceneNum)) { + MapMark_DrawForDungeon(play); } } diff --git a/soh/src/code/z_message_PAL.c b/soh/src/code/z_message_PAL.c index e6b944a739c..e910d7545e9 100644 --- a/soh/src/code/z_message_PAL.c +++ b/soh/src/code/z_message_PAL.c @@ -2609,7 +2609,7 @@ void Message_DrawMain(PlayState* play, Gfx** p) { if (msgCtx->lastPlayedSong < OCARINA_SONG_SARIAS && (msgCtx->ocarinaAction < OCARINA_ACTION_PLAYBACK_MINUET || msgCtx->ocarinaAction >= OCARINA_ACTION_PLAYBACK_SARIA)) { - if (msgCtx->disableWarpSongs || (interfaceCtx->restrictions.warpSongs == 3 && !IS_RANDO)) { + if (msgCtx->disableWarpSongs || (interfaceCtx->restrictions.warpSongs && !IS_RANDO)) { Message_StartTextbox(play, 0x88C, NULL); // "You can't warp here!" play->msgCtx.ocarinaMode = OCARINA_MODE_04; } else if ((gSaveContext.eventInf[0] & 0xF) != 1) { diff --git a/soh/src/code/z_parameter.c b/soh/src/code/z_parameter.c index d2c3e1a26b5..5f07e4ae390 100644 --- a/soh/src/code/z_parameter.c +++ b/soh/src/code/z_parameter.c @@ -8,6 +8,7 @@ #include "soh/Enhancements/randomizer/randomizer_entrance.h" #include "libultraship/bridge.h" +#include "soh/SceneDB.h" #include "soh/Enhancements/gameplaystats.h" #include "soh/Enhancements/boss-rush/BossRushTypes.h" #include "soh/Enhancements/custom-message/CustomMessageInterfaceAddon.h" @@ -1082,7 +1083,7 @@ void func_80083108(PlayState* play) { Interface_ChangeAlpha(50); } else { - if (interfaceCtx->restrictions.bButton == 0) { + if (!interfaceCtx->restrictions.bButton) { if ((gSaveContext.equips.buttonItems[0] == ITEM_SLINGSHOT) || (gSaveContext.equips.buttonItems[0] == ITEM_BOW) || (gSaveContext.equips.buttonItems[0] == ITEM_BOMBCHU) || @@ -1109,7 +1110,7 @@ void func_80083108(PlayState* play) { gSaveContext.equips.buttonItems[0] = gSaveContext.buttonStatus[0] & 0xFF; } } - } else if (interfaceCtx->restrictions.bButton == 1) { + } else { if ((gSaveContext.equips.buttonItems[0] == ITEM_SLINGSHOT) || (gSaveContext.equips.buttonItems[0] == ITEM_BOW) || (gSaveContext.equips.buttonItems[0] == ITEM_BOMBCHU) || @@ -1147,7 +1148,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.bottles != 0) { + if (interfaceCtx->restrictions.bottles) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) && (gSaveContext.equips.buttonItems[i] <= ITEM_POE)) { @@ -1158,7 +1159,7 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_DISABLED; } } - } else if (interfaceCtx->restrictions.bottles == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] >= ITEM_BOTTLE) && (gSaveContext.equips.buttonItems[i] <= ITEM_POE)) { @@ -1171,7 +1172,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.tradeItems != 0) { + if (interfaceCtx->restrictions.tradeItems) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((CVarGetInteger(CVAR_ENHANCEMENT("MMBunnyHood"), BUNNY_HOOD_VANILLA) != BUNNY_HOOD_VANILLA) && (gSaveContext.equips.buttonItems[i] >= ITEM_MASK_KEATON) @@ -1186,7 +1187,7 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_DISABLED; } } - } else if (interfaceCtx->restrictions.tradeItems == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK)) { @@ -1199,7 +1200,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.hookshot != 0) { + if (interfaceCtx->restrictions.hookshot) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_HOOKSHOT) || (gSaveContext.equips.buttonItems[i] == ITEM_LONGSHOT)) { @@ -1210,7 +1211,7 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_DISABLED; } } - } else if (interfaceCtx->restrictions.hookshot == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_HOOKSHOT) || (gSaveContext.equips.buttonItems[i] == ITEM_LONGSHOT)) { @@ -1223,7 +1224,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.ocarina != 0) { + if (interfaceCtx->restrictions.ocarina) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_OCARINA_FAIRY) || (gSaveContext.equips.buttonItems[i] == ITEM_OCARINA_TIME)) { @@ -1234,7 +1235,7 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_DISABLED; } } - } else if (interfaceCtx->restrictions.ocarina == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_OCARINA_FAIRY) || (gSaveContext.equips.buttonItems[i] == ITEM_OCARINA_TIME)) { @@ -1247,7 +1248,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.farores != 0) { + if (interfaceCtx->restrictions.farores) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (gSaveContext.equips.buttonItems[i] == ITEM_FARORES_WIND) { if (gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] == BTN_ENABLED) { @@ -1258,7 +1259,7 @@ void func_80083108(PlayState* play) { osSyncPrintf("***(i=%d)*** ", i); } } - } else if (interfaceCtx->restrictions.farores == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if (gSaveContext.equips.buttonItems[i] == ITEM_FARORES_WIND) { if (gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] == BTN_DISABLED) { @@ -1270,7 +1271,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.dinsNayrus != 0) { + if (interfaceCtx->restrictions.dinsNayrus) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_DINS_FIRE) || (gSaveContext.equips.buttonItems[i] == ITEM_NAYRUS_LOVE)) { @@ -1281,7 +1282,7 @@ void func_80083108(PlayState* play) { gSaveContext.buttonStatus[BUTTON_STATUS_INDEX(i)] = BTN_DISABLED; } } - } else if (interfaceCtx->restrictions.dinsNayrus == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] == ITEM_DINS_FIRE) || (gSaveContext.equips.buttonItems[i] == ITEM_NAYRUS_LOVE)) { @@ -1294,7 +1295,7 @@ void func_80083108(PlayState* play) { } } - if (interfaceCtx->restrictions.all != 0) { + if (interfaceCtx->restrictions.all) { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] != ITEM_OCARINA_FAIRY) && (gSaveContext.equips.buttonItems[i] != ITEM_OCARINA_TIME) && @@ -1320,7 +1321,7 @@ void func_80083108(PlayState* play) { } } } - } else if (interfaceCtx->restrictions.all == 0) { + } else { for (i = 1; i < ARRAY_COUNT(gSaveContext.equips.buttonItems); i++) { if ((gSaveContext.equips.buttonItems[i] != ITEM_DINS_FIRE) && (gSaveContext.equips.buttonItems[i] != ITEM_HOOKSHOT) && @@ -1358,61 +1359,26 @@ void func_80083108(PlayState* play) { void Interface_SetSceneRestrictions(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; - s16 i; - u8 currentScene; - - // clang-format off - interfaceCtx->restrictions.hGauge = interfaceCtx->restrictions.bButton = - interfaceCtx->restrictions.aButton = interfaceCtx->restrictions.bottles = - interfaceCtx->restrictions.tradeItems = interfaceCtx->restrictions.hookshot = - interfaceCtx->restrictions.ocarina = interfaceCtx->restrictions.warpSongs = - interfaceCtx->restrictions.sunsSong = interfaceCtx->restrictions.farores = - interfaceCtx->restrictions.dinsNayrus = interfaceCtx->restrictions.all = 0; - // clang-format on - i = 0; - - // "Data settings related to button display scene_data_ID=%d\n" - osSyncPrintf("ボタン表示関係データ設定 scene_data_ID=%d\n", play->sceneNum); - - do { - currentScene = (u8)play->sceneNum; - if (sRestrictionFlags[i].scene == currentScene) { - interfaceCtx->restrictions.hGauge = (sRestrictionFlags[i].flags1 & 0xC0) >> 6; - interfaceCtx->restrictions.bButton = (sRestrictionFlags[i].flags1 & 0x30) >> 4; - interfaceCtx->restrictions.aButton = (sRestrictionFlags[i].flags1 & 0x0C) >> 2; - interfaceCtx->restrictions.bottles = (sRestrictionFlags[i].flags1 & 0x03) >> 0; - interfaceCtx->restrictions.tradeItems = (sRestrictionFlags[i].flags2 & 0xC0) >> 6; - interfaceCtx->restrictions.hookshot = (sRestrictionFlags[i].flags2 & 0x30) >> 4; - interfaceCtx->restrictions.ocarina = (sRestrictionFlags[i].flags2 & 0x0C) >> 2; - interfaceCtx->restrictions.warpSongs = (sRestrictionFlags[i].flags2 & 0x03) >> 0; - interfaceCtx->restrictions.sunsSong = (sRestrictionFlags[i].flags3 & 0xC0) >> 6; - interfaceCtx->restrictions.farores = (sRestrictionFlags[i].flags3 & 0x30) >> 4; - interfaceCtx->restrictions.dinsNayrus = (sRestrictionFlags[i].flags3 & 0x0C) >> 2; - interfaceCtx->restrictions.all = (sRestrictionFlags[i].flags3 & 0x03) >> 0; - - osSyncPrintf(VT_FGCOL(YELLOW)); - osSyncPrintf("parameter->button_status = %x,%x,%x\n", sRestrictionFlags[i].flags1, - sRestrictionFlags[i].flags2, sRestrictionFlags[i].flags3); - osSyncPrintf("h_gage=%d, b_button=%d, a_button=%d, c_bottle=%d\n", interfaceCtx->restrictions.hGauge, - interfaceCtx->restrictions.bButton, interfaceCtx->restrictions.aButton, - interfaceCtx->restrictions.bottles); - osSyncPrintf("c_warasibe=%d, c_hook=%d, c_ocarina=%d, c_warp=%d\n", interfaceCtx->restrictions.tradeItems, - interfaceCtx->restrictions.hookshot, interfaceCtx->restrictions.ocarina, - interfaceCtx->restrictions.warpSongs); - osSyncPrintf("c_sunmoon=%d, m_wind=%d, m_magic=%d, another=%d\n", interfaceCtx->restrictions.sunsSong, - interfaceCtx->restrictions.farores, interfaceCtx->restrictions.dinsNayrus, - interfaceCtx->restrictions.all); - osSyncPrintf(VT_RST); - if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { - if (currentScene == SCENE_GERUDO_TRAINING_GROUND || currentScene == SCENE_INSIDE_GANONS_CASTLE) { - interfaceCtx->restrictions.farores = 0; - } - } - return; + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); + interfaceCtx->restrictions.hGauge = entry->restrictions.hGauge; + interfaceCtx->restrictions.bButton = entry->restrictions.bButton; + interfaceCtx->restrictions.aButton = entry->restrictions.aButton; + interfaceCtx->restrictions.bottles = entry->restrictions.bottles; + interfaceCtx->restrictions.tradeItems = entry->restrictions.tradeItems; + interfaceCtx->restrictions.hookshot = entry->restrictions.hookshot; + interfaceCtx->restrictions.ocarina = entry->restrictions.ocarina; + interfaceCtx->restrictions.warpSongs = entry->restrictions.warpSongs; + interfaceCtx->restrictions.sunsSong = entry->restrictions.sunsSong; + interfaceCtx->restrictions.farores = entry->restrictions.farores; + interfaceCtx->restrictions.dinsNayrus = entry->restrictions.dinsNayrus; + interfaceCtx->restrictions.all = entry->restrictions.all; + + if (CVarGetInteger(CVAR_ENHANCEMENT("BetterFarore"), 0)) { + if (play->sceneNum == SCENE_GERUDO_TRAINING_GROUND || play->sceneNum == SCENE_INSIDE_GANONS_CASTLE) { + interfaceCtx->restrictions.farores = 0; } - i++; - } while (sRestrictionFlags[i].scene != 0xFF); + } } Gfx* Gfx_TextureIA8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop, @@ -1439,6 +1405,140 @@ Gfx* Gfx_TextureI8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 te return displayListHead; } +void Inventory_DoBA(u8 cRight) { + if (cRight >= ITEM_STICK && cRight <= ITEM_POTION_BLUE) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.items[cRight]; + } else if (cRight >= ITEM_FAIRY && cRight <= ITEM_MASK_BUNNY) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.ammo[cRight - ITEM_FAIRY]; + } else if (cRight == ITEM_MASK_GORON) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.equipment >> 8) & 0xFF; + } else if (cRight == ITEM_MASK_ZORA) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.equipment & 0xFF; + } else if (cRight == ITEM_MASK_GERUDO || cRight == ITEM_MASK_TRUTH) { + // ITEM_MASK_GERUDO and ITEM_MASK_TRUTH land in padding bytes + gSaveContext.equips.buttonItems[0] = 0; + } else if (cRight == ITEM_SOLD_OUT) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 24) & 0xFF; + } else if (cRight == ITEM_POCKET_EGG) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 16) & 0xFF; + } else if (cRight == ITEM_POCKET_CUCCO) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.upgrades >> 8) & 0xFF; + } else if (cRight == ITEM_COJIRO) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.upgrades & 0xFF; + } else if (cRight == ITEM_ODD_MUSHROOM) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 24) & 0xFF; + } else if (cRight == ITEM_ODD_POTION) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 16) & 0xFF; + } else if (cRight == ITEM_SAW) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.questItems >> 8) & 0xFF; + } else if (cRight == ITEM_SWORD_BROKEN) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.questItems & 0xFF; + } else if (cRight >= ITEM_PRESCRIPTION && cRight <= ITEM_BULLET_BAG_30) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.dungeonItems[cRight - ITEM_PRESCRIPTION]; + } else if (cRight >= ITEM_BULLET_BAG_40 && cRight <= ITEM_SWORD_KNIFE) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.dungeonKeys[cRight - ITEM_BULLET_BAG_40]; + } else if (cRight == ITEM_SONG_BOLERO) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.defenseHearts; + } else if (cRight == ITEM_SONG_SERENADE) { + gSaveContext.equips.buttonItems[0] = (gSaveContext.inventory.gsTokens >> 8) & 0xFF; + } else if (cRight == ITEM_SONG_REQUIEM) { + gSaveContext.equips.buttonItems[0] = gSaveContext.inventory.gsTokens & 0xFF; + } else if (cRight == ITEM_SONG_NOCTURNE || cRight == ITEM_SONG_PRELUDE) { + // ITEM_SONG_NOCTURNE and ITEM_SONG_PRELUDE land in padding bytes + gSaveContext.equips.buttonItems[0] = 0; + } else if (cRight >= ITEM_SONG_LULLABY) { + // The rest of the items fall into the saved scene flags. Let's calculate the scene and which field it pulls from + u32 offset = cRight - ITEM_SONG_LULLABY; + u32 scene = offset / sizeof(SavedSceneFlags); + switch (offset % sizeof(SavedSceneFlags)) { + case 0: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 24) & 0xFF; + break; + case 1: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 16) & 0xFF; + break; + case 2: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].chest >> 8) & 0xFF; + break; + case 3: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].chest & 0xFF; + break; + case 4: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 24) & 0xFF; + break; + case 5: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 16) & 0xFF; + break; + case 6: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].swch >> 8) & 0xFF; + break; + case 7: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].swch & 0xFF; + break; + case 8: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 24) & 0xFF; + break; + case 9: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 16) & 0xFF; + break; + case 10: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].clear >> 8) & 0xFF; + break; + case 11: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].clear & 0xFF; + break; + case 12: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 24) & 0xFF; + break; + case 13: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 16) & 0xFF; + break; + case 14: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].collect >> 8) & 0xFF; + break; + case 15: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].collect & 0xFF; + break; + case 16: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 24) & 0xFF; + break; + case 17: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 16) & 0xFF; + break; + case 18: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].unk >> 8) & 0xFF; + break; + case 19: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].unk & 0xFF; + break; + case 20: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 24) & 0xFF; + break; + case 21: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 16) & 0xFF; + break; + case 22: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].rooms >> 8) & 0xFF; + break; + case 23: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].rooms & 0xFF; + break; + case 24: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 24) & 0xFF; + break; + case 25: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 16) & 0xFF; + break; + case 26: + gSaveContext.equips.buttonItems[0] = (gSaveContext.sceneFlags[scene].floors >> 8) & 0xFF; + break; + case 27: + gSaveContext.equips.buttonItems[0] = gSaveContext.sceneFlags[scene].floors & 0xFF; + break; + } + } +} + void Rando_Inventory_SwapAgeEquipment(void) { s16 i; u16 shieldEquipValue; @@ -1518,8 +1618,13 @@ void Rando_Inventory_SwapAgeEquipment(void) { (gSaveContext.equips.buttonItems[i] <= ITEM_POE)) || ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) { - gSaveContext.equips.buttonItems[i] = - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + if (i == 0) { + // If bottle is on B, it triggers BA, which we need to recreate + Inventory_DoBA(gSaveContext.equips.buttonItems[3]); + } else { + gSaveContext.equips.buttonItems[i] = + gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + } } } @@ -1675,8 +1780,13 @@ void Inventory_SwapAgeEquipment(void) { ((gSaveContext.equips.buttonItems[i] >= ITEM_WEIRD_EGG) && (gSaveContext.equips.buttonItems[i] <= ITEM_CLAIM_CHECK))) { osSyncPrintf("Register_Item_Pt(%d)=%d\n", i, gSaveContext.equips.cButtonSlots[i - 1]); - gSaveContext.equips.buttonItems[i] = - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + if (i == 0) { + // If bottle is on B, it triggers BA, which we need to recreate + Inventory_DoBA(gSaveContext.equips.buttonItems[3]); + } else { + gSaveContext.equips.buttonItems[i] = + gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[i - 1]]; + } } } @@ -2699,11 +2809,136 @@ s32 Inventory_HasSpecificBottle(u8 bottleItem) { } } -void byteSwapInventory() { - gSaveContext.inventory.equipment = BE16SWAP(gSaveContext.inventory.equipment); - gSaveContext.inventory.upgrades = BE32SWAP(gSaveContext.inventory.upgrades); - gSaveContext.inventory.questItems = BE32SWAP(gSaveContext.inventory.questItems); - gSaveContext.inventory.gsTokens = BE16SWAP(gSaveContext.inventory.gsTokens); +void Inventory_DoRBA(u8 cRight, u8 item) { + if (cRight >= ITEM_STICK && cRight <= ITEM_POTION_BLUE) { + gSaveContext.inventory.items[cRight] = item; + } else if (cRight >= ITEM_FAIRY && cRight <= ITEM_MASK_BUNNY) { + gSaveContext.inventory.ammo[cRight - ITEM_FAIRY] = item; + } else if (cRight == ITEM_MASK_GORON) { + gSaveContext.inventory.equipment = (item << 8) | (gSaveContext.inventory.equipment & 0x00FF); + } else if (cRight == ITEM_MASK_ZORA) { + gSaveContext.inventory.equipment = item | (gSaveContext.inventory.equipment & 0xFF00); + } + // ITEM_MASK_GERUDO and ITEM_MASK_TRUTH land in padding bytes + else if (cRight == ITEM_SOLD_OUT) { + gSaveContext.inventory.upgrades = (item << 24) | (gSaveContext.inventory.upgrades & 0x00FFFFFF); + } else if (cRight == ITEM_POCKET_EGG) { + gSaveContext.inventory.upgrades = (item << 16) | (gSaveContext.inventory.upgrades & 0xFF00FFFF); + } else if (cRight == ITEM_POCKET_CUCCO) { + gSaveContext.inventory.upgrades = (item << 8) | (gSaveContext.inventory.upgrades & 0xFFFF00FF); + } else if (cRight == ITEM_COJIRO) { + gSaveContext.inventory.upgrades = item | (gSaveContext.inventory.upgrades & 0xFFFFFF00); + } else if (cRight == ITEM_ODD_MUSHROOM) { + gSaveContext.inventory.questItems = (item << 24) | (gSaveContext.inventory.questItems & 0x00FFFFFF); + } else if (cRight == ITEM_ODD_POTION) { + gSaveContext.inventory.questItems = (item << 16) | (gSaveContext.inventory.questItems & 0xFF00FFFF); + } else if (cRight == ITEM_SAW) { + gSaveContext.inventory.questItems = (item << 8) | (gSaveContext.inventory.questItems & 0xFFFF00FF); + } else if (cRight == ITEM_SWORD_BROKEN) { + gSaveContext.inventory.questItems = item | (gSaveContext.inventory.questItems & 0xFFFFFF00); + } else if (cRight >= ITEM_PRESCRIPTION && cRight <= ITEM_BULLET_BAG_30) { + gSaveContext.inventory.dungeonItems[cRight - ITEM_PRESCRIPTION] = item; + } else if (cRight >= ITEM_BULLET_BAG_40 && cRight <= ITEM_SWORD_KNIFE) { + gSaveContext.inventory.dungeonKeys[cRight - ITEM_BULLET_BAG_40] = item; + } else if (cRight == ITEM_SONG_BOLERO) { + gSaveContext.inventory.defenseHearts = item; + } else if (cRight == ITEM_SONG_SERENADE) { + gSaveContext.inventory.gsTokens = (item << 8) | (gSaveContext.inventory.gsTokens & 0x00FF); + } else if (cRight == ITEM_SONG_REQUIEM) { + gSaveContext.inventory.gsTokens = item | (gSaveContext.inventory.gsTokens & 0xFF00); + } + // ITEM_SONG_NOCTURNE and ITEM_SONG_PRELUDE land in padding bytes + else if (cRight >= ITEM_SONG_LULLABY) { + // The rest of the items fall into the saved scene flags. Let's calculate the scene and which field it sets + u32 offset = cRight - ITEM_SONG_LULLABY; + u32 scene = offset / sizeof(SavedSceneFlags); + switch (offset % sizeof(SavedSceneFlags)) { + case 0: + gSaveContext.sceneFlags[scene].chest = (item << 24) | (gSaveContext.sceneFlags[scene].chest & 0x00FFFFFF); + break; + case 1: + gSaveContext.sceneFlags[scene].chest = (item << 16) | (gSaveContext.sceneFlags[scene].chest & 0xFF00FFFF); + break; + case 2: + gSaveContext.sceneFlags[scene].chest = (item << 8) | (gSaveContext.sceneFlags[scene].chest & 0xFFFF00FF); + break; + case 3: + gSaveContext.sceneFlags[scene].chest = item | (gSaveContext.sceneFlags[scene].chest & 0xFFFFFF00); + break; + case 4: + gSaveContext.sceneFlags[scene].swch = (item << 24) | (gSaveContext.sceneFlags[scene].swch & 0x00FFFFFF); + break; + case 5: + gSaveContext.sceneFlags[scene].swch = (item << 16) | (gSaveContext.sceneFlags[scene].swch & 0xFF00FFFF); + break; + case 6: + gSaveContext.sceneFlags[scene].swch = (item << 8) | (gSaveContext.sceneFlags[scene].swch & 0xFFFF00FF); + break; + case 7: + gSaveContext.sceneFlags[scene].swch = item | (gSaveContext.sceneFlags[scene].swch & 0xFFFFFF00); + break; + case 8: + gSaveContext.sceneFlags[scene].clear = (item << 24) | (gSaveContext.sceneFlags[scene].clear & 0x00FFFFFF); + break; + case 9: + gSaveContext.sceneFlags[scene].clear = (item << 16) | (gSaveContext.sceneFlags[scene].clear & 0xFF00FFFF); + break; + case 10: + gSaveContext.sceneFlags[scene].clear = (item << 8) | (gSaveContext.sceneFlags[scene].clear & 0xFFFF00FF); + break; + case 11: + gSaveContext.sceneFlags[scene].clear = item | (gSaveContext.sceneFlags[scene].clear & 0xFFFFFF00); + break; + case 12: + gSaveContext.sceneFlags[scene].collect = (item << 24) | (gSaveContext.sceneFlags[scene].collect & 0x00FFFFFF); + break; + case 13: + gSaveContext.sceneFlags[scene].collect = (item << 16) | (gSaveContext.sceneFlags[scene].collect & 0xFF00FFFF); + break; + case 14: + gSaveContext.sceneFlags[scene].collect = (item << 8) | (gSaveContext.sceneFlags[scene].collect & 0xFFFF00FF); + break; + case 15: + gSaveContext.sceneFlags[scene].collect = item | (gSaveContext.sceneFlags[scene].collect & 0xFFFFFF00); + break; + case 16: + gSaveContext.sceneFlags[scene].unk = (item << 24) | (gSaveContext.sceneFlags[scene].unk & 0x00FFFFFF); + break; + case 17: + gSaveContext.sceneFlags[scene].unk = (item << 16) | (gSaveContext.sceneFlags[scene].unk & 0xFF00FFFF); + break; + case 18: + gSaveContext.sceneFlags[scene].unk = (item << 8) | (gSaveContext.sceneFlags[scene].unk & 0xFFFF00FF); + break; + case 19: + gSaveContext.sceneFlags[scene].unk = item | (gSaveContext.sceneFlags[scene].unk & 0xFFFFFF00); + break; + case 20: + gSaveContext.sceneFlags[scene].rooms = (item << 24) | (gSaveContext.sceneFlags[scene].rooms & 0x00FFFFFF); + break; + case 21: + gSaveContext.sceneFlags[scene].rooms = (item << 16) | (gSaveContext.sceneFlags[scene].rooms & 0xFF00FFFF); + break; + case 22: + gSaveContext.sceneFlags[scene].rooms = (item << 8) | (gSaveContext.sceneFlags[scene].rooms & 0xFFFF00FF); + break; + case 23: + gSaveContext.sceneFlags[scene].rooms = item | (gSaveContext.sceneFlags[scene].rooms & 0xFFFFFF00); + break; + case 24: + gSaveContext.sceneFlags[scene].floors = (item << 24) | (gSaveContext.sceneFlags[scene].floors & 0x00FFFFFF); + break; + case 25: + gSaveContext.sceneFlags[scene].floors = (item << 16) | (gSaveContext.sceneFlags[scene].floors & 0xFF00FFFF); + break; + case 26: + gSaveContext.sceneFlags[scene].floors = (item << 8) | (gSaveContext.sceneFlags[scene].floors & 0xFFFF00FF); + break; + case 27: + gSaveContext.sceneFlags[scene].floors = item | (gSaveContext.sceneFlags[scene].floors & 0xFFFFFF00); + break; + } + } } void Inventory_UpdateBottleItem(PlayState* play, u8 item, u8 button) { @@ -2717,10 +2952,9 @@ void Inventory_UpdateBottleItem(PlayState* play, u8 item, u8 button) { item = ITEM_MILK_HALF; } - if (CVarGetInteger(CVAR_ENHANCEMENT("RestoreRBAValues"),0)) { - byteSwapInventory(); - gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[button - 1]] = item; - byteSwapInventory(); + if (button == 0) { + // If bottle is on B, it triggers RBA, which we need to recreate + Inventory_DoRBA(gSaveContext.equips.buttonItems[3], item); } else { gSaveContext.inventory.items[gSaveContext.equips.cButtonSlots[button - 1]] = item; } @@ -6595,7 +6829,7 @@ void Interface_Update(PlayState* play) { play->msgCtx.ocarinaMode = OCARINA_MODE_04; } } else if ((play->roomCtx.curRoom.behaviorType1 != ROOM_BEHAVIOR_TYPE1_1) && - (interfaceCtx->restrictions.sunsSong != 3)) { + (!interfaceCtx->restrictions.sunsSong)) { if ((gSaveContext.dayTime >= 0x4555) && (gSaveContext.dayTime < 0xC001)) { gSaveContext.nextDayTime = 0; play->transitionType = TRANS_TYPE_FADE_BLACK_FAST; diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 219b3a448d5..c8f563a5c6d 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -14,6 +14,7 @@ #include "soh/OTRGlobals.h" #include "soh/SaveManager.h" #include "soh/framebuffer_effects.h" +#include "soh/SceneDB.h" #include @@ -482,23 +483,20 @@ void Play_Init(GameState* thisx) { // save the base scene layer (before accounting for the special cases below) to use later for the transition type baseSceneLayer = gSaveContext.sceneSetupIndex; - - if ((gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_HYRULE_FIELD) && !LINK_IS_ADULT && - !IS_CUTSCENE_LAYER) { + EntranceDBEntry* entrance = EntranceDB_Retrieve(gSaveContext.entranceIndex); + if ((entrance->sceneId == SCENE_HYRULE_FIELD) && !LINK_IS_ADULT && !IS_CUTSCENE_LAYER) { if (CHECK_QUEST_ITEM(QUEST_KOKIRI_EMERALD) && CHECK_QUEST_ITEM(QUEST_GORON_RUBY) && CHECK_QUEST_ITEM(QUEST_ZORA_SAPPHIRE)) { gSaveContext.sceneSetupIndex = 1; } else { gSaveContext.sceneSetupIndex = 0; } - } else if ((gEntranceTable[((void)0, gSaveContext.entranceIndex)].scene == SCENE_KOKIRI_FOREST) && - LINK_IS_ADULT && !IS_CUTSCENE_LAYER) { + } else if ((entrance->sceneId == SCENE_KOKIRI_FOREST) && LINK_IS_ADULT && !IS_CUTSCENE_LAYER) { gSaveContext.sceneSetupIndex = (Flags_GetEventChkInf(EVENTCHKINF_USED_FOREST_TEMPLE_BLUE_WARP)) ? 3 : 2; } - Play_SpawnScene( - play, gEntranceTable[((void)0, gSaveContext.entranceIndex) + ((void)0, gSaveContext.sceneSetupIndex)].scene, - gEntranceTable[((void)0, gSaveContext.sceneSetupIndex) + ((void)0, gSaveContext.entranceIndex)].spawn); + EntranceDBEntry* adjustedEntrance = EntranceDB_RetrieveLayer(gSaveContext.entranceIndex, gSaveContext.sceneSetupIndex); + Play_SpawnScene(play, adjustedEntrance->sceneId, adjustedEntrance->spawn); osSyncPrintf("\nSCENE_NO=%d COUNTER=%d\n", ((void)0, gSaveContext.entranceIndex), gSaveContext.sceneSetupIndex); @@ -553,8 +551,8 @@ void Play_Init(GameState* thisx) { if (gSaveContext.gameMode != GAMEMODE_TITLE_SCREEN) { if (gSaveContext.nextTransitionType == TRANS_NEXT_TYPE_DEFAULT) { - play->transitionType = ENTRANCE_INFO_END_TRANS_TYPE( - gEntranceTable[((void)0, gSaveContext.entranceIndex) + baseSceneLayer].field); // Fade In + EntranceDBEntry* transEntrance = EntranceDB_RetrieveLayer(gSaveContext.entranceIndex, baseSceneLayer); + play->transitionType = transEntrance->endTransition; // Fade In } else { play->transitionType = gSaveContext.nextTransitionType; gSaveContext.nextTransitionType = TRANS_NEXT_TYPE_DEFAULT; @@ -796,8 +794,7 @@ void Play_Update(PlayState* play) { } // fade out bgm if "continue bgm" flag is not set - if (!(gEntranceTable[play->nextEntranceIndex + sceneLayer].field & - ENTRANCE_INFO_CONTINUE_BGM_FLAG)) { + if (!EntranceDB_RetrieveLayer(play->nextEntranceIndex, sceneLayer)->continueBgm) { // "Sound initalized. 111" osSyncPrintf("\n\n\nサウンドイニシャル来ました。111"); if ((play->transitionType < TRANS_TYPE_MAX) && !Environment_IsForcedSequenceDisabled()) { diff --git a/soh/src/code/z_room.c b/soh/src/code/z_room.c index 2e8cdc655fa..cd8587adf3a 100644 --- a/soh/src/code/z_room.c +++ b/soh/src/code/z_room.c @@ -7,6 +7,7 @@ #include "soh/Enhancements/game-interactor/GameInteractor.h" #include #include +#include #include "public/bridge/gfxbridge.h" #include "soh/OTRGlobals.h" @@ -649,7 +650,7 @@ void func_80097534(PlayState* play, RoomContext* roomCtx) { func_80031B14(play, &play->actorCtx); //kills all actors without room num set to -1 Actor_SpawnTransitionActors(play, &play->actorCtx); Map_InitRoomData(play, roomCtx->curRoom.num); - if (!((play->sceneNum >= SCENE_HYRULE_FIELD) && (play->sceneNum <= SCENE_LON_LON_RANCH))) { + if (!SceneDB_IsOverworld(play->sceneNum)) { Map_SavePlayerInitialInfo(play); } Audio_SetEnvReverb(play->roomCtx.curRoom.echo); diff --git a/soh/src/code/z_scene_table.c b/soh/src/code/z_scene_table.c index c7d76db01ad..64f6af65610 100644 --- a/soh/src/code/z_scene_table.c +++ b/soh/src/code/z_scene_table.c @@ -27,6 +27,7 @@ #include "soh/Enhancements/randomizer/adult_trade_shuffle.h" #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" // Entrance Table definition #define DEFINE_ENTRANCE(_0, sceneId, spawn, continueBgm, displayTitleCard, endTransType, startTransType) \ @@ -88,23 +89,23 @@ Gfx sDefaultDisplayList[] = { // Computes next entrance index based on age and day time to set the fade out transition void Scene_SetTransitionForNextEntrance(PlayState* play) { - s16 entranceIndex; + s16 layer = 0; if (!IS_DAY) { if (!LINK_IS_ADULT) { - entranceIndex = play->nextEntranceIndex + 1; + layer = 1; } else { - entranceIndex = play->nextEntranceIndex + 3; + layer = 3; } } else { if (!LINK_IS_ADULT) { - entranceIndex = play->nextEntranceIndex; + layer = 0; } else { - entranceIndex = play->nextEntranceIndex + 2; + layer = 2; } } - play->transitionType = ENTRANCE_INFO_START_TRANS_TYPE(gEntranceTable[entranceIndex].field); // Fade out + play->transitionType = EntranceDB_RetrieveLayer(play->nextEntranceIndex, layer)->startTransition; // Fade out } // Scene Draw Config 0 diff --git a/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c b/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c index d5d0877a717..4df3b24f301 100644 --- a/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c +++ b/soh/src/overlays/actors/ovl_En_Elf/z_en_elf.c @@ -1421,11 +1421,11 @@ void func_80A053F0(Actor* thisx, PlayState* play) { } else { this->actionFunc(this, play); thisx->shape.rot.y = this->unk_2BC; - nREG(80) = gSaveContext.sceneFlags[127].chest; + nREG(80) = HIGH_SCORE(HS_HBA); if (nREG(81) != 0) { - if (gSaveContext.sceneFlags[127].chest) { - LOG_NUM("z_common_data.memory.information.room_inf[127][ 0 ]", gSaveContext.sceneFlags[127].chest); + if (HIGH_SCORE(HS_HBA)) { + LOG_NUM("z_common_data.memory.information.room_inf[127][ 0 ]", HIGH_SCORE(HS_HBA)); } } diff --git a/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c b/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c index 0940511aca6..01c81f7a8ad 100644 --- a/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c +++ b/soh/src/overlays/actors/ovl_En_Horse/z_en_horse.c @@ -10,6 +10,7 @@ #include "objects/object_hni/object_hni.h" #include "scenes/overworld/spot09/spot09_scene.h" #include +#include "soh/SceneDB.h" #define FLAGS ACTOR_FLAG_UPDATE_WHILE_CULLED @@ -677,34 +678,36 @@ s32 EnHorse_Spawn(EnHorse* this, PlayState* play) { Player* player; Vec3f spawnPos; - for (i = 0; i < 169; i++) { - if (sHorseSpawns[i].scene == play->sceneNum) { - player = GET_PLAYER(play); - if (play->sceneNum != SCENE_LON_LON_RANCH || - //! Same flag checked twice - (Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) && ((gSaveContext.eventInf[0] & 0xF) != 6 || Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED))) || - // always load two spawns inside lon lon - ((sHorseSpawns[i].pos.x == 856 && sHorseSpawns[i].pos.y == 0 && sHorseSpawns[i].pos.z == -918) || - (sHorseSpawns[i].pos.x == -1003 && sHorseSpawns[i].pos.y == 0 && sHorseSpawns[i].pos.z == -755))) { - - spawnPos.x = sHorseSpawns[i].pos.x; - spawnPos.y = sHorseSpawns[i].pos.y; - spawnPos.z = sHorseSpawns[i].pos.z; - dist = Math3D_Vec3f_DistXYZ(&player->actor.world.pos, &spawnPos); - - if (play->sceneNum) {} - if (!(minDist < dist) && !func_80A5BBBC(play, this, &spawnPos)) { - minDist = dist; - this->actor.world.pos.x = sHorseSpawns[i].pos.x; - this->actor.world.pos.y = sHorseSpawns[i].pos.y; - this->actor.world.pos.z = sHorseSpawns[i].pos.z; - this->actor.prevPos = this->actor.world.pos; - this->actor.world.rot.y = sHorseSpawns[i].angle; - this->actor.shape.rot.y = Actor_WorldYawTowardActor(&this->actor, &GET_PLAYER(play)->actor); - spawn = true; - SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &this->actor.world.pos, - &this->actor.projectedPos, &this->actor.projectedW); - } + SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum); + if (!entry->epona.allowed) { + return false; + } + + for (i = 0; i < entry->epona.numSpawns; i++) { + player = GET_PLAYER(play); + if (play->sceneNum != SCENE_LON_LON_RANCH || + //! Same flag checked twice + (Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) && ((gSaveContext.eventInf[0] & 0xF) != 6 || Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED))) || + // always load two spawns inside lon lon + ((entry->epona.spawnPos[i].x == 856 && entry->epona.spawnPos[i].y == 0 && entry->epona.spawnPos[i].z == -918) || + (entry->epona.spawnPos[i].x == -1003 && entry->epona.spawnPos[i].y == 0 && entry->epona.spawnPos[i].z == -755))) { + + spawnPos.x = entry->epona.spawnPos[i].x; + spawnPos.y = entry->epona.spawnPos[i].y; + spawnPos.z = entry->epona.spawnPos[i].z; + dist = Math3D_Vec3f_DistXYZ(&player->actor.world.pos, &spawnPos); + + if (!(minDist < dist) && !func_80A5BBBC(play, this, &spawnPos)) { + minDist = dist; + this->actor.world.pos.x = entry->epona.spawnPos[i].x; + this->actor.world.pos.y = entry->epona.spawnPos[i].y; + this->actor.world.pos.z = entry->epona.spawnPos[i].z; + this->actor.prevPos = this->actor.world.pos; + this->actor.world.rot.y = 0; + this->actor.shape.rot.y = Actor_WorldYawTowardActor(&this->actor, &GET_PLAYER(play)->actor); + spawn = true; + SkinMatrix_Vec3fMtxFMultXYZW(&play->viewProjectionMtxF, &this->actor.world.pos, + &this->actor.projectedPos, &this->actor.projectedW); } } } diff --git a/soh/src/overlays/actors/ovl_player_actor/z_player.c b/soh/src/overlays/actors/ovl_player_actor/z_player.c index 16abaf56841..091cd5afd3f 100644 --- a/soh/src/overlays/actors/ovl_player_actor/z_player.c +++ b/soh/src/overlays/actors/ovl_player_actor/z_player.c @@ -32,6 +32,7 @@ #include "soh/frame_interpolation.h" #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" #include #include @@ -10844,11 +10845,9 @@ void Player_Init(Actor* thisx, PlayState* play2) { } if ((respawnFlag == 0) || (respawnFlag < -1)) { - titleFileSize = scene->titleFile.vromEnd - scene->titleFile.vromStart; if (GameInteractor_Should(VB_SHOW_TITLE_CARD, gSaveContext.showTitleCard)) { if ((gSaveContext.sceneSetupIndex < 4) && - (gEntranceTable[((void)0, gSaveContext.entranceIndex) + ((void)0, gSaveContext.sceneSetupIndex)].field & - ENTRANCE_INFO_DISPLAY_TITLE_CARD_FLAG) && + EntranceDB_RetrieveLayer(gSaveContext.entranceIndex, gSaveContext.sceneSetupIndex)->displayTitleCard && ((play->sceneNum != SCENE_DODONGOS_CAVERN) || (Flags_GetEventChkInf(EVENTCHKINF_ENTERED_DODONGOS_CAVERN))) && ((play->sceneNum != SCENE_BOMBCHU_SHOP) || (Flags_GetEventChkInf(EVENTCHKINF_USED_DODONGOS_CAVERN_BLUE_WARP)))) { TitleCard_InitPlaceName(play, &play->actorCtx.titleCtx, this->giObjectSegment, 160, 120, 144, diff --git a/soh/src/overlays/gamestates/ovl_select/z_select.c b/soh/src/overlays/gamestates/ovl_select/z_select.c index 6d826dd619a..96c632d5fec 100644 --- a/soh/src/overlays/gamestates/ovl_select/z_select.c +++ b/soh/src/overlays/gamestates/ovl_select/z_select.c @@ -13,6 +13,7 @@ #include "soh/Enhancements/randomizer/randomizer_grotto.h" #include "soh/OTRGlobals.h" #include "soh/ResourceManagerHelpers.h" +#include "soh/SceneDB.h" void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode); void Sram_InitDebugSave(void); @@ -56,7 +57,7 @@ void Select_LoadGame(SelectContext* this, s32 entranceIndex) { BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; // Check to see if the scene/entrance we just picked can be MQ'd if (entrancePair.canBeMQ) { - s16 scene = gEntranceTable[entrancePair.entranceIndex].scene; + s16 scene = EntranceDB_Retrieve(entrancePair.entranceIndex)->sceneId; u8 isEntranceDefaultMQ = ResourceMgr_IsSceneMasterQuest(scene); if (!isEntranceDefaultMQ && this->opt) { // Force vanilla for default MQ scene CVarSetInteger(CVAR_GENERAL("BetterDebugWarpScreenMQMode"), WARP_MODE_OVERRIDE_MQ_AS_VANILLA); @@ -1033,7 +1034,7 @@ void Better_Select_UpdateMenu(SelectContext* this) { if (sceneChanged) { BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; // Update the MQ status to match the new scene - if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene)) { + if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(EntranceDB_Retrieve(entrancePair.entranceIndex)->sceneId)) { this->opt = 1; } else { this->opt = 0; @@ -1575,7 +1576,7 @@ void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode) { this->pageDownIndex = CVarGetInteger(CVAR_GENERAL("BetterDebugWarpScreenPageDownIndex"), 0); BetterSceneSelectEntrancePair entrancePair = this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex]; - if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene)) { + if (entrancePair.canBeMQ && ResourceMgr_IsSceneMasterQuest(EntranceDB_Retrieve(entrancePair.entranceIndex)->sceneId)) { this->opt = 1; } } diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c index 0730f6b124b..6f9c2c677ed 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_map_PAL.c @@ -1,4 +1,5 @@ #include "z_kaleido_scope.h" +#include "soh/SceneDB.h" #include "textures/icon_item_24_static/icon_item_24_static.h" #include "textures/icon_item_nes_static/icon_item_nes_static.h" #include "textures/icon_item_ger_static/icon_item_ger_static.h" @@ -55,6 +56,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { s16 stepB; u16 rgba16; bool dpad = CVarGetInteger(CVAR_SETTING("DPadOnPause"), 0); + SceneDBEntry* entry = SceneDB_Retrieve(gSaveContext.mapIndex); OPEN_DISPS(gfxCtx); @@ -86,9 +88,6 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->cursorX[PAUSE_MAP] = 0; pauseCtx->cursorPoint[PAUSE_MAP] = pauseCtx->dungeonMapSlot; osSyncPrintf("kscope->cursor_point=%d\n", pauseCtx->cursorPoint[PAUSE_MAP]); - R_MAP_TEX_INDEX = - R_MAP_TEX_INDEX_BASE + - gMapData->floorTexIndexOffset[gSaveContext.mapIndex][pauseCtx->cursorPoint[PAUSE_MAP] - 3]; KaleidoScope_UpdateDungeonMap(play); } } @@ -116,12 +115,13 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { } } } else { + s16 oldFloor = pauseCtx->dungeonMapSlot; if ((pauseCtx->stickRelY > 30) || (dpad && CHECK_BTN_ALL(input->press.button, BTN_DUP))) { if (pauseCtx->cursorPoint[PAUSE_MAP] >= 4) { for (i = pauseCtx->cursorPoint[PAUSE_MAP] - 3 - 1; i >= 0; i--) { if ((gSaveContext.sceneFlags[gSaveContext.mapIndex].floors & gBitFlags[i]) || (CHECK_DUNGEON_ITEM(DUNGEON_MAP, gSaveContext.mapIndex) && - (gMapData->floorID[interfaceCtx->unk_25A][i] != 0))) { + (entry->dungeonData.floors[i].id != F_NA))) { pauseCtx->cursorPoint[PAUSE_MAP] = i + 3; break; } @@ -132,20 +132,15 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { for (i = pauseCtx->cursorPoint[PAUSE_MAP] - 3 + 1; i < 11; i++) { if ((gSaveContext.sceneFlags[gSaveContext.mapIndex].floors & gBitFlags[i]) || (CHECK_DUNGEON_ITEM(DUNGEON_MAP, gSaveContext.mapIndex) && - (gMapData->floorID[interfaceCtx->unk_25A][i] != 0))) { + (entry->dungeonData.floors[i].id != F_NA))) { pauseCtx->cursorPoint[PAUSE_MAP] = i + 3; break; } } } } - - i = R_MAP_TEX_INDEX; - R_MAP_TEX_INDEX = - R_MAP_TEX_INDEX_BASE + - gMapData->floorTexIndexOffset[gSaveContext.mapIndex][pauseCtx->cursorPoint[PAUSE_MAP] - 3]; pauseCtx->dungeonMapSlot = pauseCtx->cursorPoint[PAUSE_MAP]; - if (i != R_MAP_TEX_INDEX) { + if (pauseCtx->dungeonMapSlot != oldFloor) { KaleidoScope_UpdateDungeonMap(play); } } @@ -173,10 +168,6 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { pauseCtx->cursorX[PAUSE_MAP] = 0; pauseCtx->cursorSlot[PAUSE_MAP] = pauseCtx->cursorPoint[PAUSE_MAP] = pauseCtx->dungeonMapSlot; - R_MAP_TEX_INDEX = - R_MAP_TEX_INDEX_BASE + - gMapData - ->floorTexIndexOffset[gSaveContext.mapIndex][pauseCtx->cursorPoint[PAUSE_MAP] - 3]; KaleidoScope_UpdateDungeonMap(play); } } @@ -255,7 +246,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { if ((gSaveContext.sceneFlags[gSaveContext.mapIndex].floors & gBitFlags[i]) || CHECK_DUNGEON_ITEM(DUNGEON_MAP, gSaveContext.mapIndex)) { if (i != (pauseCtx->dungeonMapSlot - 3)) { - gDPLoadTextureBlock(POLY_KAL_DISP++, floorIconTexs[gMapData->floorID[interfaceCtx->unk_25A][i]], + gDPLoadTextureBlock(POLY_KAL_DISP++, floorIconTexs[entry->dungeonData.floors[i].id], G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); @@ -270,7 +261,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 150, 150, 255, pauseCtx->alpha); gDPLoadTextureBlock(POLY_KAL_DISP++, - floorIconTexs[gMapData->floorID[interfaceCtx->unk_25A][pauseCtx->dungeonMapSlot - 3]], + floorIconTexs[entry->dungeonData.floors[pauseCtx->dungeonMapSlot - 3].id], G_IM_FMT_IA, G_IM_SIZ_8b, 24, 16, 0, G_TX_WRAP | G_TX_NOMIRROR, G_TX_WRAP | G_TX_NOMIRROR, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); @@ -296,9 +287,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) { gSP1Quadrangle(POLY_KAL_DISP++, 0, 2, 3, 1, 0); if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, gSaveContext.mapIndex) && - (gMapData->skullFloorIconY[gSaveContext.mapIndex] != -99)) { - pauseCtx->mapPageVtx[120].v.ob[1] = pauseCtx->mapPageVtx[121].v.ob[1] = - gMapData->skullFloorIconY[gSaveContext.mapIndex] + pauseCtx->offsetY; + (entry->dungeonData.bossFloor != -1)) { + s16 skullFloorIconY = 51 - 14 * entry->dungeonData.bossFloor; + pauseCtx->mapPageVtx[120].v.ob[1] = pauseCtx->mapPageVtx[121].v.ob[1] = skullFloorIconY + pauseCtx->offsetY; pauseCtx->mapPageVtx[122].v.ob[1] = pauseCtx->mapPageVtx[123].v.ob[1] = pauseCtx->mapPageVtx[120].v.ob[1] - 16; gDPLoadTextureBlock(POLY_KAL_DISP++, gDungeonMapSkullTex, G_IM_FMT_RGBA, G_IM_SIZ_16b, 16, 16, 0, diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c index 217ec24e3fa..261065a0d7f 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_kaleido_scope_PAL.c @@ -22,6 +22,7 @@ #include "soh/ResourceManagerHelpers.h" #include "soh/SaveManager.h" #include "soh/Enhancements/kaleido.h" +#include "soh/SceneDB.h" static void* sEquipmentFRATexs[] = { @@ -3417,6 +3418,7 @@ static uint8_t mapBlendMask[MAP_48x85_TEX_WIDTH * MAP_48x85_TEX_HEIGHT]; // SoH [General] - Modified to account for our resource system and HD textures void KaleidoScope_LoadDungeonMap(PlayState* play) { InterfaceContext* interfaceCtx = &play->interfaceCtx; + SceneDBEntry* entry = SceneDB_Retrieve(gSaveContext.mapIndex); // Free old textures if (mapLeftTexModifiedRaw != NULL) { @@ -3428,12 +3430,13 @@ void KaleidoScope_LoadDungeonMap(PlayState* play) { mapRightTexModifiedRaw = NULL; } + s16 floor = play->pauseCtx.cursorPoint[PAUSE_MAP] - 3; // Unload original textures to bypass cache result for lookups - ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX]); - ResourceMgr_UnloadOriginalWhenAltExists(sDungeonMapTexs[R_MAP_TEX_INDEX + 1]); + ResourceMgr_UnloadOriginalWhenAltExists(entry->dungeonData.floors[floor].mapLeftTexture); + ResourceMgr_UnloadOriginalWhenAltExists(entry->dungeonData.floors[floor].mapRightTexture); - interfaceCtx->mapSegmentName[0] = sDungeonMapTexs[R_MAP_TEX_INDEX]; - interfaceCtx->mapSegmentName[1] = sDungeonMapTexs[R_MAP_TEX_INDEX + 1]; + interfaceCtx->mapSegmentName[0] = entry->dungeonData.floors[floor].mapLeftTexture; + interfaceCtx->mapSegmentName[1] = entry->dungeonData.floors[floor].mapRightTexture; // When the texture is HD (raw) we need to copy a dynamic amount of data // Otherwise the original asset has a static size diff --git a/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark.c b/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark.c index f884d5a2845..65b1154d729 100644 --- a/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark.c +++ b/soh/src/overlays/misc/ovl_kaleido_scope/z_lmap_mark.c @@ -1,4 +1,5 @@ #include "z_kaleido_scope.h" +#include "soh/SceneDB.h" #include "textures/parameter_static/parameter_static.h" #include "soh/ResourceManagerHelpers.h" @@ -36,14 +37,21 @@ static const u32 sLineBytesImageSizes[] = { 0, 1, 2, 2 }; extern PauseMapMarksData gPauseMapMarkDataTable[]; extern PauseMapMarksData gPauseMapMarkDataTableMasterQuest[]; +static const Vtx sMarkBossVtx[] = { + VTX(-4, 4, 0, 0, 0, 255, 255, 255, 255), + VTX(-4, -4, 0, 0, 256, 255, 255, 255, 255), + VTX(4, 4, 0, 256, 0, 255, 255, 255, 255), + VTX(4, -4, 0, 256, 256, 255, 255, 255, 255), +}; + +static const Vtx sMarkChestVtx[] = { + VTX(-4, 4, 0, 0, 0, 255, 255, 255, 255), + VTX(-4, -4, 0, 0, 256, 255, 255, 255, 255), + VTX(4, 4, 0, 256, 0, 255, 255, 255, 255), + VTX(4, -4, 0, 256, 256, 255, 255, 255, 255), +}; + void PauseMapMark_Init(PlayState* play) { - gBossMarkState = 0; - gBossMarkScale = 1.0f; - if(ResourceMgr_IsGameMasterQuest()) { - gLoadedPauseMarkDataTable = gPauseMapMarkDataTableMasterQuest; - } else { - gLoadedPauseMarkDataTable = gPauseMapMarkDataTable; - } } void PauseMapMark_Clear(PlayState* play) { @@ -56,122 +64,98 @@ void PauseMapMark_DrawForDungeon(PlayState* play) { PauseMapMarkInfo* markInfo; f32 scale; s32 i = 0; - - mapMarkData = &gLoadedPauseMarkDataTable[R_MAP_TEX_INDEX >> 1][i]; - - OPEN_DISPS(play->state.gfxCtx); - - while (true) { - if (mapMarkData->markType == PAUSE_MAP_MARK_NONE) { - break; - } - - if ((mapMarkData->markType == PAUSE_MAP_MARK_BOSS) && (play->sceneNum >= SCENE_DEKU_TREE_BOSS) && - (play->sceneNum <= SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR)) { - if (gBossMarkState == 0) { - Math_ApproachF(&gBossMarkScale, 1.5f, 1.0f, 0.041f); - if (gBossMarkScale == 1.5f) { - gBossMarkState = 1; - } - } else { - Math_ApproachF(&gBossMarkScale, 1.0f, 1.0f, 0.041f); - if (gBossMarkScale == 1.0f) { - gBossMarkState = 0; - } + SceneDBEntry* entry = SceneDB_Retrieve(gSaveContext.mapIndex); + SceneDBFloor* floor = &entry->dungeonData.floors[play->pauseCtx.dungeonMapSlot - 3]; + + if (SceneDB_IsBoss(play->sceneNum)) { + if (gBossMarkState == 0) { + Math_ApproachF(&gBossMarkScale, 1.5f, 1.0f, 0.041f); + if (gBossMarkScale == 1.5f) { + gBossMarkState = 1; } - scale = gBossMarkScale; } else { - scale = 1.0f; + Math_ApproachF(&gBossMarkScale, 1.0f, 1.0f, 0.041f); + if (gBossMarkScale == 1.0f) { + gBossMarkState = 0; + } } + scale = gBossMarkScale; + } else { + scale = 1.0f; + } - Matrix_Push(); + OPEN_DISPS(play->state.gfxCtx); - if ((play->pauseCtx.state == 4) || (play->pauseCtx.state >= 0x12)) { - Matrix_Translate(-36.0f, 101.0f, 0.0f, MTXMODE_APPLY); - } else { - Matrix_Translate(-36.0f, 21.0f, 0.0f, MTXMODE_APPLY); - } + gDPPipeSync(POLY_KAL_DISP++); + gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); + gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 255); - gDPPipeSync(POLY_KAL_DISP++); - gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255); - gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 255); - - markPoint = &mapMarkData->points[0]; - for (i = 0; i < mapMarkData->count; i++) { - s32 display; - - if (mapMarkData->markType == PAUSE_MAP_MARK_CHEST) { - if (Flags_GetTreasure(play, markPoint->chestFlag)) { - display = false; - } else { - switch (play->sceneNum) { - case SCENE_DEKU_TREE_BOSS: - case SCENE_DODONGOS_CAVERN_BOSS: - case SCENE_JABU_JABU_BOSS: - case SCENE_FOREST_TEMPLE_BOSS: - case SCENE_FIRE_TEMPLE_BOSS: - case SCENE_WATER_TEMPLE_BOSS: - case SCENE_SPIRIT_TEMPLE_BOSS: - case SCENE_SHADOW_TEMPLE_BOSS: - display = false; - break; - default: - display = true; - break; - } - } - } else { - display = true; - } + Matrix_Push(); - if (display) { - markInfo = &sMapMarkInfoTable[mapMarkData->markType]; + if ((play->pauseCtx.state == 4) || (play->pauseCtx.state >= 0x12)) { + Matrix_Translate(-36.0f, 101.0f, 0.0f, MTXMODE_APPLY); + } else { + Matrix_Translate(-36.0f, 21.0f, 0.0f, MTXMODE_APPLY); + } - gDPPipeSync(POLY_KAL_DISP++); - gDPLoadTextureBlock(POLY_KAL_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK, - markInfo->textureWidth, markInfo->textureHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, - G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + markInfo = &sMapMarkInfoTable[MAP_MARK_CHEST]; + gDPLoadTextureBlock(POLY_KAL_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK, + markInfo->textureWidth, markInfo->textureHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + for (s32 i = 0; i < floor->numChestMarks; i++) { + s32 display; - // Compute the offset to mirror icons over the map center (48) as an axis line - s16 mirrorOffset = CVarGetInteger(CVAR_ENHANCEMENT("MirroredWorld"), 0) ? mirrorOffset = (48 - markPoint->x) * 2 + 1 : 0; + if (Flags_GetTreasure(play, floor->chestMarks[i].chestFlag)) { + display = false; + } else { + display = SceneDB_IsDungeon(play->sceneNum); + } - Matrix_Push(); - Matrix_Translate(GREG(92) + markPoint->x + mirrorOffset, GREG(93) + markPoint->y, 0.0f, MTXMODE_APPLY); - Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); - gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), - G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); - Matrix_Pop(); + if (display) { + // Compute the offset to mirror icons over the map center (48) as an axis line + s16 mirrorOffset = CVarGetInteger("gMirroredWorld", 0) ? mirrorOffset = (48 - floor->chestMarks[i].x) * 2 + 1 : 0; - gSPVertex(POLY_KAL_DISP++, mapMarkData->vtx, mapMarkData->vtxCount, 0); - gSP1Quadrangle(POLY_KAL_DISP++, 1, 3, 2, 0, 0); - } + Matrix_Push(); + Matrix_Translate(GREG(92) + floor->chestMarks[i].x + mirrorOffset, GREG(93) + floor->chestMarks[i].y, 0.0f, MTXMODE_APPLY); + Matrix_Scale(1.0f, 1.0f, 1.0f, MTXMODE_APPLY); + gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); + Matrix_Pop(); - markPoint++; + gSPVertex(POLY_KAL_DISP++, sMarkChestVtx, 4, 0); + gSP1Quadrangle(POLY_KAL_DISP++, 1, 3, 2, 0, 0); } + } + + markInfo = &sMapMarkInfoTable[MAP_MARK_BOSS]; + gDPLoadTextureBlock(POLY_KAL_DISP++, markInfo->texture, markInfo->imageFormat, G_IM_SIZ_MARK, + markInfo->textureWidth, markInfo->textureHeight, 0, G_TX_NOMIRROR | G_TX_WRAP, + G_TX_NOMIRROR | G_TX_WRAP, G_TX_NOMASK, G_TX_NOMASK, G_TX_NOLOD, G_TX_NOLOD); + for (s32 i = 0; i < floor->numBossMarks; i++) { + // Compute the offset to mirror icons over the map center (48) as an axis line + s16 mirrorOffset = CVarGetInteger("gMirroredWorld", 0) ? mirrorOffset = (48 - floor->bossMarks[i].x) * 2 + 1 : 0; - mapMarkData++; + Matrix_Push(); + Matrix_Translate(GREG(92) + floor->bossMarks[i].x + mirrorOffset, GREG(93) + floor->bossMarks[i].y, 0.0f, MTXMODE_APPLY); + Matrix_Scale(scale, scale, scale, MTXMODE_APPLY); + gSPMatrix(POLY_KAL_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), + G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW); Matrix_Pop(); + + gSPVertex(POLY_KAL_DISP++, sMarkBossVtx, 4, 0); + gSP1Quadrangle(POLY_KAL_DISP++, 1, 3, 2, 0, 0); } + Matrix_Pop(); + CLOSE_DISPS(play->state.gfxCtx); } void PauseMapMark_Draw(PlayState* play) { PauseMapMark_Init(play); - switch (play->sceneNum) { - case SCENE_DEKU_TREE: - case SCENE_DODONGOS_CAVERN: - case SCENE_JABU_JABU: - case SCENE_FOREST_TEMPLE: - case SCENE_FIRE_TEMPLE: - case SCENE_WATER_TEMPLE: - case SCENE_SPIRIT_TEMPLE: - case SCENE_SHADOW_TEMPLE: - case SCENE_BOTTOM_OF_THE_WELL: - case SCENE_ICE_CAVERN: - PauseMapMark_DrawForDungeon(play); - break; + if (SceneDB_IsDungeon(play->sceneNum) || (CVarGetInteger(CVAR_ENHANCEMENT("PulsateBossIcon"), 0) != 0 && SceneDB_IsBoss(play->sceneNum))) { + PauseMapMark_DrawForDungeon(play); } PauseMapMark_Clear(play);