This commit is contained in:
Rozelette 2025-06-17 09:54:46 +02:00 committed by GitHub
commit 826aa2371c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
34 changed files with 5957 additions and 1053 deletions

View file

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

@ -47,8 +47,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
@ -224,7 +224,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

@ -514,7 +514,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
// 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"
@ -857,13 +858,16 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, va_l
*should = !Flags_GetRandomizerInf(RAND_INF_DARUNIAS_JOY);
break;
case VB_BE_ELIGIBLE_FOR_LIGHT_ARROWS:
*should = LINK_IS_ADULT && (gEntranceTable[gSaveContext.entranceIndex].scene == SCENE_TEMPLE_OF_TIME) &&
*should = LINK_IS_ADULT &&
(EntranceDB::Instance->RetrieveEntry(gSaveContext.entranceIndex).entry.sceneId ==
SCENE_TEMPLE_OF_TIME) &&
!Flags_GetEventChkInf(EVENTCHKINF_RETURNED_TO_TEMPLE_OF_TIME_WITH_ALL_MEDALLIONS) &&
MeetsLACSRequirements();
break;
case VB_BE_ELIGIBLE_FOR_NOCTURNE_OF_SHADOW:
*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);
break;

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"
@ -2025,6 +2026,7 @@ void Logic::InitSaveContext() {
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;
}
@ -2034,15 +2036,15 @@ void Logic::InitSaveContext() {
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;
@ -2121,9 +2123,16 @@ void Logic::InitSaveContext() {
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

@ -12,6 +12,7 @@
#include "randomizer_grotto.h"
#include "soh/OTRGlobals.h"
#include "soh/SaveManager.h"
#include "soh/SceneDB.h"
#include <string.h>
#include "global.h"
@ -92,7 +93,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);
}
}
@ -100,7 +101,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);
}
}
@ -109,56 +110,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();
@ -251,9 +241,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;
}
}
}
@ -316,8 +304,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"
@ -180,7 +181,8 @@ 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);
if (GameInteractor_Should(VB_BE_ELIGIBLE_FOR_LIGHT_ARROWS, meetsLACSRequirements)) {

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;
}
@ -206,6 +206,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) {
@ -454,8 +455,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

@ -74,6 +74,7 @@
#include "soh/SohGui/ImGuiUtils.h"
#include "ActorDB.h"
#include "SaveManager.h"
#include "SceneDB.h"
#ifdef ENABLE_REMOTE_CONTROL
#include "soh/Network/CrowdControl/CrowdControl.h"
@ -1228,6 +1229,8 @@ extern "C" void InitOTR() {
OTRGlobals::Instance->gRandoContext->AddExcludedOptions();
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

@ -16,6 +16,7 @@
#include "macros.h"
#include <variables.h>
#include <libultraship/libultraship.h>
#include "soh/SceneDB.h"
#include "soh/SohGui/SohGui.hpp"
#define NOGDI // avoid various windows defines that conflict with things in z64.h
@ -24,6 +25,7 @@
#include <fstream>
#include <filesystem>
#include <array>
#include <algorithm>
#include <mutex>
extern "C" SaveContext gSaveContext;
@ -117,7 +119,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);
@ -736,6 +739,7 @@ void SaveManager::InitFile(bool isDebug) {
}
void SaveManager::InitFileImpl(bool isDebug) {
AllocateSceneData();
if (isDebug) {
InitFileDebug();
} else {
@ -809,23 +813,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;
@ -996,13 +988,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;
@ -1117,13 +1108,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;
@ -1192,6 +1178,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) {
@ -1568,16 +1570,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->LoadData("", gSaveContext.inventory.dungeonItems[i]); });
SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) {
SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[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);
@ -1712,10 +1714,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->LoadData("", gSaveContext.inventory.dungeonItems[i]); });
SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) {
SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]);
});
SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]);
});
SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts);
@ -1744,7 +1746,7 @@ void SaveManager::LoadBaseVersion2() {
"entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered),
[](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.ship.stats.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);
@ -1928,10 +1930,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->LoadData("", gSaveContext.inventory.dungeonItems[i]); });
SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) {
SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]);
});
SaveManager::Instance->LoadArray("dungeonKeys", 19, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]);
});
SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts);
@ -1977,7 +1979,7 @@ void SaveManager::LoadBaseVersion3() {
"entrancesDiscovered", ARRAY_COUNT(gSaveContext.ship.stats.entrancesDiscovered),
[](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.ship.stats.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);
@ -2148,16 +2150,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->LoadData("", gSaveContext.inventory.dungeonItems[i]); });
SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) {
SaveManager::Instance->LoadArray("dungeonItems", 20, [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[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);
@ -2255,6 +2257,187 @@ void SaveManager::LoadBaseVersion4() {
SaveManager::Instance->LoadData("maskMemory", gSaveContext.ship.maskMemory);
}
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.ship.quest.id = 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.ship.randomizerInf), [](size_t i) {
SaveManager::Instance->LoadData("", gSaveContext.ship.randomizerInf[i]);
});
int isMQ = 0;
SaveManager::Instance->LoadData("isMasterQuest", isMQ);
if (isMQ) {
gSaveContext.ship.quest.id = QUEST_MASTER;
}
SaveManager::Instance->LoadStruct("backupFW", []() {
SaveManager::Instance->LoadStruct("pos", []() {
SaveManager::Instance->LoadData("x", gSaveContext.ship.backupFW.pos.x);
SaveManager::Instance->LoadData("y", gSaveContext.ship.backupFW.pos.y);
SaveManager::Instance->LoadData("z", gSaveContext.ship.backupFW.pos.z);
});
SaveManager::Instance->LoadData("yaw", gSaveContext.ship.backupFW.yaw);
SaveManager::Instance->LoadData("playerParams", gSaveContext.ship.backupFW.playerParams);
SaveManager::Instance->LoadData("entranceIndex", gSaveContext.ship.backupFW.entranceIndex);
SaveManager::Instance->LoadData("roomIndex", gSaveContext.ship.backupFW.roomIndex);
SaveManager::Instance->LoadData("set", gSaveContext.ship.backupFW.set);
SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.ship.backupFW.tempSwchFlags);
SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.ship.backupFW.tempCollectFlags);
});
SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams);
SaveManager::Instance->LoadData("filenameLanguage", gSaveContext.ship.filenameLanguage);
SaveManager::Instance->LoadData("maskMemory", gSaveContext.ship.maskMemory);
}
void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSave) {
SaveManager::Instance->SaveData("entranceIndex", saveContext->entranceIndex);
SaveManager::Instance->SaveData("linkAge", saveContext->linkAge);
@ -2319,17 +2502,13 @@ 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->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);
@ -2337,7 +2516,10 @@ void SaveManager::SaveBase(SaveContext* saveContext, int sectionID, bool fullSav
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", [&]() {
@ -2800,7 +2982,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

@ -166,6 +166,8 @@ class SaveManager {
static void InitFileDebug();
static void InitFileMaxed();
static void AllocateSceneData();
static void LoadRandomizerVersion1();
static void LoadRandomizerVersion2();
static void LoadRandomizerVersion3();
@ -177,6 +179,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;

1190
soh/soh/SceneDB.cpp Normal file

File diff suppressed because it is too large Load diff

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

@ -0,0 +1,374 @@
#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

3288
soh/soh/SceneDB_Table.cpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -4,6 +4,7 @@
#include "soh/resource/type/Scene.h"
#include <utils/StringHelper.h>
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/SceneDB.h"
#include "global.h"
#include "vt.h"
#include <Vertex.h>
@ -20,14 +21,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) ||
@ -37,8 +34,8 @@ 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());
@ -50,12 +47,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

