Check Tracker Re-update (#4322)

* Update check status in the check tracker to the new system. Status and Skipped are now stored in ItemLocation, though still saved separately in the trackerData section.

* Fix shop checks not showing prices when identified.

* Patch fix for check status bleed.
Some cleanup of unused code.

* Small tracker optimizations.

* Fix check hiding.

* Bit more cleanup.

* Unhide the filter and make it work again...

* Fix area totals tracking.
Fix skipped status saving.

* Merge conflict cleanup.
This commit is contained in:
Malkierian 2024-09-17 11:32:52 -07:00 committed by GitHub
parent 9c11718341
commit 4148d59c48
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 192 additions and 262 deletions

View File

@ -68,6 +68,7 @@ typedef enum { // Pre-existing IDs for save sections in base code
SECTION_ID_STATS, SECTION_ID_STATS,
SECTION_ID_ENTRANCES, SECTION_ID_ENTRANCES,
SECTION_ID_SCENES, SECTION_ID_SCENES,
SECTION_ID_TRACKER_DATA,
SECTION_ID_MAX SECTION_ID_MAX
} SaveFuncIDs; } SaveFuncIDs;
@ -279,7 +280,6 @@ typedef struct {
/* */ u8 pendingIceTrapCount; /* */ u8 pendingIceTrapCount;
/* */ SohStats sohStats; /* */ SohStats sohStats;
/* */ FaroresWindData backupFW; /* */ FaroresWindData backupFW;
/* */ RandomizerCheckTrackerData checkTrackerData[RC_MAX];
// #endregion // #endregion
// #region SOH [Randomizer] // #region SOH [Randomizer]
// Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer // Upstream TODO: Move these to their own struct or name to more obviously specific to Randomizer

View File

@ -306,7 +306,9 @@ void RandomizerOnItemReceiveHandler(GetItemEntry receivedItemEntry) {
auto loc = Rando::Context::GetInstance()->GetItemLocation(randomizerQueuedCheck); auto loc = Rando::Context::GetInstance()->GetItemLocation(randomizerQueuedCheck);
if (randomizerQueuedItemEntry.modIndex == receivedItemEntry.modIndex && randomizerQueuedItemEntry.itemId == receivedItemEntry.itemId) { if (randomizerQueuedItemEntry.modIndex == receivedItemEntry.modIndex && randomizerQueuedItemEntry.itemId == receivedItemEntry.itemId) {
SPDLOG_INFO("Item received mod {} item {} from RC {}", receivedItemEntry.modIndex, receivedItemEntry.itemId, static_cast<uint32_t>(randomizerQueuedCheck)); SPDLOG_INFO("Item received mod {} item {} from RC {}", receivedItemEntry.modIndex, receivedItemEntry.itemId, static_cast<uint32_t>(randomizerQueuedCheck));
loc->MarkAsObtained(); loc->SetCheckStatus(RCSHOW_COLLECTED);
CheckTracker::RecalculateAllAreaTotals();
SaveManager::Instance->SaveSection(gSaveContext.fileNum, SECTION_ID_TRACKER_DATA, true);
randomizerQueuedCheck = RC_UNKNOWN_CHECK; randomizerQueuedCheck = RC_UNKNOWN_CHECK;
randomizerQueuedItemEntry = GET_ITEM_NONE; randomizerQueuedItemEntry = GET_ITEM_NONE;
} }
@ -662,7 +664,8 @@ void RandomizerOnVanillaBehaviorHandler(GIVanillaBehavior id, bool* should, void
*should = false; *should = false;
} else { } else {
*should = true; *should = true;
Rando::Context::GetInstance()->GetItemLocation(RC_TOT_MASTER_SWORD)->MarkAsObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_TOT_MASTER_SWORD)->SetCheckStatus(RCSHOW_COLLECTED);
CheckTracker::RecalculateAllAreaTotals();
} }
break; break;
case VB_ITEM00_DESPAWN: { case VB_ITEM00_DESPAWN: {
@ -1179,25 +1182,26 @@ void RandomizerOnSceneInitHandler(int16_t sceneNum) {
// probably need to do something different when we implement shuffle // probably need to do something different when we implement shuffle
if (sceneNum == SCENE_TREASURE_BOX_SHOP) { if (sceneNum == SCENE_TREASURE_BOX_SHOP) {
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_1); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_1);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_1)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_2); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_2);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_2)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_3); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_3);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_3)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_4); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_4);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_4)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_5); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_ITEM_5);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_ITEM_5)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_1); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_1);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_1)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_1)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_2); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_2);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_2)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_2)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_3);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_3)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_3)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_4);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_4)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_4)->SetCheckStatus(RCSHOW_UNCHECKED);
Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5); Flags_UnsetRandomizerInf(RAND_INF_MARKET_TREASURE_CHEST_GAME_KEY_5);
Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_5)->MarkAsNotObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_MARKET_TREASURE_CHEST_GAME_KEY_5)->SetCheckStatus(RCSHOW_UNCHECKED);
CheckTracker::RecalculateAllAreaTotals();
} }
// LACs & Prelude checks // LACs & Prelude checks

View File

@ -102,15 +102,23 @@ void ItemLocation::SetCustomPrice(const uint16_t price_) {
} }
bool ItemLocation::HasObtained() const { bool ItemLocation::HasObtained() const {
return obtained; return status == RCSHOW_COLLECTED || status == RCSHOW_SAVED;
} }
void ItemLocation::MarkAsObtained() { void ItemLocation::SetCheckStatus(RandomizerCheckStatus status_) {
obtained = true; status = status_;
} }
void ItemLocation::MarkAsNotObtained() { RandomizerCheckStatus ItemLocation::GetCheckStatus() {
obtained = false; return status;
}
void ItemLocation::SetIsSkipped(bool isSkipped_) {
isSkipped = isSkipped_;
}
bool ItemLocation::GetIsSkipped() {
return isSkipped;
} }
bool ItemLocation::IsHintable() const { bool ItemLocation::IsHintable() const {
@ -213,6 +221,7 @@ void ItemLocation::ResetVariables() {
wothCandidate = false; wothCandidate = false;
barrenCandidate = false; barrenCandidate = false;
area = RA_NONE; area = RA_NONE;
obtained = false; status = RCSHOW_UNCHECKED;
isSkipped = false;
} }
} }

View File

