mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2024-08-13 17:03:47 -04:00
1070 lines
49 KiB
C++
1070 lines
49 KiB
C++
#include "randomizer_check_tracker.h"
|
|
#include "../../OTRGlobals.h"
|
|
#include <ImGuiImpl.h>
|
|
#include "../../UIWidgets.hpp"
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <set>
|
|
#include <libultraship/bridge.h>
|
|
#include <Hooks.h>
|
|
#include "3drando/item_location.hpp"
|
|
|
|
extern "C" {
|
|
#include "variables.h"
|
|
#include "functions.h"
|
|
#include "macros.h"
|
|
extern PlayState* gPlayState;
|
|
}
|
|
extern "C" uint32_t ResourceMgr_IsSceneMasterQuest(s16 sceneNum);
|
|
|
|
namespace CheckTracker {
|
|
|
|
void Teardown();
|
|
void InitializeChecks();
|
|
void UpdateChecks();
|
|
void UpdateInventoryChecks();
|
|
void DrawLocation(RandomizerCheckObject rcObj, RandomizerCheckShow* thisCheckStatus);
|
|
void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0);
|
|
void EndFloatWindows();
|
|
void UpdateOrdering(bool init = false);
|
|
bool ShouldUpdateChecks();
|
|
bool CompareCheckObject(RandomizerCheckObject i, RandomizerCheckObject j);
|
|
bool HasItemBeenCollected(RandomizerCheckObject obj);
|
|
bool HasItemBeenSkipped(RandomizerCheckObject obj);
|
|
void RainbowTick();
|
|
RandomizerCheckShow GetCheckStatus(RandomizerCheckObject rcObj, int idx);
|
|
|
|
|
|
Color_RGBA8 Color_Bg_Default = { 0, 0, 0, 255 }; // Black
|
|
Color_RGBA8 Color_Main_Default = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Area_Incomplete_Extra_Default = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Area_Complete_Extra_Default = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Unchecked_Extra_Default = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Skipped_Main_Default = { 160, 160, 160, 255 }; // Grey
|
|
Color_RGBA8 Color_Skipped_Extra_Default = { 160, 160, 160, 255 }; // Grey
|
|
Color_RGBA8 Color_Seen_Extra_Default = { 255, 255, 255, 255 }; // TODO
|
|
Color_RGBA8 Color_Hinted_Extra_Default = { 255, 255, 255, 255 }; // TODO
|
|
Color_RGBA8 Color_Checked_Extra_Default = { 255, 255, 255, 255 }; // TODO
|
|
Color_RGBA8 Color_Scummed_Extra_Default = { 255, 255, 255, 255 }; // TODO
|
|
Color_RGBA8 Color_Saved_Extra_Default = { 0, 185, 0, 255 }; // Green
|
|
|
|
Color_RGBA8 Color_Background = { 0, 0, 0, 255 };
|
|
|
|
Color_RGBA8 Color_Area_Incomplete_Main = { 255, 255, 255, 255 }; //White
|
|
Color_RGBA8 Color_Area_Incomplete_Extra = { 255, 255, 255, 255 }; //White
|
|
Color_RGBA8 Color_Area_Complete_Main = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Area_Complete_Extra = { 255, 255, 255, 255 }; // White
|
|
Color_RGBA8 Color_Unchecked_Main = { 255, 255, 255, 255 }; //White
|
|
Color_RGBA8 Color_Unchecked_Extra = { 255, 255, 255, 255 }; //Useless
|
|
Color_RGBA8 Color_Skipped_Main = { 255, 255, 255, 255 }; //Grey
|
|
Color_RGBA8 Color_Skipped_Extra = { 255, 255, 255, 255 }; //Grey
|
|
Color_RGBA8 Color_Seen_Main = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Seen_Extra = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Hinted_Main = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Hinted_Extra = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Checked_Main = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Checked_Extra = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Scummed_Main = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Scummed_Extra = { 255, 255, 255, 255 }; //TODO
|
|
Color_RGBA8 Color_Saved_Main = { 255, 255, 255, 255 }; //White
|
|
Color_RGBA8 Color_Saved_Extra = { 0, 185, 0, 255 }; //Green
|
|
|
|
SceneID DungeonSceneLookupByArea(RandomizerCheckArea area) {
|
|
switch (area) {
|
|
case RCAREA_DEKU_TREE: return SCENE_YDAN;
|
|
case RCAREA_DODONGOS_CAVERN: return SCENE_DDAN;
|
|
case RCAREA_JABU_JABUS_BELLY: return SCENE_BDAN;
|
|
case RCAREA_FOREST_TEMPLE: return SCENE_BMORI1;
|
|
case RCAREA_FIRE_TEMPLE: return SCENE_HIDAN;
|
|
case RCAREA_WATER_TEMPLE: return SCENE_MIZUSIN;
|
|
case RCAREA_SPIRIT_TEMPLE: return SCENE_JYASINZOU;
|
|
case RCAREA_SHADOW_TEMPLE: return SCENE_HAKADAN;
|
|
case RCAREA_BOTTOM_OF_THE_WELL: return SCENE_HAKADANCH;
|
|
case RCAREA_ICE_CAVERN: return SCENE_ICE_DOUKUTO;
|
|
case RCAREA_GERUDO_TRAINING_GROUND: return SCENE_MEN;
|
|
case RCAREA_GANONS_CASTLE: return SCENE_GANONTIKA;
|
|
default: return SCENE_ID_MAX;
|
|
}
|
|
}
|
|
|
|
// persistent during gameplay
|
|
bool initialized = false;
|
|
bool doInitialize = false;
|
|
std::map<RandomizerCheck, RandomizerCheckShow> checkStatusMap;
|
|
u32 areasFullyChecked = 0;
|
|
u32 areasSpoiled = 0;
|
|
bool showVOrMQ;
|
|
s8 areaChecksTotal[32]; //| For sorting and showing
|
|
s8 areaChecksGotten[32]; //| "Kokiri Forest (4/9)"
|
|
std::vector<RandomizerCheckObject> checks;
|
|
bool optCollapseAll; // A bool that will collapse all checks once
|
|
bool optExpandAll; // A bool that will expand all checks once
|
|
RandomizerCheck lastLocationChecked = RC_UNKNOWN_CHECK;
|
|
RandomizerCheckArea previousArea = RCAREA_INVALID;
|
|
RandomizerCheckArea currentArea = RCAREA_INVALID;
|
|
OSContPad* trackerButtonsPressed;
|
|
|
|
std::vector<uint32_t> buttons = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L,
|
|
BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
|
|
|
|
void DrawCheckTracker(bool& open) {
|
|
if (!open) {
|
|
CVarSetInteger("gCheckTrackerEnabled", 0);
|
|
return;
|
|
}
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(400, 540), ImGuiCond_FirstUseEver);
|
|
|
|
if (doInitialize) {
|
|
Teardown();
|
|
InitializeChecks();
|
|
} else if (initialized && (gPlayState == nullptr || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2)) {
|
|
Teardown();
|
|
return;
|
|
}
|
|
|
|
if (CVarGetInteger("gCheckTrackerWindowType", 1) == 0) {
|
|
if (CVarGetInteger("gCheckTrackerShowOnlyPaused", 0) == 1)
|
|
if (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)
|
|
return;
|
|
|
|
if (CVarGetInteger("gCheckTrackerDisplayType", 0) == 1) {
|
|
int comboButton1Mask = buttons[CVarGetInteger("gCheckTrackerComboButton1", 6)];
|
|
int comboButton2Mask = buttons[CVarGetInteger("gCheckTrackerComboButton2", 8)];
|
|
bool comboButtonsHeld = trackerButtonsPressed != nullptr &&
|
|
trackerButtonsPressed[0].button & comboButton1Mask &&
|
|
trackerButtonsPressed[0].button & comboButton2Mask;
|
|
if (!comboButtonsHeld)
|
|
return;
|
|
}
|
|
}
|
|
|
|
BeginFloatWindows("Check Tracker", open, ImGuiWindowFlags_NoScrollbar);
|
|
|
|
if (!initialized) {
|
|
ImGui::Text("Waiting for file load..."); //TODO Language
|
|
EndFloatWindows();
|
|
return;
|
|
}
|
|
|
|
SceneID sceneId = SCENE_ID_MAX;
|
|
if (gPlayState != nullptr) {
|
|
sceneId = (SceneID)gPlayState->sceneNum;
|
|
currentArea = RandomizerCheckObjects::GetRCAreaBySceneID(sceneId);
|
|
}
|
|
|
|
bool doAreaScroll =
|
|
(currentArea != RCAREA_INVALID && currentArea != previousArea &&
|
|
sceneId != SCENE_KAKUSIANA && // Don't move for grottos
|
|
sceneId != SCENE_YOUSEI_IZUMI_TATE && sceneId != SCENE_YOUSEI_IZUMI_YOKO && sceneId != SCENE_DAIYOUSEI_IZUMI && // Don't move for fairy fountains
|
|
sceneId != SCENE_SHOP1 && sceneId != SCENE_SYATEKIJYOU // Don't move for Bazaar/Gallery, as it moves between Kak and Market
|
|
);
|
|
previousArea = currentArea;
|
|
areasSpoiled |= (1 << currentArea);
|
|
|
|
//Only update the checks if something has changed
|
|
if (ShouldUpdateChecks()) {
|
|
UpdateChecks();
|
|
UpdateInventoryChecks();
|
|
UpdateOrdering();
|
|
}
|
|
|
|
|
|
//Quick Options
|
|
#ifdef __WIIU__
|
|
float headerHeight = 40.0f;
|
|
#else
|
|
float headerHeight = 20.0f;
|
|
#endif
|
|
ImVec2 size = ImGui::GetContentRegionMax();
|
|
size.y -= headerHeight;
|
|
if (!ImGui::BeginTable("Check Tracker", 1, 0, size)) {
|
|
EndFloatWindows();
|
|
return;
|
|
}
|
|
|
|
ImGui::TableNextRow(0, headerHeight);
|
|
ImGui::TableNextColumn();
|
|
UIWidgets::EnhancementCheckbox(
|
|
"Show Hidden Items", "gCheckTrackerOptionShowHidden", false,
|
|
"When active, items will show hidden checks by default when updated to this state.");
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Expand All")) {
|
|
optCollapseAll = false;
|
|
optExpandAll = true;
|
|
}
|
|
ImGui::SameLine();
|
|
if (ImGui::Button("Collapse All")) {
|
|
optExpandAll = false;
|
|
optCollapseAll = true;
|
|
}
|
|
UIWidgets::PaddedSeparator();
|
|
|
|
//Checks Section Lead-in
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
size = ImGui::GetContentRegionAvail();
|
|
if (!ImGui::BeginTable("CheckTracker##Checks", 1, ImGuiTableFlags_ScrollY, size)) {
|
|
ImGui::EndTable();
|
|
EndFloatWindows();
|
|
return;
|
|
}
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
|
|
//Prep for loop
|
|
RainbowTick();
|
|
bool doDraw = false;
|
|
bool thisAreaFullyChecked = false;
|
|
bool showHidden = CVarGetInteger("gCheckTrackerOptionShowHidden", 0);
|
|
bool hideIncomplete = CVarGetInteger("gCheckTrackerAreaIncompleteHide", 0);
|
|
bool hideComplete = CVarGetInteger("gCheckTrackerAreaCompleteHide", 0);
|
|
bool collapseLogic;
|
|
bool doingCollapseOrExpand = optExpandAll || optCollapseAll;
|
|
bool isThisAreaSpoiled;
|
|
RandomizerCheckArea lastArea = RCAREA_INVALID;
|
|
Color_RGBA8 areaCompleteColor = CVarGetColor("gCheckTrackerAreaMainCompleteColor", Color_Main_Default);
|
|
Color_RGBA8 areaIncompleteColor = CVarGetColor("gCheckTrackerAreaMainIncompleteColor", Color_Main_Default);
|
|
Color_RGBA8 extraCompleteColor = CVarGetColor("gCheckTrackerAreaExtraCompleteColor", Color_Area_Complete_Extra_Default);
|
|
Color_RGBA8 extraIncompleteColor = CVarGetColor("gCheckTrackerAreaExtraIncompleteColor", Color_Area_Incomplete_Extra_Default);
|
|
Color_RGBA8 mainColor;
|
|
Color_RGBA8 extraColor;
|
|
std::string stemp;
|
|
s32 areaMask = 1;
|
|
|
|
// Logic for each check
|
|
for (auto& obj : checks)
|
|
{
|
|
|
|
//New Area to be drawn
|
|
if (obj.rcArea != lastArea)
|
|
{
|
|
//Last Area needs to be cleaned up
|
|
if (lastArea != RCAREA_INVALID && doDraw) {
|
|
ImGui::TreePop();
|
|
UIWidgets::PaddedSeparator();
|
|
}
|
|
lastArea = obj.rcArea;
|
|
|
|
//Decide if we should skip because of hiding rules
|
|
thisAreaFullyChecked = ((areasFullyChecked & areaMask) != 0);
|
|
if (!showHidden && (
|
|
hideComplete && thisAreaFullyChecked ||
|
|
hideIncomplete && !thisAreaFullyChecked
|
|
)) {
|
|
doDraw = false;
|
|
}
|
|
else {
|
|
//Get the colour for the area
|
|
if (thisAreaFullyChecked) {
|
|
mainColor = areaCompleteColor;
|
|
extraColor = extraCompleteColor;
|
|
} else {
|
|
mainColor = areaIncompleteColor;
|
|
extraColor = extraIncompleteColor;
|
|
}
|
|
|
|
//Draw the area
|
|
collapseLogic = !thisAreaFullyChecked;
|
|
if (doingCollapseOrExpand) {
|
|
if (optExpandAll) {
|
|
collapseLogic = true;
|
|
} else if (optCollapseAll) {
|
|
collapseLogic = false;
|
|
}
|
|
}
|
|
stemp = RandomizerCheckObjects::GetRCAreaName(obj.rcArea) + "##TreeNode";
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f,
|
|
mainColor.b / 255.0f, mainColor.a / 255.0f));
|
|
if (doingCollapseOrExpand)
|
|
ImGui::SetNextItemOpen(collapseLogic, ImGuiCond_Always);
|
|
else
|
|
ImGui::SetNextItemOpen(!thisAreaFullyChecked, ImGuiCond_Once);
|
|
doDraw = ImGui::TreeNode(stemp.c_str());
|
|
ImGui::PopStyleColor();
|
|
ImGui::SameLine();
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f,
|
|
extraColor.b / 255.0f, extraColor.a / 255.0f));
|
|
|
|
isThisAreaSpoiled = areasSpoiled & areaMask || CVarGetInteger("gCheckTrackerOptionMQSpoilers", 0);
|
|
|
|
if (isThisAreaSpoiled) {
|
|
if (showVOrMQ && RandomizerCheckObjects::AreaIsDungeon(obj.rcArea)) {
|
|
if (OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(DungeonSceneLookupByArea(obj.rcArea)))
|
|
ImGui::Text("(%d/%d) - MQ", areaChecksGotten[obj.rcArea], areaChecksTotal[obj.rcArea]);
|
|
else
|
|
ImGui::Text("(%d/%d) - Vanilla", areaChecksGotten[obj.rcArea], areaChecksTotal[obj.rcArea]);
|
|
} else {
|
|
ImGui::Text("(%d/%d)", areaChecksGotten[obj.rcArea], areaChecksTotal[obj.rcArea]);
|
|
}
|
|
} else {
|
|
ImGui::Text("???", areaChecksGotten[obj.rcArea], areaChecksTotal[obj.rcArea]);
|
|
}
|
|
|
|
ImGui::PopStyleColor();
|
|
|
|
//Keep areas loaded between transitions
|
|
if (currentArea == obj.rcArea && doAreaScroll)
|
|
ImGui::SetScrollHereY(0.0f);
|
|
}
|
|
|
|
areaMask <<= 1;
|
|
}
|
|
|
|
if (doDraw && isThisAreaSpoiled)
|
|
DrawLocation(obj, &checkStatusMap.find(obj.rc)->second);
|
|
}
|
|
|
|
//Clean up last area
|
|
if (doDraw)
|
|
ImGui::TreePop();
|
|
|
|
ImGui::EndTable(); //Checks Lead-out
|
|
ImGui::EndTable(); //Quick Options Lead-out
|
|
EndFloatWindows();
|
|
if (doingCollapseOrExpand) {
|
|
optCollapseAll = false;
|
|
optExpandAll = false;
|
|
}
|
|
}
|
|
|
|
// Windowing stuff
|
|
void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags) {
|
|
ImGuiWindowFlags windowFlags = flags;
|
|
|
|
if (windowFlags == 0) {
|
|
windowFlags |=
|
|
ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoFocusOnAppearing;
|
|
}
|
|
|
|
if (!CVarGetInteger("gCheckTrackerWindowType", 1)) {
|
|
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
|
|
windowFlags |= ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar |
|
|
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar;
|
|
|
|
if (!CVarGetInteger("gCheckTrackerHudEditMode", 0)) {
|
|
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
|
|
}
|
|
}
|
|
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(Color_Background.r / 255.0f, Color_Background.g / 255.0f,
|
|
Color_Background.b / 255.0f, Color_Background.a / 255.0f));
|
|
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
|
|
ImGui::Begin(UniqueName.c_str(), &open, windowFlags);
|
|
}
|
|
void EndFloatWindows() {
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor();
|
|
ImGui::PopStyleColor();
|
|
ImGui::End();
|
|
}
|
|
|
|
bool showShops;
|
|
bool showOverworldTokens;
|
|
bool showDungeonTokens;
|
|
bool showBeans;
|
|
bool showScrubs;
|
|
bool showMerchants;
|
|
bool showCows;
|
|
bool showAdultTrade;
|
|
bool showKokiriSword;
|
|
bool showWeirdEgg;
|
|
bool showGerudoCard;
|
|
bool showFrogSongRupees;
|
|
bool showStartingMapsCompasses;
|
|
bool showKeysanity;
|
|
bool showGerudoFortressKeys;
|
|
bool showBossKeysanity;
|
|
bool showGanonBossKey;
|
|
bool showOcarinas;
|
|
bool show100SkullReward;
|
|
bool fortressFast;
|
|
bool fortressNormal;
|
|
|
|
void LoadSettings() {
|
|
//If in randomzer (n64ddFlag), then get the setting and check if in general we should be showing the settings
|
|
//If in vanilla, _try_ to show items that at least are needed for 100%
|
|
|
|
showShops = gSaveContext.n64ddFlag ? (
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_OFF &&
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHOPSANITY) != RO_SHOPSANITY_ZERO_ITEMS)
|
|
: false;
|
|
showBeans = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MAGIC_BEANS) == RO_GENERIC_YES
|
|
: true;
|
|
showScrubs = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_SCRUBS) != RO_SCRUBS_OFF
|
|
: false;
|
|
showMerchants = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_MERCHANTS) != RO_SHUFFLE_MERCHANTS_OFF
|
|
: true;
|
|
showCows = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_COWS) == RO_GENERIC_YES
|
|
: false;
|
|
showAdultTrade = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_ADULT_TRADE) == RO_GENERIC_YES
|
|
: true;
|
|
showKokiriSword = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_KOKIRI_SWORD) == RO_GENERIC_YES
|
|
: true;
|
|
showWeirdEgg = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_WEIRD_EGG) == RO_GENERIC_YES
|
|
: true;
|
|
showGerudoCard = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_GERUDO_MEMBERSHIP_CARD) == RO_GENERIC_YES
|
|
: true;
|
|
showFrogSongRupees = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_FROG_SONG_RUPEES) == RO_GENERIC_YES
|
|
: false;
|
|
showStartingMapsCompasses = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_MAPS_COMPASSES) != RO_DUNGEON_ITEM_LOC_VANILLA
|
|
: false;
|
|
showKeysanity = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_KEYSANITY) != RO_DUNGEON_ITEM_LOC_VANILLA
|
|
: false;
|
|
showBossKeysanity = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_BOSS_KEYSANITY) != RO_DUNGEON_ITEM_LOC_VANILLA
|
|
: false;
|
|
showGerudoFortressKeys = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_KEYS) != RO_GERUDO_KEYS_VANILLA
|
|
: false;
|
|
showGanonBossKey = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GANONS_BOSS_KEY) != RO_GANON_BOSS_KEY_VANILLA
|
|
: false;
|
|
showOcarinas = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_OCARINA) == RO_GENERIC_YES
|
|
: false;
|
|
show100SkullReward = gSaveContext.n64ddFlag ?
|
|
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_100_GS_REWARD) == RO_GENERIC_YES
|
|
: false;
|
|
|
|
if (gSaveContext.n64ddFlag) {
|
|
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_TOKENS)) {
|
|
case RO_TOKENSANITY_ALL:
|
|
showOverworldTokens = true;
|
|
showDungeonTokens = true;
|
|
break;
|
|
case RO_TOKENSANITY_OVERWORLD:
|
|
showOverworldTokens = true;
|
|
showDungeonTokens = false;
|
|
break;
|
|
case RO_TOKENSANITY_DUNGEONS:
|
|
showOverworldTokens = false;
|
|
showDungeonTokens = true;
|
|
break;
|
|
default:
|
|
showOverworldTokens = false;
|
|
showDungeonTokens = false;
|
|
break;
|
|
}
|
|
} else { // Vanilla
|
|
showOverworldTokens = true;
|
|
showDungeonTokens = true;
|
|
}
|
|
|
|
fortressFast = false;
|
|
fortressNormal = false;
|
|
switch (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_GERUDO_FORTRESS)) {
|
|
case RO_GF_OPEN:
|
|
showGerudoFortressKeys = false;
|
|
showGerudoCard = false;
|
|
break;
|
|
case RO_GF_FAST:
|
|
fortressFast = true;
|
|
break;
|
|
case RO_GF_NORMAL:
|
|
fortressNormal = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool IsVisibleInCheckTracker(RandomizerCheckObject rcObj) {
|
|
return
|
|
(rcObj.rcArea != RCAREA_INVALID) && // don't show Invalid locations
|
|
(rcObj.rcType != RCTYPE_GOSSIP_STONE) && //TODO: Don't show hints until tracker supports them
|
|
(rcObj.rcType != RCTYPE_CHEST_GAME) && // don't show non final reward chest game checks until we support shuffling them
|
|
(rcObj.rc != RC_HC_ZELDAS_LETTER) && // don't show zeldas letter until we support shuffling it
|
|
(!RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea) ||
|
|
rcObj.vOrMQ == RCVORMQ_BOTH ||
|
|
rcObj.vOrMQ == RCVORMQ_MQ && OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId) ||
|
|
rcObj.vOrMQ == RCVORMQ_VANILLA && !OTRGlobals::Instance->gRandomizer->masterQuestDungeons.contains(rcObj.sceneId)
|
|
) &&
|
|
(rcObj.rcType != RCTYPE_SHOP || showShops) &&
|
|
(rcObj.rcType != RCTYPE_SCRUB ||
|
|
showScrubs ||
|
|
rcObj.rc == RC_LW_DEKU_SCRUB_NEAR_BRIDGE || // The 3 scrubs that are always randomized
|
|
rcObj.rc == RC_HF_DEKU_SCRUB_GROTTO ||
|
|
rcObj.rc == RC_LW_DEKU_SCRUB_GROTTO_FRONT
|
|
) &&
|
|
(rcObj.rcType != RCTYPE_MERCHANT || showMerchants) &&
|
|
(rcObj.rcType != RCTYPE_OCARINA || showOcarinas) &&
|
|
(rcObj.rcType != RCTYPE_SKULL_TOKEN ||
|
|
(showOverworldTokens && RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea)) ||
|
|
(showDungeonTokens && RandomizerCheckObjects::AreaIsDungeon(rcObj.rcArea))
|
|
) &&
|
|
(rcObj.rcType != RCTYPE_COW || showCows) &&
|
|
(rcObj.rcType != RCTYPE_ADULT_TRADE ||
|
|
showAdultTrade ||
|
|
rcObj.rc == RC_KAK_ANJU_AS_ADULT || // adult trade checks that are always shuffled
|
|
rcObj.rc == RC_DMT_TRADE_CLAIM_CHECK // even when shuffle adult trade is off
|
|
) &&
|
|
(rcObj.rc != RC_KF_KOKIRI_SWORD_CHEST || showKokiriSword) &&
|
|
(rcObj.rc != RC_ZR_MAGIC_BEAN_SALESMAN || showBeans) &&
|
|
(rcObj.rc != RC_HC_MALON_EGG || showWeirdEgg) &&
|
|
(rcObj.rcType != RCTYPE_FROG_SONG || showFrogSongRupees) &&
|
|
(rcObj.rcType != RCTYPE_MAP_COMPASS || showStartingMapsCompasses) &&
|
|
(rcObj.rcType != RCTYPE_SMALL_KEY || showKeysanity) &&
|
|
(rcObj.rcType != RCTYPE_BOSS_KEY || showBossKeysanity) &&
|
|
(rcObj.rcType != RCTYPE_GANON_BOSS_KEY || showGanonBossKey) &&
|
|
(rcObj.rc != RC_KAK_100_GOLD_SKULLTULA_REWARD || show100SkullReward) &&
|
|
(rcObj.rcType != RCTYPE_GF_KEY && rcObj.rc != RC_GF_GERUDO_MEMBERSHIP_CARD ||
|
|
(showGerudoCard && rcObj.rc == RC_GF_GERUDO_MEMBERSHIP_CARD) ||
|
|
(fortressNormal && showGerudoFortressKeys && rcObj.rcType == RCTYPE_GF_KEY) ||
|
|
(fortressFast && showGerudoFortressKeys && rcObj.rc == RC_GF_NORTH_F1_CARPENTER)
|
|
);
|
|
}
|
|
|
|
|
|
void InitializeChecks() {
|
|
if (gPlayState == nullptr || gSaveContext.fileNum < 0 || gSaveContext.fileNum > 2)
|
|
return;
|
|
|
|
int count = 0;
|
|
|
|
//Link's Pocket
|
|
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING) {
|
|
s8 startingAge = OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_STARTING_AGE);
|
|
RandomizerCheckArea startingArea;
|
|
switch (startingAge) {
|
|
case RO_AGE_CHILD:
|
|
startingArea = RCAREA_KOKIRI_FOREST;
|
|
break;
|
|
case RO_AGE_ADULT:
|
|
startingArea = RCAREA_MARKET;
|
|
break;
|
|
default:
|
|
startingArea = RCAREA_KOKIRI_FOREST;
|
|
break;
|
|
}
|
|
RandomizerCheckObject linksPocket = { RC_LINKS_POCKET, RCVORMQ_BOTH, RCTYPE_LINKS_POCKET, startingArea, ACTOR_ID_MAX, SCENE_ID_MAX, 0x00, GI_NONE, false, "Link's Pocket", "Link's Pocket" };
|
|
|
|
checks.push_back(linksPocket);
|
|
checkStatusMap.emplace(RC_LINKS_POCKET, RCSHOW_SAVED);
|
|
count++;
|
|
areaChecksTotal[startingArea]++;
|
|
areaChecksGotten[startingArea]++;
|
|
}
|
|
|
|
LoadSettings();
|
|
for (auto& [rcCheck, rcObj] : RandomizerCheckObjects::GetAllRCObjects()) {
|
|
if (!IsVisibleInCheckTracker(rcObj))
|
|
continue;
|
|
|
|
checks.push_back(rcObj);
|
|
checkStatusMap.emplace(rcObj.rc, RCSHOW_UNCHECKED);
|
|
count++;
|
|
areaChecksTotal[rcObj.rcArea]++;
|
|
|
|
if (areaChecksGotten[rcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea))
|
|
areasSpoiled |= (1 << rcObj.rcArea);
|
|
}
|
|
|
|
showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_MQ_DUNGEON_COUNT) > 0);
|
|
//Bug: the above will spoil that everything is vanilla if the random count rolled 0.
|
|
// Should use the below instead, but the setting isn't currently saved to the savefile
|
|
//showVOrMQ = (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_RANDOM_MQ_DUNGEONS) != RO_GENERIC_OFF);
|
|
|
|
UpdateChecks();
|
|
UpdateInventoryChecks();
|
|
UpdateOrdering(true);
|
|
doInitialize = false;
|
|
initialized = true;
|
|
}
|
|
|
|
void Teardown() {
|
|
initialized = false;
|
|
checkStatusMap.clear();
|
|
areasFullyChecked = 0;
|
|
areasSpoiled = 0;
|
|
checks.clear();
|
|
lastLocationChecked = RC_UNKNOWN_CHECK;
|
|
for (int i = 0; i < sizeof(areaChecksTotal); i++) {
|
|
areaChecksTotal[i] = 0;
|
|
areaChecksGotten[i] = 0;
|
|
}
|
|
doInitialize = true;
|
|
}
|
|
|
|
int slowCheckIdx = 0;
|
|
// Checks only one check every call
|
|
bool SlowUpdateCheck() {
|
|
bool ret = false;
|
|
auto checkIt = checks.begin() + slowCheckIdx;
|
|
if (checkIt == checks.end()) {
|
|
slowCheckIdx = 0;
|
|
return false;
|
|
}
|
|
|
|
RandomizerCheckObject rcObj = *checkIt;
|
|
RandomizerCheckShow lastStatus = checkStatusMap.find(rcObj.rc)->second;
|
|
if (lastStatus != GetCheckStatus(rcObj, slowCheckIdx))
|
|
ret = true;
|
|
|
|
slowCheckIdx++;
|
|
return ret;
|
|
}
|
|
|
|
bool ShouldUpdateChecks() {
|
|
// TODO eventually will need to be hooked into game elements rather than just save file
|
|
if (CVarGetInteger("gCheckTrackerOptionPerformanceMode", 0))
|
|
return SlowUpdateCheck();
|
|
else
|
|
return true;
|
|
}
|
|
|
|
void UpdateInventoryChecks() {
|
|
//For all the areas with compasses, if you have one, spoil the area
|
|
for (u8 i = RCAREA_DEKU_TREE; i <= RCAREA_ICE_CAVERN; i++)
|
|
if (gSaveContext.inventory.dungeonItems[i - RCAREA_DEKU_TREE] & 0x02)
|
|
areasSpoiled |= (1 << i);
|
|
}
|
|
|
|
void UpdateChecks() {
|
|
int idx = 0;
|
|
RandomizerCheckObject* lastCheck;
|
|
RandomizerCheckShow lastStatus;
|
|
for (auto& rcObj : checks) {
|
|
RandomizerCheckShow* checkStatusPtr = &checkStatusMap.find(rcObj.rc)->second;
|
|
lastStatus = *checkStatusPtr;
|
|
*checkStatusPtr = GetCheckStatus(rcObj, idx);
|
|
|
|
//Update areasFullyChecked
|
|
if (lastStatus != *checkStatusPtr) {
|
|
if (lastStatus != RCSHOW_CHECKED && lastStatus != RCSHOW_SAVED && (*checkStatusPtr == RCSHOW_CHECKED || *checkStatusPtr == RCSHOW_SAVED))
|
|
areaChecksGotten[rcObj.rcArea]++;
|
|
else if ((lastStatus == RCSHOW_CHECKED || lastStatus == RCSHOW_SAVED) && *checkStatusPtr != RCSHOW_CHECKED && *checkStatusPtr != RCSHOW_SAVED)
|
|
areaChecksGotten[rcObj.rcArea]--;
|
|
|
|
if (areaChecksGotten[rcObj.rcArea] == areaChecksTotal[rcObj.rcArea])
|
|
areasFullyChecked |= (1 << rcObj.rcArea);
|
|
else
|
|
areasFullyChecked &= (0xFFFFFFFF - (1 << rcObj.rcArea));
|
|
|
|
if (areaChecksGotten[rcObj.rcArea] != 0 || RandomizerCheckObjects::AreaIsOverworld(rcObj.rcArea))
|
|
areasSpoiled |= (1 << rcObj.rcArea);
|
|
}
|
|
|
|
lastCheck = &rcObj;
|
|
|
|
idx++;
|
|
}
|
|
}
|
|
|
|
void UpdateOrdering(bool init) {
|
|
// Sort the entire thing
|
|
if (init) {
|
|
std::sort(checks.begin(), checks.end(), CompareCheckObject);
|
|
return;
|
|
}
|
|
|
|
//sort each area individually
|
|
int startOffset = 0;
|
|
int endOffset = 0;
|
|
for (int x = 0; x < sizeof(areaChecksTotal); x++) {
|
|
endOffset = startOffset + areaChecksTotal[x];
|
|
std::sort(checks.begin() + startOffset, checks.begin() + endOffset, CompareCheckObject);
|
|
startOffset += areaChecksTotal[x];
|
|
}
|
|
}
|
|
|
|
bool CompareCheckObject(RandomizerCheckObject i, RandomizerCheckObject j) {
|
|
if (i.rcArea < j.rcArea)
|
|
return true;
|
|
else if (i.rcArea > j.rcArea)
|
|
return false;
|
|
|
|
if (checkStatusMap.find(i.rc)->second < checkStatusMap.find(j.rc)->second)
|
|
return true;
|
|
else if (checkStatusMap.find(i.rc)->second > checkStatusMap.find(j.rc)->second)
|
|
return false;
|
|
|
|
if (i.rc < j.rc)
|
|
return true;
|
|
else if (i.rc > j.rc)
|
|
return false;
|
|
|
|
return false;
|
|
}
|
|
|
|
RandomizerCheckShow GetCheckStatus(RandomizerCheckObject rcObj, int idx) {
|
|
if (HasItemBeenCollected(rcObj))
|
|
return RCSHOW_SAVED; // TODO: use SAVED until we hook into game elements without requiring a save. Then we'll use CHECKED
|
|
|
|
if (HasItemBeenSkipped(rcObj))
|
|
return RCSHOW_SKIPPED;
|
|
|
|
return RCSHOW_UNCHECKED;
|
|
|
|
// TODO Seen, Hinted, Scummed, saved/checked
|
|
}
|
|
|
|
bool HasItemBeenSkipped(RandomizerCheckObject obj) {
|
|
return gSaveContext.sohStats.locationsSkipped[obj.rc] == 1;
|
|
}
|
|
|
|
bool HasItemBeenCollected(RandomizerCheckObject obj) {
|
|
ItemLocation* x = Location(obj.rc);
|
|
SpoilerCollectionCheck check = x->GetCollectionCheck();
|
|
auto flag = check.flag;
|
|
auto scene = check.scene;
|
|
auto type = check.type;
|
|
|
|
switch (type) {
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_ALWAYS_COLLECTED:
|
|
return true;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_BIGGORON:
|
|
return gSaveContext.bgsFlag & flag;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_CHEST:
|
|
return gSaveContext.sceneFlags[scene].chest & (1 << flag);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE:
|
|
return gSaveContext.sceneFlags[scene].collect & (1 << flag);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_MERCHANT:
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM:
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_COW:
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_SCRUB:
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF:
|
|
return Flags_GetRandomizerInf(OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(obj.rc));
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF:
|
|
return gSaveContext.eventChkInf[flag / 16] & (0x01 << flag % 16);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_GERUDO_MEMBERSHIP_CARD:
|
|
return CHECK_FLAG_ALL(gSaveContext.eventChkInf[0x09], 0x0F);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_GOLD_SKULLTULA:
|
|
return GET_GS_FLAGS(scene) & flag;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_INF_TABLE:
|
|
return gSaveContext.infTable[scene] & INDEX_TO_16BIT_LITTLE_ENDIAN_BITMASK(flag);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_ITEM_GET_INF:
|
|
return gSaveContext.itemGetInf[flag / 16] & INDEX_TO_16BIT_LITTLE_ENDIAN_BITMASK(flag);
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_MAGIC_BEANS:
|
|
return BEANS_BOUGHT >= 10;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_MINIGAME:
|
|
if (obj.rc == RC_LH_CHILD_FISHING)
|
|
return HIGH_SCORE(HS_FISHING) & 0x400;
|
|
if (obj.rc == RC_LH_ADULT_FISHING)
|
|
return HIGH_SCORE(HS_FISHING) & 0x800;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_NONE:
|
|
return false;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_POE_POINTS:
|
|
return gSaveContext.highScores[HS_POE_POINTS] >= 1000;
|
|
case SpoilerCollectionCheckType::SPOILER_CHK_GRAVEDIGGER:
|
|
// Gravedigger has a fix in place that means one of two save locations. Check both.
|
|
return (gSaveContext.itemGetInf[1] & 0x1000) || // vanilla flag
|
|
((gSaveContext.n64ddFlag || CVarGetInteger("gGravediggingTourFix", 0)) &&
|
|
gSaveContext.sceneFlags[scene].collect & (1 << flag)); // rando/fix flag
|
|
default:
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void DrawLocation(RandomizerCheckObject rcObj, RandomizerCheckShow* thisCheckStatus) {
|
|
Color_RGBA8 mainColor;
|
|
Color_RGBA8 extraColor;
|
|
std::string txt;
|
|
bool showHidden = CVarGetInteger("gCheckTrackerOptionShowHidden", 0);
|
|
|
|
if (*thisCheckStatus == RCSHOW_UNCHECKED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerUncheckedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_SKIPPED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerSkippedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_SEEN) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerSeenHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_HINTED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerHintedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerHintedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerHintedExtraColor", Color_Hinted_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_CHECKED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerCheckedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerCheckedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerCheckedExtraColor", Color_Checked_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_SCUMMED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerScummedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default);
|
|
} else if (*thisCheckStatus == RCSHOW_SAVED) {
|
|
if (!showHidden && CVarGetInteger("gCheckTrackerSavedHide", 0))
|
|
return;
|
|
mainColor = CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default);
|
|
extraColor = CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default);
|
|
}
|
|
|
|
//Main Text
|
|
txt = rcObj.rcShortName;
|
|
if (lastLocationChecked == rcObj.rc)
|
|
txt = "* " + txt;
|
|
|
|
// Draw button - for Skipped/Unchecked only
|
|
if (*thisCheckStatus == RCSHOW_UNCHECKED || *thisCheckStatus == RCSHOW_SKIPPED) {
|
|
bool skipped = (*thisCheckStatus == RCSHOW_SKIPPED);
|
|
if (ImGui::ArrowButton(std::to_string(rcObj.rc).c_str(), skipped ? ImGuiDir_Left : ImGuiDir_Right)) {
|
|
if (skipped) {
|
|
gSaveContext.sohStats.locationsSkipped[rcObj.rc] = 0;
|
|
*thisCheckStatus = RCSHOW_UNCHECKED;
|
|
} else {
|
|
gSaveContext.sohStats.locationsSkipped[rcObj.rc] = 1;
|
|
*thisCheckStatus = RCSHOW_SKIPPED;
|
|
}
|
|
}
|
|
} else {
|
|
ImGui::InvisibleButton("", ImVec2(20.0f, 10.0f));
|
|
}
|
|
ImGui::SameLine();
|
|
|
|
//Draw
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(mainColor.r / 255.0f, mainColor.g / 255.0f, mainColor.b / 255.0f, mainColor.a / 255.0f));
|
|
ImGui::Text("%s", txt.c_str());
|
|
ImGui::PopStyleColor();
|
|
|
|
//Draw the extra info
|
|
if (*thisCheckStatus != RCSHOW_UNCHECKED) {
|
|
switch (*thisCheckStatus) {
|
|
case RCSHOW_SAVED:
|
|
case RCSHOW_CHECKED:
|
|
case RCSHOW_SCUMMED:
|
|
if (gSaveContext.n64ddFlag)
|
|
txt = OTRGlobals::Instance->gRandomizer
|
|
->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rcObj.rc].get.rgID][gSaveContext.language];
|
|
else if (gSaveContext.language == LANGUAGE_ENG)
|
|
txt = ItemFromGIID(rcObj.ogItemId).GetName().english;
|
|
else if (gSaveContext.language == LANGUAGE_FRA)
|
|
txt = ItemFromGIID(rcObj.ogItemId).GetName().french;
|
|
break;
|
|
case RCSHOW_SKIPPED:
|
|
txt = "Skipped"; //TODO language
|
|
break;
|
|
case RCSHOW_SEEN:
|
|
if (gSaveContext.n64ddFlag)
|
|
txt = OTRGlobals::Instance->gRandomizer
|
|
->EnumToSpoilerfileGetName[gSaveContext.itemLocations[rcObj.rc].get.fakeRgID][gSaveContext.language];
|
|
else if (gSaveContext.language == LANGUAGE_ENG)
|
|
txt = ItemFromGIID(rcObj.ogItemId).GetName().english;
|
|
else if (gSaveContext.language == LANGUAGE_FRA)
|
|
txt = ItemFromGIID(rcObj.ogItemId).GetName().french;
|
|
break;
|
|
case RCSHOW_HINTED:
|
|
txt = "Hints are WIP"; // TODO language
|
|
break;
|
|
}
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(extraColor.r / 255.0f, extraColor.g / 255.0f, extraColor.b / 255.0f, extraColor.a / 255.0f));
|
|
ImGui::SameLine();
|
|
ImGui::Text(" (%s)", txt.c_str());
|
|
ImGui::PopStyleColor();
|
|
}
|
|
|
|
}
|
|
|
|
static std::set<std::string> rainbowCVars = {
|
|
"gCheckTrackerAreaMainIncompleteColor", "gCheckTrackerAreaExtraIncompleteColor",
|
|
"gCheckTrackerAreaMainCompleteColor", "gCheckTrackerAreaExtraCompleteColor",
|
|
"gCheckTrackerUncheckedMainColor", "gCheckTrackerUncheckedExtraColor",
|
|
"gCheckTrackerSkippedMainColor", "gCheckTrackerSkippedExtraColor",
|
|
"gCheckTrackerSeenMainColor", "gCheckTrackerSeenExtraColor",
|
|
"gCheckTrackerHintedMainColor", "gCheckTrackerHintedExtraColor",
|
|
"gCheckTrackerCheckedMainColor", "gCheckTrackerCheckedExtraColor",
|
|
"gCheckTrackerScummedMainColor", "gCheckTrackerScummedExtraColor",
|
|
"gCheckTrackerSavedMainColor", "gCheckTrackerSavedExtraColor",
|
|
};
|
|
|
|
int hue = 0;
|
|
void RainbowTick() {
|
|
float freqHue = hue * 2 * M_PI / (360 * CVarGetFloat("gCosmetics.RainbowSpeed", 0.6f));
|
|
for (auto cvar : rainbowCVars) {
|
|
if (CVarGetInteger((cvar + "RBM").c_str(), 0) == 0)
|
|
continue;
|
|
|
|
Color_RGBA8 newColor;
|
|
newColor.r = sin(freqHue + 0) * 127 + 128;
|
|
newColor.g = sin(freqHue + (2 * M_PI / 3)) * 127 + 128;
|
|
newColor.b = sin(freqHue + (4 * M_PI / 3)) * 127 + 128;
|
|
newColor.a = 255;
|
|
|
|
CVarSetColor(cvar.c_str(), newColor);
|
|
}
|
|
|
|
hue++;
|
|
hue %= 360;
|
|
}
|
|
|
|
void ImGuiDrawTwoColorPickerSection(const char* text, const char* cvarMainName, const char* cvarExtraName,
|
|
Color_RGBA8& main_color, Color_RGBA8& extra_color, Color_RGBA8& main_default_color,
|
|
Color_RGBA8& extra_default_color, const char* cvarHideName) {
|
|
Color_RGBA8 cvarMainColor = CVarGetColor(cvarMainName, main_default_color);
|
|
Color_RGBA8 cvarExtraColor = CVarGetColor(cvarExtraName, extra_default_color);
|
|
main_color = cvarMainColor;
|
|
extra_color = cvarExtraColor;
|
|
|
|
if (ImGui::CollapsingHeader(text)) {
|
|
if (*cvarHideName != '\0') {
|
|
std::string label = cvarHideName;
|
|
label += "##Hidden";
|
|
ImGui::PushID(label.c_str());
|
|
UIWidgets::EnhancementCheckbox("Hidden", cvarHideName, false,
|
|
"When active, checks will hide by default when updated to this state. Can "
|
|
"be overriden with the \"Show Hidden Items\" option.");
|
|
ImGui::PopID();
|
|
}
|
|
if (ImGui::BeginTable(text, 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV | ImGuiTableFlags_Hideable)) {
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
|
if (UIWidgets::EnhancementColor("Check", cvarMainName,
|
|
ImVec4(main_color.r, main_color.g, main_color.b, main_color.a),
|
|
ImVec4(main_default_color.r, main_default_color.g, main_default_color.b, main_default_color.a)))
|
|
{
|
|
main_color = CVarGetColor(cvarMainName, main_default_color);
|
|
};
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::TableNextColumn();
|
|
ImGui::AlignTextToFramePadding();
|
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
|
if (UIWidgets::EnhancementColor("Details", cvarExtraName,
|
|
ImVec4(extra_color.r, extra_color.g, extra_color.b, extra_color.a),
|
|
ImVec4(extra_default_color.r, extra_default_color.g, extra_default_color.b, extra_default_color.a)))
|
|
{
|
|
extra_color = CVarGetColor(cvarExtraName, extra_default_color);
|
|
}
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::EndTable();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const char* windowType[] = { "Floating", "Window" };
|
|
const char* displayType[] = { "Always", "Combo Button Hold" };
|
|
const char* buttonStrings[] = { "A Button", "B Button", "C-Up", "C-Down", "C-Left", "C-Right", "L Button",
|
|
"Z Button", "R Button", "Start", "D-Up", "D-Down", "D-Left", "D-Right" };
|
|
void DrawCheckTrackerOptions(bool& open) {
|
|
if (!open) {
|
|
CVarSetInteger("gCheckTrackerSettingsEnabled", 0);
|
|
return;
|
|
}
|
|
|
|
ImGui::SetNextWindowSize(ImVec2(600, 375), ImGuiCond_FirstUseEver);
|
|
|
|
if (!ImGui::Begin("Check Tracker Settings", &open, ImGuiWindowFlags_NoFocusOnAppearing)) {
|
|
ImGui::End();
|
|
return;
|
|
}
|
|
|
|
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f });
|
|
ImGui::BeginTable("CheckTrackerSettingsTable", 2, ImGuiTableFlags_BordersH | ImGuiTableFlags_BordersV);
|
|
ImGui::TableSetupColumn("General settings", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
|
ImGui::TableSetupColumn("Section settings", ImGuiTableColumnFlags_WidthStretch, 200.0f);
|
|
ImGui::TableHeadersRow();
|
|
ImGui::TableNextRow();
|
|
ImGui::TableNextColumn();
|
|
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
|
if (UIWidgets::EnhancementColor("BG Color", "gCheckTrackerBgColor",
|
|
ImVec4(Color_Background.r, Color_Background.g, Color_Background.b, Color_Background.a),
|
|
ImVec4(Color_Bg_Default.r, Color_Bg_Default.g, Color_Bg_Default.b, Color_Bg_Default.a),
|
|
false, true))
|
|
{
|
|
Color_Background = CVarGetColor("gCheckTrackerBgColor", Color_Bg_Default);
|
|
}
|
|
ImGui::PopItemWidth();
|
|
|
|
ImGui::Text("Window Type");
|
|
ImGui::SameLine();
|
|
UIWidgets::EnhancementCombobox("gCheckTrackerWindowType", windowType, 2, 1);
|
|
|
|
if (CVarGetInteger("gCheckTrackerWindowType", 1) == 0) {
|
|
UIWidgets::EnhancementCheckbox("Enable Dragging", "gCheckTrackerHudEditMode");
|
|
UIWidgets::EnhancementCheckbox("Only enable while paused", "gCheckTrackerShowOnlyPaused");
|
|
ImGui::Text("Display Mode");
|
|
ImGui::SameLine();
|
|
UIWidgets::EnhancementCombobox("gCheckTrackerDisplayType", displayType, 2, 0);
|
|
if (CVarGetInteger("gCheckTrackerDisplayType", 0) > 0) {
|
|
ImGui::Text("Combo Button 1");
|
|
ImGui::SameLine();
|
|
UIWidgets::EnhancementCombobox("gCheckTrackerComboButton1", buttonStrings, 14, 6);
|
|
ImGui::Text("Combo Button 2");
|
|
ImGui::SameLine();
|
|
UIWidgets::EnhancementCombobox("gCheckTrackerComboButton2", buttonStrings, 14, 8);
|
|
}
|
|
}
|
|
UIWidgets::EnhancementCheckbox("Performance mode", "gCheckTrackerOptionPerformanceMode");
|
|
UIWidgets::Tooltip("Slows down checking for updates to 1 check per frame. Only required if experiencing poor performance when using Check Tracker.");
|
|
UIWidgets::EnhancementCheckbox("Vanilla/MQ Dungeon Spoilers", "gCheckTrackerOptionMQSpoilers");
|
|
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked. ");
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGuiDrawTwoColorPickerSection("Area Incomplete", "gCheckTrackerAreaMainIncompleteColor", "gCheckTrackerAreaExtraIncompleteColor", Color_Area_Incomplete_Main, Color_Area_Incomplete_Extra, Color_Main_Default, Color_Area_Incomplete_Extra_Default, "gCheckTrackerAreaIncompleteHide" );
|
|
ImGuiDrawTwoColorPickerSection("Area Complete", "gCheckTrackerAreaMainCompleteColor", "gCheckTrackerAreaExtraCompleteColor", Color_Area_Complete_Main, Color_Area_Complete_Extra, Color_Main_Default, Color_Area_Complete_Extra_Default, "gCheckTrackerAreaCompleteHide" );
|
|
ImGuiDrawTwoColorPickerSection("Unchecked", "gCheckTrackerUncheckedMainColor", "gCheckTrackerUncheckedExtraColor", Color_Unchecked_Main, Color_Unchecked_Extra, Color_Main_Default, Color_Unchecked_Extra_Default, "gCheckTrackerUncheckedHide" );
|
|
ImGuiDrawTwoColorPickerSection("Skipped", "gCheckTrackerSkippedMainColor", "gCheckTrackerSkippedExtraColor", Color_Skipped_Main, Color_Skipped_Extra, Color_Main_Default, Color_Skipped_Extra_Default, "gCheckTrackerSkippedHide" );
|
|
ImGuiDrawTwoColorPickerSection("Seen (WIP)", "gCheckTrackerSeenMainColor", "gCheckTrackerSeenExtraColor", Color_Seen_Main, Color_Seen_Extra, Color_Main_Default, Color_Seen_Extra_Default, "gCheckTrackerSeenHide" );
|
|
ImGuiDrawTwoColorPickerSection("Hinted (WIP)", "gCheckTrackerHintedMainColor", "gCheckTrackerHintedExtraColor", Color_Hinted_Main, Color_Hinted_Extra, Color_Main_Default, Color_Hinted_Extra_Default, "gCheckTrackerHintedHide" );
|
|
ImGuiDrawTwoColorPickerSection("Checked (WIP)", "gCheckTrackerCheckedMainColor", "gCheckTrackerCheckedExtraColor", Color_Checked_Main, Color_Checked_Extra, Color_Main_Default, Color_Checked_Extra_Default, "gCheckTrackerCheckedHide" );
|
|
ImGuiDrawTwoColorPickerSection("Scummed (WIP)", "gCheckTrackerScummedMainColor", "gCheckTrackerScummedExtraColor", Color_Scummed_Main, Color_Scummed_Extra, Color_Main_Default, Color_Scummed_Extra_Default, "gCheckTrackerScummedHide" );
|
|
ImGuiDrawTwoColorPickerSection("Saved", "gCheckTrackerSavedMainColor", "gCheckTrackerSavedExtraColor", Color_Saved_Main, Color_Saved_Extra, Color_Main_Default, Color_Saved_Extra_Default, "gCheckTrackerSavedHide" );
|
|
|
|
ImGui::PopStyleVar(1);
|
|
ImGui::EndTable();
|
|
ImGui::End();
|
|
}
|
|
|
|
void InitCheckTracker() {
|
|
SohImGui::AddWindow("Randomizer", "Check Tracker", DrawCheckTracker, CVarGetInteger("gCheckTrackerEnabled", 0) == 1);
|
|
SohImGui::AddWindow("Randomizer", "Check Tracker Settings", DrawCheckTrackerOptions);
|
|
Color_Background = CVarGetColor("gCheckTrackerBgColor", Color_Bg_Default);
|
|
Color_Area_Incomplete_Main = CVarGetColor("gCheckTrackerAreaMainIncompleteColor", Color_Main_Default);
|
|
Color_Area_Incomplete_Extra = CVarGetColor("gCheckTrackerAreaExtraIncompleteColor", Color_Area_Incomplete_Extra_Default);
|
|
Color_Area_Complete_Main = CVarGetColor("gCheckTrackerAreaMainCompleteColor", Color_Main_Default);
|
|
Color_Area_Complete_Extra = CVarGetColor("gCheckTrackerAreaExtraCompleteColor", Color_Area_Complete_Extra_Default);
|
|
Color_Unchecked_Main = CVarGetColor("gCheckTrackerUncheckedMainColor", Color_Main_Default);
|
|
Color_Unchecked_Extra = CVarGetColor("gCheckTrackerUncheckedExtraColor", Color_Unchecked_Extra_Default);
|
|
Color_Skipped_Main = CVarGetColor("gCheckTrackerSkippedMainColor", Color_Main_Default);
|
|
Color_Skipped_Extra = CVarGetColor("gCheckTrackerSkippedExtraColor", Color_Skipped_Extra_Default);
|
|
Color_Seen_Main = CVarGetColor("gCheckTrackerSeenMainColor", Color_Main_Default);
|
|
Color_Seen_Extra = CVarGetColor("gCheckTrackerSeenExtraColor", Color_Seen_Extra_Default);
|
|
Color_Hinted_Main = CVarGetColor("gCheckTrackerHintedMainColor", Color_Main_Default);
|
|
Color_Hinted_Extra = CVarGetColor("gCheckTrackerHintedExtraColor", Color_Hinted_Extra_Default);
|
|
Color_Checked_Main = CVarGetColor("gCheckTrackerCheckedMainColor", Color_Main_Default);
|
|
Color_Checked_Extra = CVarGetColor("gCheckTrackerCheckedExtraColor", Color_Checked_Extra_Default);
|
|
Color_Scummed_Main = CVarGetColor("gCheckTrackerScummedMainColor", Color_Main_Default);
|
|
Color_Scummed_Extra = CVarGetColor("gCheckTrackerScummedExtraColor", Color_Scummed_Extra_Default);
|
|
Color_Saved_Main = CVarGetColor("gCheckTrackerSavedMainColor", Color_Main_Default);
|
|
Color_Saved_Extra = CVarGetColor("gCheckTrackerSavedExtraColor", Color_Saved_Extra_Default);
|
|
|
|
Ship::RegisterHook<Ship::ControllerRead>([](OSContPad* cont_pad) {
|
|
trackerButtonsPressed = cont_pad;
|
|
});
|
|
Ship::RegisterHook<Ship::LoadFile>([](uint32_t fileNum) {
|
|
doInitialize = true;
|
|
});
|
|
Ship::RegisterHook<Ship::DeleteFile>([](uint32_t fileNum) {
|
|
Teardown();
|
|
});
|
|
LocationTable_Init();
|
|
}
|
|
|
|
} // namespace CheckTracker
|