@ -875,6 +875,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;
@ -2218,6 +2219,7 @@ void Cutscene_HandleConditionalTriggers(PlayState* play) {
return;
}
s32 scene = EntranceDB_Retrieve(gSaveContext.entranceIndex)->sceneId;
if ((gSaveContext.gameMode == GAMEMODE_NORMAL) && (gSaveContext.respawnFlag <= 0) &&
(gSaveContext.cutsceneIndex < 0xFFF0)) {
if ((gSaveContext.entranceIndex == ENTR_DESERT_COLOSSUS_OUTSIDE_TEMPLE) &&
@ -2247,12 +2249,12 @@ void Cutscene_HandleConditionalTriggers(PlayState* play) {
(CHECK_QUEST_ITEM(QUEST_MEDALLION_SPIRIT) && 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,10 +3,11 @@
#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) {
s32 validScenes[] = { SCENE_HYRULE_FIELD, SCENE_LAKE_HYLIA, SCENE_GERUDO_VALLEY, SCENE_GERUDOS_FORTRESS,
SCENE_LON_LON_RANCH };
#if 0
s32 validScenes[] = { SCENE_HYRULE_FIELD, SCENE_LAKE_HYLIA, SCENE_GERUDO_VALLEY, SCENE_GERUDOS_FORTRESS, SCENE_LON_LON_RANCH };
s32 i;
for (i = 0; i < ARRAY_COUNT(validScenes); i++) {
@ -16,6 +17,8 @@ s32 func_8006CFC0(s32 scene) {
}
return 0;
#endif
return SceneDB_Retrieve(scene)->epona.allowed;
}
void func_8006D074(PlayState* play) {
@ -108,20 +111,14 @@ void func_8006D0EC(PlayState* play, Player* player) {
Actor* horseActor = 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) {
SceneDBEntry* entry = SceneDB_Retrieve(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);
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;
}
break;
}
}
} else if (!Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED)) {
if ((DREG(1) == 0) && (play->sceneNum == SCENE_LON_LON_BUILDINGS) && !IS_DAY) {
Actor_Spawn(&play->actorCtx, play, ACTOR_EN_HORSE, 0.0f, 0.0f, -60.0f, 0, 0x7360, 0, 1, true);

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 };
@ -124,6 +126,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

@ -132,25 +132,32 @@ 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 },
{ 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,
980, 1640, 1510, 590, 1610, 1130, 1130, 820, 1320, 1620, 0, 0, 0, 0, 1300, 1270 },
{ 1160, 620, 1330, 1280, 440, 600, 810, 830, 720, 1170, 1490, 1640, 1870, 1800, 1610, 1130, 860, 1310, 1140,
850, 760, 380, 800, 800, 1930, 1410, 640, 845, 810, 810, 850, 1390, 1540, 1650, 1880, 1530, 420, 1950 },
{ 1120, 1290, 1120, 1380, 930, 1520, 1980, 2010, 1590, 1510, 1500, 1300, 1240, 1800, 1290,
1450, 1560, 880, 820, 820, 1060, 1670, 1120, 1130, 1130, 1290, 1290, 1280, 1390, 940,
1520, 1520, 1980, 1620, 1510, 1490, 1240, 1290, 1450, 880, 880, 1060, 1670, 1520 },
{ 800, 1500, 1370, 1730, 1590, 1020, 1060, 1470, 1600, 1830, 1630, 2000, 650, 660, 1020, 880,
940, 720, 570, 620, 570, 550, 970, 920, 1040, 1150, 1200, 1550, 1520, 1020, 820, 1010 },
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 },
{ 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, 980, 1640, 1510, 590, 1610,
1130, 1130, 820, 1320, 1620, 0, 0, 0, 0, 1300, 1270 },
{ 1160, 620, 1330, 1280, 440, 600, 810, 830, 720, 1170, 1490, 1640, 1870,
1800, 1610, 1130, 860, 1310, 1140, 850, 760, 380, 800, 800, 1930, 1410,
640, 845, 810, 810, 850, 1390, 1540, 1650, 1880, 1530, 420, 1950 },
{ 1120, 1290, 1120, 1380, 930, 1520, 1980, 2010, 1590, 1510, 1500,
1300, 1240, 1800, 1290, 1450, 1560, 880, 820, 820, 1060, 1670,
1120, 1130, 1130, 1290, 1290, 1280, 1390, 940, 1520, 1520, 1980,
1620, 1510, 1490, 1240, 1290, 1450, 880, 880, 1060, 1670, 1520 },
{ 800, 1500, 1370, 1730, 1590, 1020, 1060, 1470, 1600, 1830, 1630,
2000, 650, 660, 1020, 880, 940, 720, 570, 620, 570, 550,
970, 920, 1040, 1150, 1200, 1550, 1520, 1020, 820, 1010 },
{ 1320, 1320, 1090, 1510, 1480, 940, 920, 910, 800, 820, 1150, 1000, 1800, 1660,
1090, 1630, 710, 1670, 830, 770, 800, 850, 830, 820, 1800, 1090, 850 },
{ 1080, 1420, 1620, 1040, 940, 1190, 1310, 1090, 1380, 1080 },
{ 1070, 1180, 1270, 990, 1280, 1450, 1680, 1530, 760, 860, 1500, 800 },
};
};
static s16 sRoomCompassOffsetY[10][44] = {
{ -660, -570, -410, -690, -500, -380, -470, -630, -990, -870,
@ -277,7 +284,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"
#include "soh/Enhancements/cosmetics/cosmeticsTypes.h"
@ -14,6 +16,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;
@ -31,7 +35,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;
@ -52,6 +57,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;
@ -63,32 +69,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 (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;
}
}
@ -365,101 +352,50 @@ 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) &&
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)))) {
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()) ||
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))) {
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 (sEntranceIconMapIndex < 24) {
play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(minimapTableOW[sEntranceIconMapIndex]);
play->interfaceCtx.mapSegmentName[0] = minimapTableOW[sEntranceIconMapIndex];
sOwEntranceIconPosX = 243;
sOwEntranceIconPosY = -833;
play->interfaceCtx.mapSegmentName[0] = gGerudosFortressMinimapTex;
} else {
sOwEntranceIconPosX = entry->worldData.iconX;
sOwEntranceIconPosY = entry->worldData.iconY;
play->interfaceCtx.mapSegmentName[0] = entry->worldData.minimapTexture;
}
play->interfaceCtx.mapSegment[0] = ResourceGetDataByName(play->interfaceCtx.mapSegmentName[0]);
interfaceCtx->unk_258 = mapIndex;
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:
} 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("デクの樹ダンジョン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];
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"
break;
}
}
@ -470,26 +406,7 @@ 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:
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;
@ -499,8 +416,6 @@ void Map_InitRoomData(PlayState* play, s16 room) {
osSyncPrintf("部屋部屋=%d\n", room); // "Room Room = %d"
osSyncPrintf(VT_RST);
Map_InitData(play, room);
break;
}
} 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,76 +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];
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);
}
break;
}
}
void Minimap_DrawCompassIcons(PlayState* play) {
@ -607,6 +478,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);
}
@ -640,10 +512,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;
}
@ -767,6 +639,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);
@ -793,18 +666,9 @@ 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) != HIDDEN) {
if (SCENEDB_ISDUNGEON(entry)) {
if (!R_MINIMAP_DISABLED &&
CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) != HIDDEN) { // 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);
@ -813,17 +677,16 @@ void Minimap_Draw(PlayState* play) {
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;
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);
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) != ORIGINAL_LOCATION) {
dgnMiniMapY = R_DGN_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) == ANCHOR_LEFT) {
if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {
X_Margins_Minimap = Left_MM_Margin;
@ -849,9 +712,8 @@ void Minimap_Draw(PlayState* play) {
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);
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)) {
@ -861,8 +723,7 @@ void Minimap_Draw(PlayState* play) {
}
}
if (CHECK_BTN_ALL(play->state.input[0].press.button, BTN_L) && !Play_InCsMode(play) &&
enableMapToggle) {
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,
@ -872,28 +733,7 @@ void Minimap_Draw(PlayState* play) {
// 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:
} 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);
@ -903,28 +743,28 @@ void Minimap_Draw(PlayState* play) {
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,
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(R_OW_MINIMAP_X + X_Margins_Minimap);
s16 oWMiniMapY = R_OW_MINIMAP_Y + Y_Margins_Minimap;
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) != ORIGINAL_LOCATION) {
oWMiniMapY =
R_OW_MINIMAP_Y + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) + Y_Margins_Minimap;
oWMiniMapY = entry->worldData.minimapY + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0) +
Y_Margins_Minimap;
if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 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) +
oWMiniMapX = OTRGetDimensionFromLeftEdge(entry->worldData.minimapX +
CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) +
X_Margins_Minimap);
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 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) +
oWMiniMapX = OTRGetDimensionFromRightEdge(entry->worldData.minimapX +
CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) +
X_Margins_Minimap);
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == ANCHOR_NONE) {
oWMiniMapX = CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0);
@ -934,13 +774,12 @@ void Minimap_Draw(PlayState* play) {
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 = entry->worldData.minimapWidth << 5;
}
gSPWideTextureRectangle(OVERLAY_DISP++, oWMiniMapX << 2, oWMiniMapY << 2,
(oWMiniMapX + gMapData->owMinimapWidth[mapIndex]) << 2,
(oWMiniMapY + gMapData->owMinimapHeight[mapIndex]) << 2, G_TX_RENDERTILE,
sValue, 0, 1 << 10, 1 << 10);
gSPWideTextureRectangle(
OVERLAY_DISP++, 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);
@ -950,24 +789,23 @@ void Minimap_Draw(PlayState* play) {
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];
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)
// 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));
(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 = gMapData->owEntranceIconPosY[sEntranceIconMapIndex] & 0x3FF;
// 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;
@ -986,30 +824,26 @@ void Minimap_Draw(PlayState* play) {
entranceX = OTRGetRectDimensionFromRightEdge(
newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0));
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == ANCHOR_NONE) {
entranceX =
newX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0);
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) {
// 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);
}
//! @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]]) ||
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);
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);
@ -1034,8 +868,7 @@ void Minimap_Draw(PlayState* play) {
entranceX = OTRGetRectDimensionFromRightEdge(
origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0));
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == ANCHOR_NONE) {
entranceX =
origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0);
entranceX = origX + X_Margins_Minimap + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0);
}
}
@ -1046,16 +879,14 @@ void Minimap_Draw(PlayState* play) {
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++, 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) {
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); }
@ -1064,8 +895,6 @@ void Minimap_Draw(PlayState* play) {
// clang-format on
R_MINIMAP_DISABLED ^= 1;
}
break;
}
}
@ -1083,6 +912,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);
@ -1090,47 +920,34 @@ 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:
if (SCENEDB_ISDUNGEON(entry)) {
interfaceCtx->mapPalette[30] = 0;
if (CHECK_DUNGEON_ITEM(DUNGEON_MAP, mapIndex)) {
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]) {
if (player->actor.world.pos.y > entry->dungeonData.floors[floor].height) {
break;
}
}
gSaveContext.sceneFlags[mapIndex].floors |= gBitFlags[floor];
gSaveContext.sceneFlags[play->sceneNum].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);
}
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]);
entry->dungeonData.numRooms);
sLastRoomNum = interfaceCtx->mapRoomNum;
}
for (i = 0; i < gMapData->switchEntryCount[mapIndex]; i++) {
if ((interfaceCtx->mapRoomNum == gMapData->switchFromRoom[mapIndex][i]) &&
(floor == gMapData->switchFromFloor[mapIndex][i])) {
interfaceCtx->mapRoomNum = gMapData->switchToRoom[mapIndex][i];
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);
@ -1142,19 +959,8 @@ void Map_Update(PlayState* 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;
} 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"
@ -95,26 +96,8 @@ 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;
}
mapMarkIconData = &sLoadedMarkDataTable[dungeon][interfaceCtx->mapRoomNum][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);
SceneDBEntry* entry = SceneDB_Retrieve(dungeon);
SceneDBRoom* room = &entry->dungeonData.rooms[interfaceCtx->mapRoomNum];
s32 Top_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.T"), 0);
s32 Left_MC_Margin = CVarGetInteger(CVAR_COSMETIC("HUD.Margin.L"), 0);
@ -133,11 +116,27 @@ void MapMark_DrawForDungeon(PlayState* play) {
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];
OPEN_DISPS(play->state.gfxCtx);
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;
@ -154,8 +153,8 @@ void MapMark_DrawForDungeon(PlayState* play) {
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) != ORIGINAL_LOCATION) {
rectTop = (markPoint->y + Y_Margins_Minimap_ic + 140 +
CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0));
rectTop =
(markPoint->y + Y_Margins_Minimap_ic + 140 + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosY"), 0));
if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == ANCHOR_LEFT) {
if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.UseMargins"), 0) != 0) {
X_Margins_Minimap_ic = Left_MC_Margin;
@ -166,23 +165,20 @@ void MapMark_DrawForDungeon(PlayState* play) {
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);
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);
markPointX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + 204 + X_Margins_Minimap_ic);
}
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == 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);
markPointX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + 204 + X_Margins_Minimap_ic);
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == ANCHOR_NONE) {
rectLeft = markPointX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + 204 +
X_Margins_Minimap_ic;
rectLeft =
markPointX + CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosX"), 0) + 204 + X_Margins_Minimap_ic;
} else if (CVarGetInteger(CVAR_COSMETIC("HUD.Minimap.PosType"), 0) == HIDDEN) {
rectLeft = -9999;
}
@ -201,32 +197,11 @@ void MapMark_DrawForDungeon(PlayState* play) {
rectTop + height << 2, G_TX_RENDERTILE, 0, 0, width_factor, height_factor);
}
markPoint++;
}
mapMarkIconData++;
}
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:
if (SceneDB_IsDungeon(play->sceneNum) || SceneDB_IsBoss(play->sceneNum)) {
MapMark_DrawForDungeon(play);
break;
}
}