@ -32,8 +32,10 @@ class ItemLocation {
bool HasCustomPrice() const; bool HasCustomPrice() const;
void SetCustomPrice(uint16_t price_); void SetCustomPrice(uint16_t price_);
bool HasObtained() const; bool HasObtained() const;
void MarkAsObtained(); void SetCheckStatus(RandomizerCheckStatus status_);
void MarkAsNotObtained(); RandomizerCheckStatus GetCheckStatus();
void SetIsSkipped(bool isSkipped_);
bool GetIsSkipped();
bool IsHintable() const; bool IsHintable() const;
void SetAsHintable(); void SetAsHintable();
bool IsAHintAccessible() const; bool IsAHintAccessible() const;
@ -70,6 +72,7 @@ class ItemLocation {
bool visibleInImGui = false; bool visibleInImGui = false;
bool wothCandidate = false; bool wothCandidate = false;
bool barrenCandidate = false; bool barrenCandidate = false;
bool obtained = false; RandomizerCheckStatus status = RCSHOW_UNCHECKED;
bool isSkipped = false;
}; };
} // namespace Rando } // namespace Rando

View File

@ -56,8 +56,6 @@ std::set<RandomizerCheck> spoilerExcludedLocations;
std::set<RandomizerTrick> enabledTricks; std::set<RandomizerTrick> enabledTricks;
std::set<RandomizerTrick> enabledGlitches; std::set<RandomizerTrick> enabledGlitches;
std::set<std::map<RandomizerCheck, RandomizerCheckTrackerData>> checkTrackerStates;
u8 generated; u8 generated;
char* seedString; char* seedString;

View File

