mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-12-22 16:18:50 -05:00
Track keys, heart pieces, and heart containers collected (#1849)
* Track keys, heart pieces, and heart containers collected * Update soh/soh/Enhancements/randomizer/randomizer_item_tracker.cpp
This commit is contained in:
parent
897e70b6fc
commit
3b7b4913eb
@ -25,6 +25,12 @@ typedef struct {
|
||||
/* 0x5C */ s16 gsTokens;
|
||||
} Inventory; // size = 0x5E
|
||||
|
||||
typedef struct {
|
||||
/* */ u8 heartPieces;
|
||||
/* */ u8 heartContainers;
|
||||
/* */ u8 dungeonKeys[19];
|
||||
} SohStats;
|
||||
|
||||
typedef struct {
|
||||
/* 0x00 */ u32 chest;
|
||||
/* 0x04 */ u32 swch;
|
||||
@ -189,6 +195,7 @@ typedef struct {
|
||||
u16 adultTradeItems;
|
||||
u8 pendingIceTrapCount;
|
||||
u8 mqDungeonCount;
|
||||
SohStats sohStats;
|
||||
} SaveContext; // size = 0x1428
|
||||
|
||||
typedef enum {
|
||||
|
@ -14,6 +14,8 @@ typedef enum {
|
||||
TEXT_ALTAR_ADULT = 0x7088,
|
||||
TEXT_GANONDORF = 0x70CC,
|
||||
TEXT_GANONDORF_NOHINT = 0x70CD,
|
||||
TEXT_HEART_CONTAINER = 0xC6,
|
||||
TEXT_HEART_PIECE = 0xC2,
|
||||
TEXT_BLUE_RUPEE = 0xCC,
|
||||
TEXT_RED_RUPEE = 0xF0,
|
||||
TEXT_PURPLE_RUPEE = 0xF1,
|
||||
|
@ -134,6 +134,7 @@ std::map<uint32_t, ItemMapEntry> itemMapping = {
|
||||
ITEM_MAP_ENTRY(ITEM_DUNGEON_MAP),
|
||||
ITEM_MAP_ENTRY(ITEM_KEY_SMALL),
|
||||
ITEM_MAP_ENTRY(ITEM_HEART_CONTAINER),
|
||||
ITEM_MAP_ENTRY(ITEM_HEART_PIECE),
|
||||
ITEM_MAP_ENTRY(ITEM_MAGIC_SMALL),
|
||||
ITEM_MAP_ENTRY(ITEM_MAGIC_LARGE)
|
||||
};
|
||||
@ -1302,7 +1303,9 @@ void DrawQuestStatusTab() {
|
||||
float lineHeight = ImGui::GetTextLineHeightWithSpacing();
|
||||
ImGui::Image(SohImGui::GetTextureByName(itemMapping[ITEM_KEY_SMALL].name), ImVec2(lineHeight, lineHeight));
|
||||
ImGui::SameLine();
|
||||
ImGui::InputScalar("##Keys", ImGuiDataType_S8, gSaveContext.inventory.dungeonKeys + dungeonItemsScene);
|
||||
if (ImGui::InputScalar("##Keys", ImGuiDataType_S8, gSaveContext.inventory.dungeonKeys + dungeonItemsScene)) {
|
||||
gSaveContext.sohStats.dungeonKeys[dungeonItemsScene] = gSaveContext.inventory.dungeonKeys[dungeonItemsScene];
|
||||
};
|
||||
} else {
|
||||
// dungeonItems is size 20 but dungeonKeys is size 19, so there are no keys for the last scene (Barinade's Lair)
|
||||
ImGui::Text("Barinade's Lair does not have small keys");
|
||||
|
@ -55,8 +55,8 @@ std::vector<ItemTrackerItem> equipmentItems = {
|
||||
|
||||
std::vector<ItemTrackerItem> miscItems = {
|
||||
ITEM_TRACKER_ITEM(ITEM_BRACELET, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_SCALE_SILVER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_WALLET_ADULT, 0, DrawItem),
|
||||
ITEM_TRACKER_ITEM(ITEM_HEART_CONTAINER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_MAGIC_SMALL, 0, DrawItem), ITEM_TRACKER_ITEM(QUEST_STONE_OF_AGONY, 1 << 21, DrawQuest),
|
||||
ITEM_TRACKER_ITEM(QUEST_GERUDO_CARD, 1 << 22, DrawQuest), ITEM_TRACKER_ITEM(QUEST_SKULL_TOKEN, 1 << 23, DrawQuest),
|
||||
ITEM_TRACKER_ITEM(ITEM_HEART_CONTAINER, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_HEART_PIECE, 0, DrawItem), ITEM_TRACKER_ITEM(ITEM_MAGIC_SMALL, 0, DrawItem),
|
||||
ITEM_TRACKER_ITEM(QUEST_GERUDO_CARD, 1 << 22, DrawQuest), ITEM_TRACKER_ITEM(QUEST_SKULL_TOKEN, 1 << 23, DrawQuest), ITEM_TRACKER_ITEM(QUEST_STONE_OF_AGONY, 1 << 21, DrawQuest),
|
||||
};
|
||||
|
||||
std::vector<ItemTrackerItem> dungeonRewardStones = {
|
||||
@ -297,35 +297,46 @@ ItemTrackerNumbers GetItemCurrentAndMax(ItemTrackerItem item) {
|
||||
result.maxCapacity = result.currentCapacity = 100;
|
||||
result.currentAmmo = gSaveContext.inventory.gsTokens;
|
||||
break;
|
||||
case ITEM_HEART_CONTAINER:
|
||||
result.maxCapacity = result.currentCapacity = 8;
|
||||
result.currentAmmo = gSaveContext.sohStats.heartContainers;
|
||||
break;
|
||||
case ITEM_HEART_PIECE:
|
||||
result.maxCapacity = result.currentCapacity = 36;
|
||||
result.currentAmmo = gSaveContext.sohStats.heartPieces;
|
||||
break;
|
||||
case ITEM_KEY_SMALL:
|
||||
// Though the ammo/capacity naming doesn't really make sense for keys, we are
|
||||
// hijacking the same system to display key counts as there are enough similarities
|
||||
result.currentAmmo = MAX(gSaveContext.inventory.dungeonKeys[item.data], 0);
|
||||
result.currentCapacity = gSaveContext.sohStats.dungeonKeys[item.data];
|
||||
switch (item.data) {
|
||||
case SCENE_BMORI1:
|
||||
result.maxCapacity = result.currentCapacity = FOREST_TEMPLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = FOREST_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_HIDAN:
|
||||
result.maxCapacity = result.currentCapacity = FIRE_TEMPLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = FIRE_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_MIZUSIN:
|
||||
result.maxCapacity = result.currentCapacity = WATER_TEMPLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = WATER_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_JYASINZOU:
|
||||
result.maxCapacity = result.currentCapacity = SPIRIT_TEMPLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = SPIRIT_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_HAKADAN:
|
||||
result.maxCapacity = result.currentCapacity = SHADOW_TEMPLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = SHADOW_TEMPLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_HAKADANCH:
|
||||
result.maxCapacity = result.currentCapacity = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX;
|
||||
result.maxCapacity = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_MEN:
|
||||
result.maxCapacity = result.currentCapacity = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX;
|
||||
result.maxCapacity = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_GERUDOWAY:
|
||||
result.maxCapacity = result.currentCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
|
||||
result.maxCapacity = GERUDO_FORTRESS_SMALL_KEY_MAX;
|
||||
break;
|
||||
case SCENE_GANONTIKA:
|
||||
result.maxCapacity = result.currentCapacity = GANONS_CASTLE_SMALL_KEY_MAX;
|
||||
result.maxCapacity = GANONS_CASTLE_SMALL_KEY_MAX;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -345,8 +356,32 @@ void DrawItemCount(ItemTrackerItem item) {
|
||||
ItemTrackerNumbers currentAndMax = GetItemCurrentAndMax(item);
|
||||
ImVec2 p = ImGui::GetCursorScreenPos();
|
||||
int32_t trackerNumberDisplayMode = CVar_GetS32("gItemTrackerCapacityTrack", 1);
|
||||
int32_t trackerKeyNumberDisplayMode = CVar_GetS32("gItemTrackerKeyTrack", 0);
|
||||
|
||||
if (currentAndMax.currentCapacity > 0 && trackerNumberDisplayMode != ITEM_TRACKER_NUMBER_NONE && IsValidSaveFile()) {
|
||||
if (item.id == ITEM_KEY_SMALL && IsValidSaveFile()) {
|
||||
std::string currentString = "";
|
||||
std::string maxString = std::to_string(currentAndMax.maxCapacity);
|
||||
ImU32 currentColor = IM_COL_WHITE;
|
||||
ImU32 maxColor = IM_COL_GREEN;
|
||||
// "Collected / Max", "Current / Collected / Max", "Current / Max"
|
||||
if (trackerKeyNumberDisplayMode == 1 || trackerKeyNumberDisplayMode == 2) {
|
||||
currentString+= std::to_string(currentAndMax.currentAmmo);
|
||||
currentString+= "/";
|
||||
}
|
||||
if (trackerKeyNumberDisplayMode == 0 || trackerKeyNumberDisplayMode == 1) {
|
||||
currentString+= std::to_string(currentAndMax.currentCapacity);
|
||||
currentString+= "/";
|
||||
}
|
||||
|
||||
ImGui::SetCursorScreenPos(ImVec2(p.x + (iconSize / 2) - (ImGui::CalcTextSize((currentString + maxString).c_str()).x / 2), p.y - 14));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, currentColor);
|
||||
ImGui::Text(currentString.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::SameLine(0, 0.0f);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, maxColor);
|
||||
ImGui::Text(maxString.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
} else if (currentAndMax.currentCapacity > 0 && trackerNumberDisplayMode != ITEM_TRACKER_NUMBER_NONE && IsValidSaveFile()) {
|
||||
std::string currentString = "";
|
||||
std::string maxString = "";
|
||||
ImU32 currentColor = IM_COL_WHITE;
|
||||
@ -362,7 +397,8 @@ void DrawItemCount(ItemTrackerItem item) {
|
||||
item.id == ITEM_BOMBCHU ||
|
||||
item.id == ITEM_BEAN ||
|
||||
item.id == QUEST_SKULL_TOKEN ||
|
||||
item.id == ITEM_KEY_SMALL;
|
||||
item.id == ITEM_HEART_CONTAINER ||
|
||||
item.id == ITEM_HEART_PIECE;
|
||||
|
||||
bool shouldDisplayMax = !(trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || trackerNumberDisplayMode == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY);
|
||||
|
||||
@ -445,7 +481,11 @@ void DrawItem(ItemTrackerItem item) {
|
||||
switch (item.id) {
|
||||
case ITEM_HEART_CONTAINER:
|
||||
actualItemId = item.id;
|
||||
hasItem = !!gSaveContext.doubleDefense;
|
||||
hasItem = gSaveContext.sohStats.heartContainers > 0;
|
||||
break;
|
||||
case ITEM_HEART_PIECE:
|
||||
actualItemId = item.id;
|
||||
hasItem = gSaveContext.sohStats.heartPieces > 0;
|
||||
break;
|
||||
case ITEM_MAGIC_SMALL:
|
||||
case ITEM_MAGIC_LARGE:
|
||||
@ -793,9 +833,6 @@ void UpdateVectors() {
|
||||
mainWindowItems.insert(mainWindowItems.end(), miscItems.begin(), miscItems.end());
|
||||
}
|
||||
if (CVar_GetS32("gItemTrackerDungeonRewardsDisplayType", 1) == 1) {
|
||||
if (CVar_GetS32("gItemTrackerMiscItemsDisplayType", 1) == 1) {
|
||||
mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
|
||||
}
|
||||
mainWindowItems.insert(mainWindowItems.end(), dungeonRewardStones.begin(), dungeonRewardStones.end());
|
||||
mainWindowItems.insert(mainWindowItems.end(), dungeonRewardMedallions.begin(), dungeonRewardMedallions.end());
|
||||
}
|
||||
@ -804,7 +841,6 @@ void UpdateVectors() {
|
||||
mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
|
||||
mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
|
||||
mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
|
||||
mainWindowItems.push_back(ITEM_TRACKER_ITEM(ITEM_NONE, 0, DrawItem));
|
||||
}
|
||||
mainWindowItems.insert(mainWindowItems.end(), songItems.begin(), songItems.end());
|
||||
}
|
||||
@ -910,6 +946,7 @@ void DrawItemTracker(bool& open) {
|
||||
}
|
||||
|
||||
const char* itemTrackerCapacityTrackOptions[5] = { "No Numbers", "Current Capacity", "Current Ammo", "Current Capacity / Max Capacity", "Current Ammo / Current Capacity" };
|
||||
const char* itemTrackerKeyTrackOptions[3] = { "Collected / Max", "Current / Collected / Max", "Current / Max" };
|
||||
|
||||
void DrawItemTrackerOptions(bool& open) {
|
||||
if (!open) {
|
||||
@ -965,6 +1002,9 @@ void DrawItemTrackerOptions(bool& open) {
|
||||
if (CVar_GetS32("gItemTrackerCapacityTrack", 1) == ITEM_TRACKER_NUMBER_CURRENT_CAPACITY_ONLY || CVar_GetS32("gItemTrackerCapacityTrack", 1) == ITEM_TRACKER_NUMBER_CURRENT_AMMO_ONLY) {
|
||||
PaddedEnhancementCheckbox("Align count to left side", "gItemTrackerCurrentOnLeft", 0);
|
||||
}
|
||||
ImGui::Text("Key Count Tracking");
|
||||
UIWidgets::EnhancementCombobox("gItemTrackerKeyTrack", itemTrackerKeyTrackOptions, 3, 0);
|
||||
UIWidgets::InsertHelpHoverText("Customize what numbers are shown for key tracking.");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
|
@ -254,8 +254,8 @@ namespace GameMenuBar {
|
||||
CVar_SetS32("gGuardVision", 0);
|
||||
// Enable passage of time on file select
|
||||
CVar_SetS32("gTimeFlowFileSelect", 0);
|
||||
// Count Golden Skulltulas
|
||||
CVar_SetS32("gInjectSkulltulaCount", 0);
|
||||
// Inject Item Counts in messages
|
||||
CVar_SetS32("gInjectItemCounts", 0);
|
||||
// Pull grave during the day
|
||||
CVar_SetS32("gDayGravePull", 0);
|
||||
// Pull out Ocarina to Summon Scarecrow
|
||||
@ -353,8 +353,8 @@ namespace GameMenuBar {
|
||||
CVar_SetS32("gAssignableTunicsAndBoots", 1);
|
||||
// Enable passage of time on file select
|
||||
CVar_SetS32("gTimeFlowFileSelect", 1);
|
||||
// Count Golden Skulltulas
|
||||
CVar_SetS32("gInjectSkulltulaCount", 1);
|
||||
// Inject Item Counts in messages
|
||||
CVar_SetS32("gInjectItemCounts", 1);
|
||||
|
||||
// Pause link animation (0 to 16)
|
||||
CVar_SetS32("gPauseLiveLink", 1);
|
||||
@ -998,8 +998,8 @@ namespace GameMenuBar {
|
||||
UIWidgets::Tooltip("Allows the Lon Lon Ranch obstacle course reward to be shared across time periods");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable visible guard vision", "gGuardVision", true, false);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Enable passage of time on file select", "gTimeFlowFileSelect", true, false);
|
||||
UIWidgets::PaddedEnhancementCheckbox("Count Golden Skulltulas", "gInjectSkulltulaCount", true, false);
|
||||
UIWidgets::Tooltip("Injects Golden Skulltula total count in pickup messages");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Item counts in messages", "gInjectItemCounts", true, false);
|
||||
UIWidgets::Tooltip("Injects item counts in pickup messages, like golden skulltula tokens and heart pieces");
|
||||
UIWidgets::PaddedEnhancementCheckbox("Pull grave during the day", "gDayGravePull", true, false);
|
||||
UIWidgets::Tooltip("Allows graves to be pulled when child during the day");
|
||||
|
||||
|
@ -1986,7 +1986,7 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
|
||||
}
|
||||
}
|
||||
if (textId == TEXT_GS_NO_FREEZE || textId == TEXT_GS_FREEZE) {
|
||||
if (CVar_GetS32("gInjectSkulltulaCount", 0) != 0) {
|
||||
if (CVar_GetS32("gInjectItemCounts", 0) != 0) {
|
||||
// The freeze text cannot be manually dismissed and must be auto-dismissed.
|
||||
// This is fine and even wanted when skull tokens are not shuffled, but when
|
||||
// when they are shuffled we don't want to be able to manually dismiss the box.
|
||||
@ -2004,6 +2004,14 @@ extern "C" int CustomMessage_RetrieveIfExists(GlobalContext* globalCtx) {
|
||||
CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{gsCount}}", std::to_string(gSaveContext.inventory.gsTokens + 1));
|
||||
}
|
||||
}
|
||||
if (textId == TEXT_HEART_CONTAINER && CVar_GetS32("gInjectItemCounts", 0)) {
|
||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_CONTAINER);
|
||||
CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{heartContainerCount}}", std::to_string(gSaveContext.sohStats.heartContainers + 1));
|
||||
}
|
||||
if (textId == TEXT_HEART_PIECE && CVar_GetS32("gInjectItemCounts", 0)) {
|
||||
messageEntry = CustomMessageManager::Instance->RetrieveMessage(customMessageTableID, TEXT_HEART_PIECE);
|
||||
CustomMessageManager::ReplaceStringInMessage(messageEntry, "{{heartPieceCount}}", std::to_string(gSaveContext.sohStats.heartPieces + 1));
|
||||
}
|
||||
if (messageEntry.textBoxType != -1) {
|
||||
font->charTexBuf[0] = (messageEntry.textBoxType << 4) | messageEntry.textBoxPos;
|
||||
switch (gSaveContext.language) {
|
||||
|
@ -416,6 +416,11 @@ void SaveManager::InitFileNormal() {
|
||||
}
|
||||
gSaveContext.inventory.defenseHearts = 0;
|
||||
gSaveContext.inventory.gsTokens = 0;
|
||||
gSaveContext.sohStats.heartPieces = 0;
|
||||
gSaveContext.sohStats.heartContainers = 0;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) {
|
||||
gSaveContext.sohStats.dungeonKeys[dungeon] = 0;
|
||||
}
|
||||
for (int scene = 0; scene < ARRAY_COUNT(gSaveContext.sceneFlags); scene++) {
|
||||
gSaveContext.sceneFlags[scene].chest = 0;
|
||||
gSaveContext.sceneFlags[scene].swch = 0;
|
||||
@ -561,6 +566,11 @@ void SaveManager::InitFileDebug() {
|
||||
}
|
||||
gSaveContext.inventory.defenseHearts = 0;
|
||||
gSaveContext.inventory.gsTokens = 0;
|
||||
gSaveContext.sohStats.heartPieces = 8;
|
||||
gSaveContext.sohStats.heartContainers = 8;
|
||||
for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) {
|
||||
gSaveContext.sohStats.dungeonKeys[dungeon] = 8;
|
||||
}
|
||||
|
||||
gSaveContext.horseData.scene = SCENE_SPOT00;
|
||||
gSaveContext.horseData.pos.x = -1840;
|
||||
@ -955,6 +965,13 @@ void SaveManager::LoadBaseVersion2() {
|
||||
SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts);
|
||||
SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens);
|
||||
});
|
||||
SaveManager::Instance->LoadStruct("sohStats", []() {
|
||||
SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces);
|
||||
SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers);
|
||||
SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) {
|
||||
SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]);
|
||||
});
|
||||
});
|
||||
SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) {
|
||||
SaveManager::Instance->LoadStruct("", [&i]() {
|
||||
SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest);
|
||||
@ -1109,6 +1126,13 @@ void SaveManager::SaveBase() {
|
||||
SaveManager::Instance->SaveData("defenseHearts", gSaveContext.inventory.defenseHearts);
|
||||
SaveManager::Instance->SaveData("gsTokens", gSaveContext.inventory.gsTokens);
|
||||
});
|
||||
SaveManager::Instance->SaveStruct("sohStats", []() {
|
||||
SaveManager::Instance->SaveData("heartPieces", gSaveContext.sohStats.heartPieces);
|
||||
SaveManager::Instance->SaveData("heartContainers", gSaveContext.sohStats.heartContainers);
|
||||
SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) {
|
||||
SaveManager::Instance->SaveData("", gSaveContext.sohStats.dungeonKeys[i]);
|
||||
});
|
||||
});
|
||||
SaveManager::Instance->SaveArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) {
|
||||
SaveManager::Instance->SaveStruct("", [&i]() {
|
||||
SaveManager::Instance->SaveData("chest", gSaveContext.sceneFlags[i].chest);
|
||||
|
@ -75,7 +75,7 @@ std::vector<std::string> sceneNames = {
|
||||
"Castle Hedge Maze (Day)",
|
||||
"Castle Hedge Maze (Night)",
|
||||
"Cutscene Map",
|
||||
"Dampé's Grave & Windmill",
|
||||
"Damp<EFBFBD>'s Grave & Windmill",
|
||||
"Fishing Pond",
|
||||
"Castle Courtyard",
|
||||
"Bombchu Bowling Alley",
|
||||
@ -231,7 +231,7 @@ std::vector<std::string> itemNames = {
|
||||
"Gerudo's Card",
|
||||
"Gold Skulltula Token",
|
||||
"Heart Container",
|
||||
"Piece of Heart [?]",
|
||||
"Piece of Heart",
|
||||
"Big Key",
|
||||
"Compass",
|
||||
"Dungeon Map",
|
||||
|
@ -132,4 +132,22 @@ extern "C" void OTRMessage_Init()
|
||||
"\x08Missiles 10 unités 99 Rubis\x09&&\x1B%gAcheter&Ne pas acheter%w",
|
||||
}
|
||||
);
|
||||
CustomMessageManager::Instance->CreateGetItemMessage(
|
||||
customMessageTableID, (GetItemID)TEXT_HEART_CONTAINER, ITEM_HEART_CONTAINER,
|
||||
{
|
||||
TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM,
|
||||
"You got a %rHeart Container%w!&You've collected %r{{heartContainerCount}}%w containers&in total!",
|
||||
"Du erhältst ein %rHerzgefäß%w! Du&hast insgesamt %r{{heartContainerCount}}%w Gefäße&gesammelt!",
|
||||
"Vous obtenez un %rRécipient de&coeur%w! Vous avez&collecté %r{{heartContainerCount}}%w récipients en tout!"
|
||||
}
|
||||
);
|
||||
CustomMessageManager::Instance->CreateGetItemMessage(
|
||||
customMessageTableID, (GetItemID)TEXT_HEART_PIECE, ITEM_HEART_PIECE,
|
||||
{
|
||||
TEXTBOX_TYPE_BLUE, TEXTBOX_POS_BOTTOM,
|
||||
"You got a %rHeart Piece%w!&You've collected %r{{heartPieceCount}}%w pieces&in total!",
|
||||
"Du erhältst ein %rHerzteil%w! Du hast&insgesamt %r{{heartPieceCount}}%w Teile&gesammelt!",
|
||||
"Vous obtenez un %rMorceau de&coeur%w! Vous avez&collecté %r{{heartPieceCount}}%w morceaux en tout!"
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -1760,6 +1760,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
// but we check for a globalCtx here so the game won't crash if we do somehow get here.
|
||||
if (gSaveContext.n64ddFlag && globalCtx != NULL) {
|
||||
if (globalCtx->sceneNum == 10) { // ganon's tower -> ganon's castle
|
||||
gSaveContext.sohStats.dungeonKeys[13]++;
|
||||
if (gSaveContext.inventory.dungeonKeys[13] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[13] = 1;
|
||||
PerformAutosave(globalCtx, item);
|
||||
@ -1772,6 +1773,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
}
|
||||
|
||||
if (globalCtx->sceneNum == 92) { // Desert Colossus -> Spirit Temple.
|
||||
gSaveContext.sohStats.dungeonKeys[6]++;
|
||||
if (gSaveContext.inventory.dungeonKeys[6] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[6] = 1;
|
||||
PerformAutosave(globalCtx, item);
|
||||
@ -1783,6 +1785,7 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
}
|
||||
}
|
||||
}
|
||||
gSaveContext.sohStats.dungeonKeys[gSaveContext.mapIndex]++;
|
||||
if (gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[gSaveContext.mapIndex] = 1;
|
||||
PerformAutosave(globalCtx, item);
|
||||
@ -2132,11 +2135,13 @@ u8 Item_Give(GlobalContext* globalCtx, u8 item) {
|
||||
return ITEM_NONE;
|
||||
} else if ((item == ITEM_HEART_PIECE_2) || (item == ITEM_HEART_PIECE)) {
|
||||
gSaveContext.inventory.questItems += 1 << (QUEST_HEART_PIECE + 4);
|
||||
gSaveContext.sohStats.heartPieces++;
|
||||
PerformAutosave(globalCtx, item);
|
||||
return ITEM_NONE;
|
||||
} else if (item == ITEM_HEART_CONTAINER) {
|
||||
gSaveContext.healthCapacity += 0x10;
|
||||
gSaveContext.health += 0x10;
|
||||
gSaveContext.sohStats.heartContainers++;
|
||||
PerformAutosave(globalCtx, item);
|
||||
return ITEM_NONE;
|
||||
} else if (item == ITEM_HEART) {
|
||||
@ -2447,6 +2452,7 @@ u16 Randomizer_Item_Give(GlobalContext* globalCtx, GetItemEntry giEntry) {
|
||||
}
|
||||
|
||||
if ((item >= RG_FOREST_TEMPLE_SMALL_KEY) && (item <= RG_GANONS_CASTLE_SMALL_KEY)) {
|
||||
gSaveContext.sohStats.dungeonKeys[mapIndex]++;
|
||||
if (gSaveContext.inventory.dungeonKeys[mapIndex] < 0) {
|
||||
gSaveContext.inventory.dungeonKeys[mapIndex] = 1;
|
||||
return RG_NONE;
|
||||
|
@ -461,13 +461,21 @@ void Sram_InitSave(FileChooseContext* fileChooseCtx) {
|
||||
if(Randomizer_GetSettingValue(RSK_KEYSANITY) == 0) {
|
||||
// TODO: If master quest there are different key counts
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_BMORI1] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_BMORI1] = FOREST_TEMPLE_SMALL_KEY_MAX; // Forest
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_HIDAN] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_HIDAN] = FIRE_TEMPLE_SMALL_KEY_MAX; // Fire
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_MIZUSIN] = WATER_TEMPLE_SMALL_KEY_MAX; // Water
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_MIZUSIN] = WATER_TEMPLE_SMALL_KEY_MAX; // Water
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_JYASINZOU] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_JYASINZOU] = SPIRIT_TEMPLE_SMALL_KEY_MAX; // Spirit
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_HAKADAN] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_HAKADAN] = SHADOW_TEMPLE_SMALL_KEY_MAX; // Shadow
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_HAKADANCH] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_HAKADANCH] = BOTTOM_OF_THE_WELL_SMALL_KEY_MAX; // BotW
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_MEN] = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; // GTG
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_MEN] = GERUDO_TRAINING_GROUNDS_SMALL_KEY_MAX; // GTG
|
||||
gSaveContext.inventory.dungeonKeys[SCENE_GANONTIKA] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon
|
||||
gSaveContext.sohStats.dungeonKeys[SCENE_GANONTIKA] = GANONS_CASTLE_SMALL_KEY_MAX; // Ganon
|
||||
}
|
||||
|
||||
// "Start with" == 0 for Boss Kesanity
|
||||
|
Loading…
Reference in New Issue
Block a user