View file

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

@ -7,6 +7,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"
@ -1068,7 +1069,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) ||
@ -1095,7 +1096,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) ||
@ -1133,7 +1134,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)) {
@ -1144,7 +1145,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)) {
@ -1157,7 +1158,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) &&
@ -1173,7 +1174,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)) {
@ -1186,7 +1187,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)) {
@ -1197,7 +1198,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)) {
@ -1210,7 +1211,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)) {
@ -1221,7 +1222,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)) {
@ -1234,7 +1235,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) {
@ -1245,7 +1246,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) {
@ -1257,7 +1258,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)) {
@ -1268,7 +1269,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)) {
@ -1281,7 +1282,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) &&
@ -1308,7 +1309,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) &&
@ -1346,61 +1347,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) {
if (play->sceneNum == SCENE_GERUDO_TRAINING_GROUND || play->sceneNum == SCENE_INSIDE_GANONS_CASTLE) {
interfaceCtx->restrictions.farores = 0;
}
}
return;
}
i++;
} while (sRestrictionFlags[i].scene != 0xFF);
}
Gfx* Gfx_TextureIA8(Gfx* displayListHead, void* texture, s16 textureWidth, s16 textureHeight, s16 rectLeft, s16 rectTop,
@ -1427,6 +1393,141 @@ 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;
@ -6864,7 +6965,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

@ -15,6 +15,7 @@
#include "soh/ResourceManagerHelpers.h"
#include "soh/SaveManager.h"
#include "soh/framebuffer_effects.h"
#include "soh/SceneDB.h"
#include <libultraship/libultraship.h>
@ -478,23 +479,21 @@ 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);
@ -549,8 +548,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;
@ -819,8 +818,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"
@ -646,7 +647,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

