This commit is contained in:
rozlette 2024-12-04 23:53:07 -06:00
commit 2c63ae3815
36 changed files with 4634 additions and 991 deletions

View file

@ -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,

View file

@ -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];

View file

@ -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);

View file

@ -1,6 +1,7 @@
#include <libultraship/bridge.h>
#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);

View file

@ -8,6 +8,7 @@
#include <vector>
#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();
}

View file

@ -11,6 +11,7 @@
#include "randomizer_grotto.h"
#include "soh/OTRGlobals.h"
#include "soh/SaveManager.h"
#include "soh/SceneDB.h"
#include <string.h>
#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

View file

@ -1,5 +1,6 @@
#include <libultraship/bridge.h>
#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);

View file

@ -9,13 +9,13 @@
#include <spdlog/fmt/fmt.h>
#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) {

View file

@ -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();

View file

@ -15,6 +15,7 @@
#include "macros.h"
#include <variables.h>
#include <libultraship/libultraship.h>
#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 <fstream>
#include <filesystem>
#include <array>
#include <algorithm>
#include <mutex>
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<u8, 20> 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<u8, 20> 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<uint8_t>(ITEM_NONE));
});
SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i],
static_cast<uint8_t>(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<uint8_t>(ITEM_NONE));
});
SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i],
static_cast<uint8_t>(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<uint8_t>(ITEM_NONE));
});
SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.equips.cButtonSlots), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.equips.cButtonSlots[i], static_cast<uint8_t>(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<int>(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<int>(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;

View file

@ -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<InitFunc> initFuncs;

1173
soh/soh/SceneDB.cpp Normal file

File diff suppressed because it is too large Load diff

367
soh/soh/SceneDB.h Normal file
View file

@ -0,0 +1,367 @@
#pragma once
#include <libultraship/libultra.h>
#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 <string>
#include <unordered_map>
#include <vector>
#include <map>
class SceneDB {
public:
static SceneDB* Instance;
struct Init {
struct FloorInit {
FloorID id = F_NA;
f32 height = 9999.0f;
std::vector<s8> palettes;
std::string mapLeftTexture;
std::string mapRightTexture;
std::vector<PauseMapMarkPoint> chestMarks;
std::vector<PauseMapMarkPoint> bossMarks;
};
struct RoomInit {
s16 compassOffsetX = 0;
s16 compassOffsetY = 0;
std::string minimapTexture;
std::vector<MapMarkPoint> chestMarks;
std::vector<MapMarkPoint> 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<Vec3s> 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<s16> palettes;
std::string nameEngTexture;
std::string nameGerTexture;
std::string nameFraTexture;
std::vector<FloorInit> floors;
std::vector<RoomInit> rooms;
std::vector<IntraRoomTransitionInit> 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<s8> rooms;
std::string mapLeftTexture;
std::string mapRightTexture;
std::vector<PauseMapMarkPoint> chestMarks;
std::vector<PauseMapMarkPoint> bossMarks;
};
struct RoomInfo {
std::string minimapTexture;
std::vector<MapMarkPoint> chestMarks;
std::vector<MapMarkPoint> bossMarks;
};
void SetName(const std::string& newName);
void SetDesc(const std::string& newDesc);
void SetTitleCard(const std::string& newTitleCard);
void SetEponaSpawnPos(const std::vector<Vec3s>& newSpawnPos);
void SetDungeonPalettes(const std::vector<s16>& newDungeonPalettes);
void SetDungeonNameTextures(const std::string& newNameEngTexture, const std::string& newNameGerTexture, const std::string& newNameFraTexture);
void SetDungeonFloors(const std::vector<Init::FloorInit>& newDungeonFloors);
void SetDungeonFloors(const std::vector<SceneDBFloor>& newDungeonFloors, const std::vector<FloorInfo>& newDungeonFloorInfo);
void SetDungeonRooms(const std::vector<Init::RoomInit>& newDungeonRooms);
void SetDungeonRooms(const std::vector<SceneDBRoom>& newDungeonRooms, const std::vector<RoomInfo>& newDungeonRoomInfo);
void SetDungeonIntraRoomTransitions(const std::vector<Init::IntraRoomTransitionInit>& newDungeonIntraRoomTransitions);
void SetDungeonIntraRoomTransitions(const std::vector<SceneDBIntraRoomTransition>& 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<Vec3s> eponaSpawnPos;
std::vector<s16> dungeonPalettes;
std::string nameEngTexture;
std::string nameGerTexture;
std::string nameFraTexture;
std::vector<FloorInfo> dungeonFloorInfo;
std::vector<SceneDBFloor> dungeonFloors;
std::vector<RoomInfo> dungeonRoomInfo;
std::vector<SceneDBRoom> dungeonRooms;
std::vector<SceneDBIntraRoomTransition> 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<Entry> db;
std::unordered_map<std::string, int> 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<Entry> db;
std::unordered_map<std::string, int> 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<IdLookupKey, s32> 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<NextLayerLookupKey, s32> 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

1912
soh/soh/SceneDB_Table.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -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();
}

View file

@ -4,6 +4,7 @@
#include "soh/resource/type/Scene.h"
#include <utils/StringHelper.h>
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/SceneDB.h"
#include "global.h"
#include "vt.h"
#include <Vertex.h>
@ -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);

View file

@ -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;

View file

@ -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;

View file

@ -3,8 +3,10 @@
#include <assert.h>
#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) {

View file

@ -4,7 +4,7 @@
void (*sKaleidoScopeUpdateFunc)(PlayState* play);
void (*sKaleidoScopeDrawFunc)(PlayState* play);
f32 gBossMarkScale;
f32 gBossMarkScale = 1.0f;
u32 D_8016139C;
PauseMapMarksData* gLoadedPauseMarkDataTable;

View file

@ -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) {

View file

@ -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 },

View file

@ -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 <assert.h>
#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;
SceneDBEntry* entry = SceneDB_Retrieve(mapIndex);
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("%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 (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]);
if (sEntranceIconMapIndex < 24) {
play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(minimapTableOW[sEntranceIconMapIndex]);
play->interfaceCtx.mapSegmentName[0] = minimapTableOW[sEntranceIconMapIndex];
}
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);
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(" 各階ONチェック\n"); // "MAP Individual Floor ON Check"
break;
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(" 各階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("_%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("_%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 (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);
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;
}
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);
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 = 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);
}
}
// 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);
}
//! @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);
}
}
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);
}
}
// 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);
}
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;
}
} 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);
}
}
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;
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;
}
break;
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;
// 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 = 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);
}
}
// 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);
}
}
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);
}
}
// 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);
}
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,
entry->dungeonData.numRooms);
sLastRoomNum = interfaceCtx->mapRoomNum;
}
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);
}
}
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;
}
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);
}
}
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;
}
}
}