@ -27,16 +27,6 @@ typedef struct {
uint8_t id; uint8_t id;
} Sprite; } Sprite;
// Check tracker check visibility categories
typedef enum {
RCSHOW_UNCHECKED,
RCSHOW_SEEN,
RCSHOW_IDENTIFIED,
RCSHOW_SCUMMED,
RCSHOW_COLLECTED,
RCSHOW_SAVED,
} RandomizerCheckStatus;
typedef enum { typedef enum {
HINT_TYPE_HINT_KEY, HINT_TYPE_HINT_KEY,
HINT_TYPE_AREA, HINT_TYPE_AREA,
@ -315,6 +305,16 @@ typedef enum {
RCAREA_INVALID RCAREA_INVALID
} RandomizerCheckArea; } RandomizerCheckArea;
// Check tracker check visibility categories
typedef enum {
RCSHOW_UNCHECKED,
RCSHOW_SEEN,
RCSHOW_IDENTIFIED,
RCSHOW_SCUMMED,
RCSHOW_COLLECTED,
RCSHOW_SAVED,
} RandomizerCheckStatus;
typedef enum { typedef enum {
RR_NONE, RR_NONE,
RR_ROOT, RR_ROOT,
@ -3886,13 +3886,6 @@ typedef enum {
RSK_MAX RSK_MAX
} RandomizerSettingKey; } RandomizerSettingKey;
typedef struct {
RandomizerCheckStatus status;
uint16_t skipped;
int16_t price;
uint16_t hintItem;
} RandomizerCheckTrackerData;
//Generic Settings (any binary option can use this) //Generic Settings (any binary option can use this)
// off/on // off/on
typedef enum { typedef enum {

View File

@ -36,21 +36,6 @@ extern std::vector<ItemTrackerItem> equipmentItems;
using json = nlohmann::json; using json = nlohmann::json;
void to_json(json& j, const RandomizerCheckTrackerData& rctd) {
j = json {
{ "status", rctd.status == RCSHOW_COLLECTED ? RCSHOW_SAVED : rctd.status },
{ "skipped", rctd.skipped },
{ "price", rctd.price },
{ "hintItem", rctd.hintItem }};
}
void from_json(const json& j, RandomizerCheckTrackerData& rctd) {
j.at("status").get_to(rctd.status);
j.at("skipped").get_to(rctd.skipped);
j.at("hintItem").get_to(rctd.hintItem);
j.at("price").get_to(rctd.price);
}
namespace CheckTracker { namespace CheckTracker {
// settings // settings
@ -149,13 +134,12 @@ OSContPad* trackerButtonsPressed;
std::unordered_map<RandomizerCheck, std::string> checkNameOverrides; std::unordered_map<RandomizerCheck, std::string> checkNameOverrides;
bool ShouldShowCheck(RandomizerCheck rc); bool ShouldShowCheck(RandomizerCheck rc);
bool ShouldHideArea(RandomizerCheckArea rcArea); bool UpdateFilters();
void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0); void BeginFloatWindows(std::string UniqueName, bool& open, ImGuiWindowFlags flags = 0);
bool CompareChecks(RandomizerCheck, RandomizerCheck); bool CompareChecks(RandomizerCheck, RandomizerCheck);
bool CheckByArea(RandomizerCheckArea); bool CheckByArea(RandomizerCheckArea);
void DrawLocation(RandomizerCheck); void DrawLocation(RandomizerCheck);
void EndFloatWindows(); void EndFloatWindows();
bool HasItemBeenCollected(RandomizerCheck);
void LoadSettings(); void LoadSettings();
void RainbowTick(); void RainbowTick();
void UpdateAreas(RandomizerCheckArea area); void UpdateAreas(RandomizerCheckArea area);
@ -219,39 +203,35 @@ Color_RGBA8 Color_Saved_Extra = { 0, 185, 0, 255 }; // Green
std::vector<uint32_t> buttons = { BTN_A, BTN_B, BTN_CUP, BTN_CDOWN, BTN_CLEFT, BTN_CRIGHT, BTN_L, 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 }; BTN_Z, BTN_R, BTN_START, BTN_DUP, BTN_DDOWN, BTN_DLEFT, BTN_DRIGHT };
static ImGuiTextFilter checkSearch; static ImGuiTextFilter checkSearch;
std::array<bool, RCAREA_INVALID> filterAreasHidden = { 0 };
void DefaultCheckData(RandomizerCheck rc) { std::array<bool, RC_MAX> filterChecksHidden = { 0 };
gSaveContext.checkTrackerData[rc].status = RCSHOW_UNCHECKED;
gSaveContext.checkTrackerData[rc].skipped = 0;
gSaveContext.checkTrackerData[rc].hintItem = RC_UNKNOWN_CHECK;
}
void SongFromImpa() { void SongFromImpa() {
if (IS_RANDO) { if (IS_RANDO) {
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA) == RO_GENERIC_ON && IS_RANDO) { if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SKIP_CHILD_ZELDA) == RO_GENERIC_ON && IS_RANDO) {
if (gSaveContext.checkTrackerData[RC_SONG_FROM_IMPA].status != RCSHOW_SAVED) { //if (gSaveContext.checkTrackerData[RC_SONG_FROM_IMPA].status != RCSHOW_SAVED) {
gSaveContext.checkTrackerData[RC_SONG_FROM_IMPA].status = RCSHOW_SAVED; // gSaveContext.checkTrackerData[RC_SONG_FROM_IMPA].status = RCSHOW_SAVED;
} //}
} }
} }
} }
void GiftFromSages() { void GiftFromSages() {
if (!IS_RANDO) { if (!IS_RANDO) {
DefaultCheckData(RC_GIFT_FROM_SAGES); //DefaultCheckData(RC_GIFT_FROM_SAGES);
} }
} }
std::vector<RandomizerCheck> checks; std::vector<RandomizerCheck> checks;
// Function for adding Link's Pocket check // Function for adding Link's Pocket check
void LinksPocket() { void LinksPocket() {
if (IS_RANDO) { /*if (IS_RANDO) {
if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING || if (OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING ||
OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_DUNGEON_REWARDS) == RO_DUNGEON_REWARDS_END_OF_DUNGEON) { OTRGlobals::Instance->gRandomizer->GetRandoSettingValue(RSK_SHUFFLE_DUNGEON_REWARDS) == RO_DUNGEON_REWARDS_END_OF_DUNGEON) {
DefaultCheckData(RC_LINKS_POCKET); DefaultCheckData(RC_LINKS_POCKET);
gSaveContext.checkTrackerData[RC_LINKS_POCKET].status = RCSHOW_SAVED; gSaveContext.checkTrackerData[RC_LINKS_POCKET].status = RCSHOW_SAVED;
} }
} }*/
} }
void TrySetAreas() { void TrySetAreas() {
@ -280,37 +260,38 @@ uint16_t GetTotalChecksGotten() {
return totalChecksGotten; return totalChecksGotten;
} }
void RecalculateAreaTotals() { void RecalculateAreaTotals(RandomizerCheckArea rcArea) {
for (auto [rcArea, checks] : checksByArea) { areaChecksGotten[rcArea] = 0;
areaCheckTotals[rcArea] = 0;
for (auto rc : checksByArea.at(rcArea)) {
if (!IsVisibleInCheckTracker(rc)) {
continue;
}
areaCheckTotals[rcArea]++;
if (OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetIsSkipped() || OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->HasObtained()) {
areaChecksGotten[rcArea]++;
}
}
CalculateTotals();
}
void RecalculateAllAreaTotals() {
for (auto& [rcArea, checks] : checksByArea) {
if (rcArea == RCAREA_INVALID) { if (rcArea == RCAREA_INVALID) {
return; return;
} }
areaChecksGotten[rcArea] = 0; RecalculateAreaTotals(rcArea);
areaCheckTotals[rcArea] = 0;
for (auto rc : checks) {
if (!IsVisibleInCheckTracker(rc)) {
continue;
}
areaCheckTotals[rcArea]++;
if (gSaveContext.checkTrackerData[rc].skipped || gSaveContext.checkTrackerData[rc].status == RCSHOW_COLLECTED
|| gSaveContext.checkTrackerData[rc].status == RCSHOW_SAVED) {
areaChecksGotten[rcArea]++;
}
}
} }
totalChecks = 0;
totalChecksGotten = 0;
} }
void SetCheckCollected(RandomizerCheck rc) { void SetCheckCollected(RandomizerCheck rc) {
gSaveContext.checkTrackerData[rc].status = RCSHOW_COLLECTED; OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetCheckStatus(RCSHOW_COLLECTED);
Rando::Location* loc = Rando::StaticData::GetLocation(rc); Rando::Location* loc = Rando::StaticData::GetLocation(rc);
if (IsVisibleInCheckTracker(rc)) { if (IsVisibleInCheckTracker(rc)) {
if (!gSaveContext.checkTrackerData[rc].skipped) { if (!OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetIsSkipped()) {
areaChecksGotten[loc->GetArea()]++; areaChecksGotten[loc->GetArea()]++;
} else { } else {
gSaveContext.checkTrackerData[rc].skipped = false; OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
} }
} }
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
@ -427,6 +408,8 @@ void ClearAreaChecksAndTotals() {
areaChecksGotten[rcArea] = 0; areaChecksGotten[rcArea] = 0;
areaCheckTotals[rcArea] = 0; areaCheckTotals[rcArea] = 0;
} }
totalChecks = 0;
totalChecksGotten = 0;
} }
void SetShopSeen(uint32_t sceneNum, bool prices) { void SetShopSeen(uint32_t sceneNum, bool prices) {
@ -439,8 +422,8 @@ void SetShopSeen(uint32_t sceneNum, bool prices) {
} }
bool statusChanged = false; bool statusChanged = false;
for (int i = start; i < start + 8; i++) { for (int i = start; i < start + 8; i++) {
if (gSaveContext.checkTrackerData[i].status == RCSHOW_UNCHECKED) { if (OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->GetCheckStatus() == RCSHOW_UNCHECKED) {
gSaveContext.checkTrackerData[i].status = RCSHOW_SEEN; OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->SetCheckStatus(RCSHOW_SEEN);
statusChanged = true; statusChanged = true;
} }
} }
@ -449,73 +432,23 @@ void SetShopSeen(uint32_t sceneNum, bool prices) {
} }
} }
bool HasItemBeenCollected(RandomizerCheck rc) {
if (gPlayState == nullptr) {
return false;
}
Rando::Location* x = Rando::StaticData::GetLocation(rc);
Rando::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_CHEST:
return (gPlayState->sceneNum == scene && gPlayState->actorCtx.flags.chest & (1 << flag)) ||
gSaveContext.sceneFlags[scene].chest & (1 << flag);
case SpoilerCollectionCheckType::SPOILER_CHK_COLLECTABLE:
return (gPlayState->sceneNum == scene && gPlayState->actorCtx.flags.collect & (1 << flag)) ||
gSaveContext.sceneFlags[scene].collect & (1 << flag);
case SpoilerCollectionCheckType::SPOILER_CHK_SHOP_ITEM:
case SpoilerCollectionCheckType::SPOILER_CHK_FISH:
case SpoilerCollectionCheckType::SPOILER_CHK_RANDOMIZER_INF:
case SpoilerCollectionCheckType::SPOILER_CHK_MASTER_SWORD:
return Flags_GetRandomizerInf(OTRGlobals::Instance->gRandomizer->GetRandomizerInfFromCheck(rc));
case SpoilerCollectionCheckType::SPOILER_CHK_EVENT_CHK_INF:
return gSaveContext.eventChkInf[flag / 16] & (0x01 << flag % 16);
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_NONE:
return false;
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
((IS_RANDO || CVarGetInteger(CVAR_ENHANCEMENT("GravediggingTourFix"), 0)) &&
gSaveContext.sceneFlags[scene].collect & (1 << flag) || (gPlayState->actorCtx.flags.collect & (1 << flag))); // rando/fix flag
default:
return false;
}
return false;
}
void CheckTrackerLoadGame(int32_t fileNum) { void CheckTrackerLoadGame(int32_t fileNum) {
LoadSettings(); LoadSettings();
TrySetAreas(); TrySetAreas();
for (auto& entry : Rando::StaticData::GetLocationTable()) { for (auto& entry : Rando::StaticData::GetLocationTable()) {
RandomizerCheck rc = entry.GetRandomizerCheck(); RandomizerCheck rc = entry.GetRandomizerCheck();
RandomizerCheckTrackerData rcTrackerData = gSaveContext.checkTrackerData[rc];
if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET || if (rc == RC_UNKNOWN_CHECK || rc == RC_MAX || rc == RC_LINKS_POCKET ||
!Rando::StaticData::GetLocation(rc) != RC_UNKNOWN_CHECK) { !Rando::StaticData::GetLocation(rc) != RC_UNKNOWN_CHECK) {
continue; continue;
} }
Rando::Location* entry2; Rando::Location* entry2 = Rando::StaticData::GetLocation(rc);
if (rc == RC_GIFT_FROM_SAGES && !IS_RANDO) { Rando::ItemLocation* loc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
entry2 = Rando::StaticData::GetLocation(rc);
} else {
entry2 = Rando::StaticData::GetLocation(rc);
}
checksByArea.find(entry2->GetArea())->second.push_back(entry2->GetRandomizerCheck()); checksByArea.find(entry2->GetArea())->second.push_back(entry2->GetRandomizerCheck());
if (IsVisibleInCheckTracker(entry2->GetRandomizerCheck())) { if (IsVisibleInCheckTracker(entry2->GetRandomizerCheck())) {
areaCheckTotals[entry2->GetArea()]++; areaCheckTotals[entry2->GetArea()]++;
if (rcTrackerData.status == RCSHOW_SAVED || rcTrackerData.skipped) { if (loc->GetCheckStatus() == RCSHOW_SAVED || loc->GetIsSkipped()) {
areaChecksGotten[entry2->GetArea()]++; areaChecksGotten[entry2->GetArea()]++;
} }
} }
@ -570,6 +503,7 @@ void CheckTrackerLoadGame(int32_t fileNum) {
initialized = true; initialized = true;
UpdateAllOrdering(); UpdateAllOrdering();
UpdateInventoryChecks(); UpdateInventoryChecks();
UpdateFilters();
} }
void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) { void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
@ -581,10 +515,9 @@ void CheckTrackerShopSlotChange(uint8_t cursorSlot, int16_t basePrice) {
if (GetCheckArea() == RCAREA_KAKARIKO_VILLAGE && gPlayState->sceneNum == SCENE_BAZAAR) { if (GetCheckArea() == RCAREA_KAKARIKO_VILLAGE && gPlayState->sceneNum == SCENE_BAZAAR) {
slot = RC_KAK_BAZAAR_ITEM_1 + cursorSlot; slot = RC_KAK_BAZAAR_ITEM_1 + cursorSlot;
} }
auto status = gSaveContext.checkTrackerData[slot].status; auto status = OTRGlobals::Instance->gRandoContext->GetItemLocation(slot)->GetCheckStatus();
if (status == RCSHOW_SEEN) { if (status == RCSHOW_SEEN) {
gSaveContext.checkTrackerData[slot].status = RCSHOW_IDENTIFIED; OTRGlobals::Instance->gRandoContext->GetItemLocation(slot)->SetCheckStatus(RCSHOW_IDENTIFIED);
gSaveContext.checkTrackerData[slot].price = basePrice;
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
} }
} }
@ -617,8 +550,7 @@ void CheckTrackerFrame() {
return; return;
} }
// TODO: Move to OnAmmoChange hook once it gets added. // TODO: Move to OnAmmoChange hook once it gets added.
if (gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_COLLECTED && if (!OTRGlobals::Instance->gRandoContext->GetItemLocation(RC_ZR_MAGIC_BEAN_SALESMAN)->HasObtained()) {
gSaveContext.checkTrackerData[RC_ZR_MAGIC_BEAN_SALESMAN].status != RCSHOW_SAVED) {
if (BEANS_BOUGHT >= 10) { if (BEANS_BOUGHT >= 10) {
SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN); SetCheckCollected(RC_ZR_MAGIC_BEAN_SALESMAN);
} }
@ -827,33 +759,43 @@ void CheckTrackerFlagSet(int16_t flagType, int32_t flag) {
void InitTrackerData(bool isDebug) { void InitTrackerData(bool isDebug) {
TrySetAreas(); TrySetAreas();
areasSpoiled = 0; areasSpoiled = 0;
for (auto& loc : Rando::StaticData::GetLocationTable()) {
if (loc.GetRandomizerCheck() != RC_UNKNOWN_CHECK && loc.GetRandomizerCheck() != RC_MAX) {
DefaultCheckData(loc.GetRandomizerCheck());
}
}
UpdateAllOrdering();
} }
void SaveTrackerData(SaveContext* saveContext, int sectionID, bool gameSave) { void SaveTrackerData(SaveContext* saveContext, int sectionID, bool fullSave) {
SaveManager::Instance->SaveArray("checks", ARRAY_COUNT(saveContext->checkTrackerData), [&](size_t i) { bool updateOrdering = false;
if (saveContext->checkTrackerData[i].status == RCSHOW_COLLECTED) { std::vector<RandomizerCheck> checkCount;
if (gameSave) { for (int i = RC_UNKNOWN_CHECK; i < RC_MAX; i++) {
gSaveContext.checkTrackerData[i].status = saveContext->checkTrackerData[i].status = RCSHOW_SAVED; if (OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->GetCheckStatus() != RCSHOW_UNCHECKED ||
UpdateAllOrdering(); OTRGlobals::Instance->gRandoContext->GetItemLocation(i)->GetIsSkipped())
UpdateInventoryChecks(); checkCount.push_back(static_cast<RandomizerCheck>(i));
} else { }
saveContext->checkTrackerData[i].status = RCSHOW_SCUMMED; SaveManager::Instance->SaveArray("checkStatus", checkCount.size(), [&](size_t i) {
RandomizerCheck check = checkCount.at(i);
RandomizerCheckStatus savedStatus = OTRGlobals::Instance->gRandoContext->GetItemLocation(check)->GetCheckStatus();
bool isSkipped = OTRGlobals::Instance->gRandoContext->GetItemLocation(check)->GetIsSkipped();
if (savedStatus == RCSHOW_COLLECTED) {
if (fullSave) {
OTRGlobals::Instance->gRandoContext->GetItemLocation(check)->SetCheckStatus(RCSHOW_SAVED);
savedStatus = RCSHOW_SAVED;
updateOrdering = true;
}
else {
savedStatus = RCSHOW_SCUMMED;
} }
} }
SaveManager::Instance->SaveStruct("", [&]() { if (savedStatus != RCSHOW_UNCHECKED || isSkipped) {
SaveManager::Instance->SaveData("status", saveContext->checkTrackerData[i].status); SaveManager::Instance->SaveStruct("", [&]() {
SaveManager::Instance->SaveData("skipped", saveContext->checkTrackerData[i].skipped); SaveManager::Instance->SaveData("randomizerCheck", check);
SaveManager::Instance->SaveData("price", saveContext->checkTrackerData[i].price); SaveManager::Instance->SaveData("status", savedStatus);
SaveManager::Instance->SaveData("hintItem", saveContext->checkTrackerData[i].hintItem); SaveManager::Instance->SaveData("skipped", isSkipped);
}); });
}
}); });
SaveManager::Instance->SaveData("areasSpoiled", areasSpoiled); SaveManager::Instance->SaveData("areasSpoiled", areasSpoiled);
if (updateOrdering) {
UpdateAllOrdering();
UpdateAllAreas();
}
} }
void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) { void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
@ -861,15 +803,21 @@ void SaveFile(SaveContext* saveContext, int sectionID, bool fullSave) {
} }
void LoadFile() { void LoadFile() {
SaveManager::Instance->LoadArray("checks", RC_MAX, [](size_t i) { SaveManager::Instance->LoadArray("checkStatus", RC_MAX, [](size_t i) {
SaveManager::Instance->LoadStruct("", [&]() { SaveManager::Instance->LoadStruct("", [&]() {
SaveManager::Instance->LoadData("status", gSaveContext.checkTrackerData[i].status); RandomizerCheckStatus status;
SaveManager::Instance->LoadData("skipped", gSaveContext.checkTrackerData[i].skipped); bool skipped;
SaveManager::Instance->LoadData("price", gSaveContext.checkTrackerData[i].price); RandomizerCheck rc;
SaveManager::Instance->LoadData("hintItem", gSaveContext.checkTrackerData[i].hintItem); SaveManager::Instance->LoadData("randomizerCheck", rc, RC_UNKNOWN_CHECK);
SaveManager::Instance->LoadData("status", status, RCSHOW_UNCHECKED);
SaveManager::Instance->LoadData("skipped", skipped, false);
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetCheckStatus(status);
OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(skipped);
});
}); });
}); SaveManager::Instance->LoadData("areasSpoiled", areasSpoiled, (uint32_t)0);
SaveManager::Instance->LoadData("areasSpoiled", areasSpoiled); UpdateAllOrdering();
UpdateAllAreas();
} }
void Teardown() { void Teardown() {
@ -877,6 +825,8 @@ void Teardown() {
ClearAreaChecksAndTotals(); ClearAreaChecksAndTotals();
checksByArea.clear(); checksByArea.clear();
areasSpoiled = 0; areasSpoiled = 0;
filterAreasHidden = { 0 };
filterChecksHidden = { 0 };
lastLocationChecked = RC_UNKNOWN_CHECK; lastLocationChecked = RC_UNKNOWN_CHECK;
} }
@ -890,30 +840,6 @@ void SetAreaSpoiled(RandomizerCheckArea rcArea) {
SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true); SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionId, true);
} }
void UpdateCheck(uint32_t check, RandomizerCheckTrackerData data) {
auto area = Rando::StaticData::GetLocation(static_cast<RandomizerCheck>(check))->GetArea();
if ((!gSaveContext.checkTrackerData[check].skipped && data.skipped) ||
((gSaveContext.checkTrackerData[check].status != RCSHOW_COLLECTED && gSaveContext.checkTrackerData[check].status != RCSHOW_SAVED) &&
(data.status == RCSHOW_COLLECTED || data.status == RCSHOW_SAVED))) {
areaChecksGotten[area]++;
} else if ((gSaveContext.checkTrackerData[check].skipped && !data.skipped) ||
((gSaveContext.checkTrackerData[check].status == RCSHOW_COLLECTED || gSaveContext.checkTrackerData[check].status == RCSHOW_SAVED) &&
(data.status != RCSHOW_COLLECTED && data.status != RCSHOW_SAVED))) {
areaChecksGotten[area]--;
}
gSaveContext.checkTrackerData[check] = data;
UpdateOrdering(area);
}
void CheckTrackerWindow::Draw() {
if (!IsVisible()) {
return;
}
DrawElement();
// Sync up the IsVisible flag if it was changed by ImGui
SyncVisibilityConsoleVariable();
}
void CheckTrackerWindow::DrawElement() { void CheckTrackerWindow::DrawElement() {
if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) { if (CVarGetInteger(CVAR_TRACKER_CHECK("WindowType"), TRACKER_WINDOW_WINDOW) == TRACKER_WINDOW_FLOATING) {
if (CVarGetInteger(CVAR_TRACKER_CHECK("ShowOnlyPaused"), 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) { if (CVarGetInteger(CVAR_TRACKER_CHECK("ShowOnlyPaused"), 0) && (gPlayState == nullptr || gPlayState->pauseCtx.state == 0)) {
@ -985,7 +911,9 @@ void CheckTrackerWindow::DrawElement() {
doAreaScroll = true; doAreaScroll = true;
} }
UIWidgets::Tooltip("Clear the search field"); UIWidgets::Tooltip("Clear the search field");
checkSearch.Draw(); if (checkSearch.Draw()) {
UpdateFilters();
}
UIWidgets::PaddedSeparator(); UIWidgets::PaddedSeparator();
@ -1039,7 +967,7 @@ void CheckTrackerWindow::DrawElement() {
previousShowHidden = showHidden; previousShowHidden = showHidden;
doAreaScroll = true; doAreaScroll = true;
} }
if ((shouldHideFilteredAreas && ShouldHideArea(rcArea)) || if ((shouldHideFilteredAreas && filterAreasHidden[rcArea]) ||
(!showHidden && ((hideComplete && thisAreaFullyChecked) || (hideIncomplete && !thisAreaFullyChecked))) (!showHidden && ((hideComplete && thisAreaFullyChecked) || (hideIncomplete && !thisAreaFullyChecked)))
) { ) {
doDraw = false; doDraw = false;
@ -1099,7 +1027,7 @@ void CheckTrackerWindow::DrawElement() {
doAreaScroll = false; doAreaScroll = false;
} }
for (auto rc : checks) { for (auto rc : checks) {
if (doDraw && isThisAreaSpoiled && ShouldShowCheck(rc)) { if (doDraw && isThisAreaSpoiled && !filterChecksHidden[rc]) {
DrawLocation(rc); DrawLocation(rc);
} }
} }
@ -1119,13 +1047,16 @@ void CheckTrackerWindow::DrawElement() {
} }
} }
bool ShouldHideArea(RandomizerCheckArea rcArea) { bool UpdateFilters() {
if (checkSearch.Filters.Size == 0 || checkSearch.PassFilter(RandomizerCheckObjects::GetRCAreaName(rcArea).c_str())) { for (auto& [rcArea, checks] : checksByArea) {
return false; filterAreasHidden[rcArea] = !checkSearch.PassFilter(RandomizerCheckObjects::GetRCAreaName(rcArea).c_str());
} for (auto check : checks) {
for (auto check : checksByArea[rcArea]) { if (ShouldShowCheck(check)) {
if (ShouldShowCheck(check)) { filterAreasHidden[rcArea] = false;
return false; filterChecksHidden[check] = false;
} else {
filterChecksHidden[check] = true;
}
} }
} }
@ -1136,8 +1067,9 @@ bool ShouldShowCheck(RandomizerCheck check) {
return ( return (
IsVisibleInCheckTracker(check) && IsVisibleInCheckTracker(check) &&
(checkSearch.Filters.Size == 0 || (checkSearch.Filters.Size == 0 ||
checkSearch.PassFilter(RandomizerCheckObjects::GetRCAreaName(Rando::StaticData::GetLocation(check)->GetArea()).c_str()) || checkSearch.PassFilter((Rando::StaticData::GetLocation(check)->GetShortName() + " " +
checkSearch.PassFilter(Rando::StaticData::GetLocation(check)->GetShortName().c_str())) Rando::StaticData::GetLocation(check)->GetName() + " " +
RandomizerCheckObjects::GetRCAreaName(Rando::StaticData::GetLocation(check)->GetArea())).c_str()))
); );
} }
@ -1368,6 +1300,13 @@ void UpdateInventoryChecks() {
void UpdateAreaFullyChecked(RandomizerCheckArea area) { void UpdateAreaFullyChecked(RandomizerCheckArea area) {
} }
void UpdateAllAreas() {
// Sort the entire thing
for (int i = 0; i < RCAREA_INVALID; i++) {
UpdateAreas(static_cast<RandomizerCheckArea>(i));
}
}
void UpdateAreas(RandomizerCheckArea area) { void UpdateAreas(RandomizerCheckArea area) {
areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size(); areasFullyChecked[area] = areaChecksGotten[area] == checksByArea.find(area)->second.size();
} }
@ -1384,7 +1323,7 @@ void UpdateOrdering(RandomizerCheckArea rcArea) {
if(checksByArea.contains(rcArea)) { if(checksByArea.contains(rcArea)) {
std::sort(checksByArea.find(rcArea)->second.begin(), checksByArea.find(rcArea)->second.end(), CompareChecks); std::sort(checksByArea.find(rcArea)->second.begin(), checksByArea.find(rcArea)->second.end(), CompareChecks);
} }
RecalculateAllAreaTotals();
CalculateTotals(); CalculateTotals();
} }
@ -1393,14 +1332,14 @@ bool IsEoDCheck(RandomizerCheckType type) {
} }
bool CompareChecks(RandomizerCheck i, RandomizerCheck j) { bool CompareChecks(RandomizerCheck i, RandomizerCheck j) {
RandomizerCheckTrackerData iShow = gSaveContext.checkTrackerData[i];
RandomizerCheckTrackerData jShow = gSaveContext.checkTrackerData[j];
Rando::Location* x = Rando::StaticData::GetLocation(i); Rando::Location* x = Rando::StaticData::GetLocation(i);
Rando::Location* y = Rando::StaticData::GetLocation(j); Rando::Location* y = Rando::StaticData::GetLocation(j);
bool iCollected = iShow.status == RCSHOW_COLLECTED || iShow.status == RCSHOW_SAVED; auto itemI = OTRGlobals::Instance->gRandoContext->GetItemLocation(i);
bool iSaved = iShow.status == RCSHOW_SAVED; auto itemJ = OTRGlobals::Instance->gRandoContext->GetItemLocation(j);
bool jCollected = jShow.status == RCSHOW_COLLECTED || jShow.status == RCSHOW_SAVED; bool iCollected = itemI->HasObtained();
bool jSaved = jShow.status == RCSHOW_SAVED; bool iSaved = itemI->GetCheckStatus() == RCSHOW_SAVED;
bool jCollected = itemJ->HasObtained();
bool jSaved = itemJ->GetCheckStatus() == RCSHOW_SAVED;
if (!iCollected && jCollected) { if (!iCollected && jCollected) {
return true; return true;
@ -1414,9 +1353,9 @@ bool CompareChecks(RandomizerCheck i, RandomizerCheck j) {
return false; return false;
} }
if (!iShow.skipped && jShow.skipped) { if (!itemI->GetIsSkipped() && itemJ->GetIsSkipped()) {
return true; return true;
} else if (iShow.skipped && !jShow.skipped) { } else if (itemI->GetIsSkipped() && !itemJ->GetIsSkipped()) {
return false; return false;
} }
@ -1446,14 +1385,8 @@ void DrawLocation(RandomizerCheck rc) {
bool showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0); bool showHidden = CVarGetInteger(CVAR_TRACKER_CHECK("ShowHidden"), 0);
Rando::Location* loc = Rando::StaticData::GetLocation(rc); Rando::Location* loc = Rando::StaticData::GetLocation(rc);
Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc); Rando::ItemLocation* itemLoc = OTRGlobals::Instance->gRandoContext->GetItemLocation(rc);
RandomizerCheckTrackerData checkData = gSaveContext.checkTrackerData[rc]; RandomizerCheckStatus status = itemLoc->GetCheckStatus();
RandomizerCheckStatus status = checkData.status; bool skipped = itemLoc->GetIsSkipped();
if (itemLoc->HasObtained()) {
status = RCSHOW_COLLECTED;
}
bool skipped = checkData.skipped;
if (status == RCSHOW_COLLECTED) { if (status == RCSHOW_COLLECTED) {
if (!showHidden && CVarGetInteger(CVAR_TRACKER_CHECK("Collected.Hide"), 0)) { if (!showHidden && CVarGetInteger(CVAR_TRACKER_CHECK("Collected.Hide"), 0)) {
return; return;
@ -1525,11 +1458,13 @@ void DrawLocation(RandomizerCheck rc) {
if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) { if (status == RCSHOW_UNCHECKED || status == RCSHOW_SEEN || status == RCSHOW_IDENTIFIED || status == RCSHOW_SCUMMED || skipped) {
if (UIWidgets::StateButton(std::to_string(rc).c_str(), skipped ? ICON_FA_PLUS : ICON_FA_TIMES)) { if (UIWidgets::StateButton(std::to_string(rc).c_str(), skipped ? ICON_FA_PLUS : ICON_FA_TIMES)) {
if (skipped) { if (skipped) {
gSaveContext.checkTrackerData[rc].skipped = false; OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(false);
areaChecksGotten[loc->GetArea()]--; areaChecksGotten[loc->GetArea()]--;
totalChecksGotten--;
} else { } else {
gSaveContext.checkTrackerData[rc].skipped = true; OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->SetIsSkipped(true);
areaChecksGotten[loc->GetArea()]++; areaChecksGotten[loc->GetArea()]++;
totalChecksGotten++;
} }
UpdateOrdering(loc->GetArea()); UpdateOrdering(loc->GetArea());
UpdateInventoryChecks(); UpdateInventoryChecks();
@ -1550,9 +1485,7 @@ void DrawLocation(RandomizerCheck rc) {
bool mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && itemLoc->IsAddedToPool(); bool mystery = CVarGetInteger(CVAR_RANDOMIZER_ENHANCEMENT("MysteriousShuffle"), 0) && itemLoc->IsAddedToPool();
if (checkData.hintItem != 0) { if (status != RCSHOW_UNCHECKED) {
// TODO hints
} else if (status != RCSHOW_UNCHECKED) {
switch (status) { switch (status) {
case RCSHOW_SAVED: case RCSHOW_SAVED:
case RCSHOW_COLLECTED: case RCSHOW_COLLECTED:
@ -1581,8 +1514,8 @@ void DrawLocation(RandomizerCheck rc) {
} else if (!mystery) { } else if (!mystery) {
txt = itemLoc->GetPlacedItem().GetName().GetForLanguage(gSaveContext.language); txt = itemLoc->GetPlacedItem().GetName().GetForLanguage(gSaveContext.language);
} }
if (!IsVisibleInCheckTracker(rc) && status == RCSHOW_IDENTIFIED && !mystery) { if (IsVisibleInCheckTracker(rc) && status == RCSHOW_IDENTIFIED && !mystery) {
txt += fmt::format(" - {}", gSaveContext.checkTrackerData[rc].price); txt += fmt::format(" - {}", OTRGlobals::Instance->gRandoContext->GetItemLocation(rc)->GetPrice());
} }
} else { } else {
if (IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID())) { if (IsHeartPiece((GetItemID)Rando::StaticData::RetrieveItem(loc->GetVanillaItem()).GetItemID())) {
@ -1608,8 +1541,7 @@ void DrawLocation(RandomizerCheck rc) {
} }
if (CVarGetInteger("gCheckTrackerOptionShowLogic", 0)) { if (CVarGetInteger("gCheckTrackerOptionShowLogic", 0)) {
std::vector<LocationAccess> locationsInRegion = areaTable[itemLoc->GetParentRegionKey()].locations; for (auto& locationInRegion : areaTable[itemLoc->GetParentRegionKey()].locations) {
for (auto& locationInRegion : locationsInRegion) {
if (locationInRegion.GetLocation() == rc) { if (locationInRegion.GetLocation() == rc) {
std::string conditionStr = locationInRegion.GetConditionStr(); std::string conditionStr = locationInRegion.GetConditionStr();
if (conditionStr != "true") { if (conditionStr != "true") {
@ -1742,12 +1674,12 @@ void CheckTrackerSettingsWindow::DrawElement() {
UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked."); UIWidgets::Tooltip("If enabled, Vanilla/MQ dungeons will show on the tracker immediately. Otherwise, Vanilla/MQ dungeon locations must be unlocked.");
if (UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", CVAR_TRACKER_CHECK("HideRightShopChecks"), false, "", UIWidgets::CheckboxGraphics::Cross, true)) { if (UIWidgets::EnhancementCheckbox("Hide right-side shop item checks", CVAR_TRACKER_CHECK("HideRightShopChecks"), false, "", UIWidgets::CheckboxGraphics::Cross, true)) {
hideShopRightChecks = !hideShopRightChecks; hideShopRightChecks = !hideShopRightChecks;
RecalculateAreaTotals(); RecalculateAllAreaTotals();
} }
UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops."); UIWidgets::Tooltip("If enabled, will prevent the tracker from displaying slots 1-4 in all shops.");
if (UIWidgets::EnhancementCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), false, "")) { if (UIWidgets::EnhancementCheckbox("Always show gold skulltulas", CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), false, "")) {
alwaysShowGS = !alwaysShowGS; alwaysShowGS = !alwaysShowGS;
RecalculateAreaTotals(); RecalculateAllAreaTotals();
} }
UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings."); UIWidgets::Tooltip("If enabled, will show GS locations in the tracker regardless of tokensanity settings.");
UIWidgets::EnhancementCheckbox("Show Logic", "gCheckTrackerOptionShowLogic"); UIWidgets::EnhancementCheckbox("Show Logic", "gCheckTrackerOptionShowLogic");
@ -1796,7 +1728,7 @@ void CheckTrackerWindow::InitElement() {
Color_Saved_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Saved.ExtraColor"), Color_Saved_Extra_Default); Color_Saved_Extra = CVarGetColor(CVAR_TRACKER_CHECK("Saved.ExtraColor"), Color_Saved_Extra_Default);
SaveManager::Instance->AddInitFunction(InitTrackerData); SaveManager::Instance->AddInitFunction(InitTrackerData);
sectionId = SaveManager::Instance->AddSaveFunction("trackerData", 1, SaveFile, true, -1); sectionId = SaveManager::Instance->AddSaveFunction("trackerData", 1, SaveFile, true, SECTION_PARENT_NONE);
SaveManager::Instance->AddLoadFunction("trackerData", 1, LoadFile); SaveManager::Instance->AddLoadFunction("trackerData", 1, LoadFile);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>(CheckTrackerLoadGame); GameInteractor::Instance->RegisterGameHook<GameInteractor::OnLoadGame>(CheckTrackerLoadGame);
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([](uint32_t fileNum) { GameInteractor::Instance->RegisterGameHook<GameInteractor::OnExitGame>([](uint32_t fileNum) {
@ -1811,8 +1743,6 @@ void CheckTrackerWindow::InitElement() {
hideShopRightChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideRightShopChecks"), 1); hideShopRightChecks = CVarGetInteger(CVAR_TRACKER_CHECK("HideRightShopChecks"), 1);
alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0); alwaysShowGS = CVarGetInteger(CVAR_TRACKER_CHECK("AlwaysShowGSLocs"), 0);
//LocationTable_Init();
} }
} // namespace CheckTracker } // namespace CheckTracker

View File

@ -21,7 +21,6 @@ class CheckTrackerSettingsWindow : public Ship::GuiWindow {
class CheckTrackerWindow : public Ship::GuiWindow { class CheckTrackerWindow : public Ship::GuiWindow {
public: public:
using GuiWindow::GuiWindow; using GuiWindow::GuiWindow;
void Draw() override;
~CheckTrackerWindow() {}; ~CheckTrackerWindow() {};
protected: protected:
@ -44,20 +43,19 @@ class CheckTrackerWindow : public Ship::GuiWindow {
//repeat... //repeat...
#define INDEX_TO_16BIT_LITTLE_ENDIAN_BITMASK(idx) (0x8000 >> (7 - (idx % 8) + ((idx % 16) / 8) * 8)) #define INDEX_TO_16BIT_LITTLE_ENDIAN_BITMASK(idx) (0x8000 >> (7 - (idx % 8) + ((idx % 16) / 8) * 8))
void DefaultCheckData(RandomizerCheck rc);
void Teardown(); void Teardown();
void UpdateAllOrdering(); void UpdateAllOrdering();
bool IsVisibleInCheckTracker(RandomizerCheck rc); bool IsVisibleInCheckTracker(RandomizerCheck rc);
bool IsCheckShuffled(RandomizerCheck rc); bool IsCheckShuffled(RandomizerCheck rc);
void InitTrackerData(bool isDebug); void InitTrackerData(bool isDebug);
RandomizerCheckArea GetCheckArea(); RandomizerCheckArea GetCheckArea();
void UpdateCheck(uint32_t, RandomizerCheckTrackerData);
uint16_t GetTotalChecks(); uint16_t GetTotalChecks();
uint16_t GetTotalChecksGotten(); uint16_t GetTotalChecksGotten();
bool IsAreaSpoiled(RandomizerCheckArea rcArea); bool IsAreaSpoiled(RandomizerCheckArea rcArea);
void SetAreaSpoiled(RandomizerCheckArea rcArea); void SetAreaSpoiled(RandomizerCheckArea rcArea);
void UpdateInventoryChecks();
void UpdateAreas(RandomizerCheckArea area);
void UpdateAllOrdering();
void UpdateAllAreas();
void RecalculateAllAreaTotals();
} // namespace CheckTracker } // namespace CheckTracker
void to_json(nlohmann::json & j, const RandomizerCheckTrackerData& rctd);
void from_json(const nlohmann::json& j, RandomizerCheckTrackerData& rctd);

View File

@ -97,7 +97,7 @@ void GiveLinksPocketItem() {
if (Randomizer_GetSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING) { if (Randomizer_GetSettingValue(RSK_LINKS_POCKET) != RO_LINKS_POCKET_NOTHING) {
GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, (GetItemID)RG_NONE); GetItemEntry getItemEntry = Randomizer_GetItemFromKnownCheck(RC_LINKS_POCKET, (GetItemID)RG_NONE);
StartingItemGive(getItemEntry); StartingItemGive(getItemEntry);
Rando::Context::GetInstance()->GetItemLocation(RC_LINKS_POCKET)->MarkAsObtained(); Rando::Context::GetInstance()->GetItemLocation(RC_LINKS_POCKET)->SetCheckStatus(RCSHOW_SAVED);
// If we re-add the above, we'll get the item on save creation, now it's given on first load // If we re-add the above, we'll get the item on save creation, now it's given on first load
Flags_SetRandomizerInf(RAND_INF_LINKS_POCKET); Flags_SetRandomizerInf(RAND_INF_LINKS_POCKET);
} }

View File

@ -111,6 +111,7 @@ SaveManager::SaveManager() {
coreSectionIDsByName["sohStats"] = SECTION_ID_STATS; coreSectionIDsByName["sohStats"] = SECTION_ID_STATS;
coreSectionIDsByName["entrances"] = SECTION_ID_ENTRANCES; coreSectionIDsByName["entrances"] = SECTION_ID_ENTRANCES;
coreSectionIDsByName["scenes"] = SECTION_ID_SCENES; coreSectionIDsByName["scenes"] = SECTION_ID_SCENES;
coreSectionIDsByName["trackerData"] = SECTION_ID_TRACKER_DATA;
AddLoadFunction("base", 1, LoadBaseVersion1); AddLoadFunction("base", 1, LoadBaseVersion1);
AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 2, LoadBaseVersion2);
AddLoadFunction("base", 3, LoadBaseVersion3); AddLoadFunction("base", 3, LoadBaseVersion3);
@ -404,13 +405,6 @@ void SaveManager::LoadRandomizerVersion3() {
// all ItemLocations is 0 anyway. // all ItemLocations is 0 anyway.
randoContext->GetItemLocation(i)->SetCustomPrice(price); randoContext->GetItemLocation(i)->SetCustomPrice(price);
} }
uint16_t obtained = 0;
SaveManager::Instance->LoadData("obtained", obtained, (uint16_t)0);
if (obtained) {
randoContext->GetItemLocation(i)->MarkAsObtained();
} else {
randoContext->GetItemLocation(i)->MarkAsNotObtained();
}
}); });
}); });
@ -496,7 +490,6 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID, bool f
if (randoContext->GetItemLocation(i)->HasCustomPrice()) { if (randoContext->GetItemLocation(i)->HasCustomPrice()) {
SaveManager::Instance->SaveData("price", randoContext->GetItemLocation(i)->GetPrice()); SaveManager::Instance->SaveData("price", randoContext->GetItemLocation(i)->GetPrice());
} }
SaveManager::Instance->SaveData("obtained", randoContext->GetItemLocation(i)->HasObtained());
}); });
}); });
@ -666,8 +659,8 @@ void SaveManager::Init() {
if (std::filesystem::exists(GetFileName(fileNum))) { if (std::filesystem::exists(GetFileName(fileNum))) {
LoadFile(fileNum); LoadFile(fileNum);
saveBlock = nlohmann::json::object(); saveBlock = nlohmann::json::object();
OTRGlobals::Instance->gRandoContext->ClearItemLocations();
} }
} }
} }

View File

@ -163,6 +163,8 @@ class SaveManager {
static void LoadRandomizerVersion1(); static void LoadRandomizerVersion1();
static void LoadRandomizerVersion2(); static void LoadRandomizerVersion2();
static void LoadRandomizerVersion3(); static void LoadRandomizerVersion3();
static void LoadTrackerData();
static void SaveTrackerData(SaveContext* saveContext, int sectionID, bool fullSave);
static void SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave); static void SaveRandomizer(SaveContext* saveContext, int sectionID, bool fullSave);
static void LoadBaseVersion1(); static void LoadBaseVersion1();