@ -26,6 +26,7 @@
#include "soh/mq_asset_hacks.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) \
@ -87,23 +88,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

@ -1413,11 +1413,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_CULLING_DISABLED
@ -679,30 +680,35 @@ s32 EnHorse_Spawn(EnHorse* this, PlayState* play) {
Player* player;
Vec3f spawnPos;
for (i = 0; i < 169; i++) {
if (sHorseSpawns[i].scene == play->sceneNum) {
SceneDBEntry* entry = SceneDB_Retrieve(play->sceneNum);
if (!entry->epona.allowed) {
return false;
}
for (i = 0; i < entry->epona.numSpawns; i++) {
player = GET_PLAYER(play);
if (play->sceneNum != SCENE_LON_LON_RANCH ||
//! Same flag checked twice
(Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED) &&
((gSaveContext.eventInf[0] & 0xF) != 6 || Flags_GetEventChkInf(EVENTCHKINF_EPONA_OBTAINED))) ||
// always load two spawns inside lon lon
((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))) {
((entry->epona.spawnPos[i].x == 856 && entry->epona.spawnPos[i].y == 0 &&
entry->epona.spawnPos[i].z == -918) ||
(entry->epona.spawnPos[i].x == -1003 && entry->epona.spawnPos[i].y == 0 &&
entry->epona.spawnPos[i].z == -755))) {
spawnPos.x = sHorseSpawns[i].pos.x;
spawnPos.y = sHorseSpawns[i].pos.y;
spawnPos.z = sHorseSpawns[i].pos.z;
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 (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.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 = sHorseSpawns[i].angle;
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,
@ -710,7 +716,6 @@ s32 EnHorse_Spawn(EnHorse* this, PlayState* play) {
}
}
}
}
return spawn;
}

View file

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

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);
@ -57,7 +58,7 @@ void Select_LoadGame(SelectContext* this, s32 entranceIndex) {
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);
@ -1212,7 +1213,8 @@ void Better_Select_UpdateMenu(SelectContext* this) {
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;
@ -1795,7 +1797,7 @@ void Select_SwitchBetterWarpMode(SelectContext* this, u8 isBetterWarpMode) {
BetterSceneSelectEntrancePair entrancePair =
this->betterScenes[this->currentScene].entrancePairs[this->pageDownIndex];
if (entrancePair.canBeMQ &&
ResourceMgr_IsSceneMasterQuest(gEntranceTable[entrancePair.entranceIndex].scene)) {
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"
@ -60,6 +61,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);
@ -91,9 +93,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);
}
}
@ -121,12 +120,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;
}
@ -137,20 +137,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);
}
}
@ -179,10 +174,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);
}
}
@ -263,9 +254,9 @@ 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_OPA_DISP++, floorIconTexs[gMapData->floorID[interfaceCtx->unk_25A][i]],
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);
gDPLoadTextureBlock(POLY_OPA_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);
gSP1Quadrangle(POLY_OPA_DISP++, j, j + 2, j + 3, j + 1, 0);
}
@ -277,8 +268,7 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gDPPipeSync(POLY_OPA_DISP++);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 150, 150, 255, pauseCtx->alpha);
gDPLoadTextureBlock(POLY_OPA_DISP++,
floorIconTexs[gMapData->floorID[interfaceCtx->unk_25A][pauseCtx->dungeonMapSlot - 3]],
gDPLoadTextureBlock(POLY_OPA_DISP++, 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);
@ -303,10 +293,9 @@ void KaleidoScope_DrawDungeonMap(PlayState* play, GraphicsContext* gfxCtx) {
gSP1Quadrangle(POLY_OPA_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;
if (CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, gSaveContext.mapIndex) && (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_OPA_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[] = {
gPauseEquipment00FRATex, gPauseEquipment01Tex, gPauseEquipment02Tex, gPauseEquipment03Tex, gPauseEquipment04Tex,
@ -3680,6 +3681,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) {
@ -3691,12 +3693,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,12 +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) {
if (ResourceMgr_IsGameMasterQuest()) {
gLoadedPauseMarkDataTable = gPauseMapMarkDataTableMasterQuest;
} else {
gLoadedPauseMarkDataTable = gPauseMapMarkDataTable;
}
}
void PauseMapMark_Clear(PlayState* play) {
@ -54,18 +64,10 @@ 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];
OPEN_DISPS(play->state.gfxCtx);
while (true) {
if (mapMarkData->markType == PAUSE_MAP_MARK_NONE) {
break;
}
if ((mapMarkData->markType == PAUSE_MAP_MARK_BOSS) && (play->sceneNum >= SCENE_DEKU_TREE_BOSS) &&
(play->sceneNum <= SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR)) {
if (SceneDB_IsBoss(play->sceneNum)) {
if (gBossMarkState == 0) {
Math_ApproachF(&gBossMarkScale, 1.5f, 1.0f, 0.041f);
if (gBossMarkScale == 1.5f) {
@ -82,6 +84,12 @@ void PauseMapMark_DrawForDungeon(PlayState* play) {
scale = 1.0f;
}
OPEN_DISPS(play->state.gfxCtx);
gDPPipeSync(POLY_OPA_DISP++);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
gDPSetEnvColor(POLY_OPA_DISP++, 0, 0, 0, 255);
Matrix_Push();
if ((play->pauseCtx.state == 4) || (play->pauseCtx.state >= 0x12)) {
@ -90,68 +98,58 @@ void PauseMapMark_DrawForDungeon(PlayState* play) {
Matrix_Translate(-36.0f, 21.0f, 0.0f, MTXMODE_APPLY);
}
gDPPipeSync(POLY_OPA_DISP++);
gDPSetPrimColor(POLY_OPA_DISP++, 0, 0, 255, 255, 255, 255);
gDPSetEnvColor(POLY_OPA_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_OPA_DISP++);
markInfo = &sMapMarkInfoTable[MAP_MARK_CHEST];
gDPLoadTextureBlock(POLY_OPA_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 (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_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
Matrix_Pop();
gSPVertex(POLY_OPA_DISP++, sMarkChestVtx, 4, 0);
gSP1Quadrangle(POLY_OPA_DISP++, 1, 3, 2, 0, 0);
}
}
markInfo = &sMapMarkInfoTable[MAP_MARK_BOSS];
gDPLoadTextureBlock(POLY_OPA_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(CVAR_ENHANCEMENT("MirroredWorld"), 0)
? mirrorOffset = (48 - markPoint->x) * 2 + 1
? mirrorOffset = (48 - floor->bossMarks[i].x) * 2 + 1
: 0;
Matrix_Push();
Matrix_Translate(GREG(92) + markPoint->x + mirrorOffset, GREG(93) + markPoint->y, 0.0f, MTXMODE_APPLY);
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_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx),
G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
gSPMatrix(POLY_OPA_DISP++, MATRIX_NEWMTX(play->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
Matrix_Pop();
gSPVertex(POLY_OPA_DISP++, mapMarkData->vtx, mapMarkData->vtxCount, 0);
gSPVertex(POLY_OPA_DISP++, sMarkBossVtx, 4, 0);
gSP1Quadrangle(POLY_OPA_DISP++, 1, 3, 2, 0, 0);
}
markPoint++;
}
mapMarkData++;
Matrix_Pop();
}
CLOSE_DISPS(play->state.gfxCtx);
}
@ -159,33 +157,9 @@ void PauseMapMark_DrawForDungeon(PlayState* play) {
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:
if (SceneDB_IsDungeon(play->sceneNum) ||
(CVarGetInteger(CVAR_ENHANCEMENT("PulsateBossIcon"), 0) != 0 && SceneDB_IsBoss(play->sceneNum))) {
PauseMapMark_DrawForDungeon(play);
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:
case SCENE_GANONDORF_BOSS:
case SCENE_GANONS_TOWER_COLLAPSE_EXTERIOR:
if (CVarGetInteger(CVAR_ENHANCEMENT("PulsateBossIcon"), 0) != 0) {
PauseMapMark_DrawForDungeon(play);
}
break;
}
PauseMapMark_Clear(play);