View file

@ -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];
mapMarkIconData = &sLoadedMarkDataTable[dungeon][interfaceCtx->mapRoomNum][0];
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;
} 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];
}
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 {
rectLeft = PosX_Minimap_ori;
rectTop = PosY_Minimap_ori;
}
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;
} else {
X_Margins_Minimap_ic = 0;
Y_Margins_Minimap_ic = 0;
}
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);
}
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);
}
}

View file

@ -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) {

View file

@ -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
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;
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;
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;

View file

@ -14,6 +14,7 @@
#include "soh/OTRGlobals.h"
#include "soh/SaveManager.h"
#include "soh/framebuffer_effects.h"
#include "soh/SceneDB.h"
#include <libultraship/libultraship.h>
@ -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()) {

View file

@ -7,6 +7,7 @@
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include <string.h>
#include <assert.h>
#include <soh/SceneDB.h>
#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);

View file

@ -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

View file

@ -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));
}
}

View file

@ -10,6 +10,7 @@
#include "objects/object_hni/object_hni.h"
#include "scenes/overworld/spot09/spot09_scene.h"
#include <assert.h>
#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))) {
SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum);
if (!entry->epona.allowed) {
return false;
}
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);
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))) {
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);
}
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);
}
}
}

View file

@ -32,6 +32,7 @@
#include "soh/frame_interpolation.h"
#include "soh/OTRGlobals.h"
#include "soh/ResourceManagerHelpers.h"
#include "soh/SceneDB.h"
#include <string.h>
#include <stdlib.h>
@ -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,

View file

@ -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;
}
}

View file

@ -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,

View file

@ -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

View file

@ -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;
SceneDBEntry* entry = SceneDB_Retrieve(gSaveContext.mapIndex);
SceneDBFloor* floor = &entry->dungeonData.floors[play->pauseCtx.dungeonMapSlot - 3];
mapMarkData = &gLoadedPauseMarkDataTable[R_MAP_TEX_INDEX >> 1][i];
if (SceneDB_IsBoss(play->sceneNum)) {
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;
}
}
scale = gBossMarkScale;
} else {
scale = 1.0f;
}
OPEN_DISPS(play->state.gfxCtx);
while (true) {
if (mapMarkData->markType == PAUSE_MAP_MARK_NONE) {
break;
gDPPipeSync(POLY_KAL_DISP++);
gDPSetPrimColor(POLY_KAL_DISP++, 0, 0, 255, 255, 255, 255);
gDPSetEnvColor(POLY_KAL_DISP++, 0, 0, 0, 255);
Matrix_Push();
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);
}
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;
if (Flags_GetTreasure(play, floor->chestMarks[i].chestFlag)) {
display = false;
} else {
display = SceneDB_IsDungeon(play->sceneNum);
}
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;
}
}
scale = gBossMarkScale;
} else {
scale = 1.0f;
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;
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();
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;
Matrix_Push();
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);
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;
}
if (display) {
markInfo = &sMapMarkInfoTable[mapMarkData->markType];
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);
// 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;
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();
gSPVertex(POLY_KAL_DISP++, mapMarkData->vtx, mapMarkData->vtxCount, 0);
gSP1Quadrangle(POLY_KAL_DISP++, 1, 3, 2, 0, 0);
}
markPoint++;
}
mapMarkData++;
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);