mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 14:23:44 -07:00
Created the initial Logic Tracker.
This commit is contained in:
parent
0c19604a38
commit
1d09631215
8 changed files with 378 additions and 29 deletions
|
@ -5,6 +5,7 @@
|
||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <stack>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
|
||||||
|
@ -1032,3 +1033,106 @@ LogicExpression::ValueVariant LogicExpression::Impl::Evaluate(const std::string&
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpressionEvaluation EvaluateExpression(std::string condition) {
|
||||||
|
const auto& expression = LogicExpression::Parse(condition);
|
||||||
|
|
||||||
|
// Create a vector to store the evaluation sequence
|
||||||
|
std::vector<std::tuple<std::string, std::string, int, std::string, LogicExpression::ValueVariant>>
|
||||||
|
evaluationSequence;
|
||||||
|
|
||||||
|
// Define a callback that records each evaluation step
|
||||||
|
auto recordCallback = [&evaluationSequence](const std::string& exprStr, const std::string& path, int depth,
|
||||||
|
const std::string& type, const LogicExpression::ValueVariant& result) {
|
||||||
|
evaluationSequence.emplace_back(exprStr, path, depth, type, result);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Evaluate the expression with the callback
|
||||||
|
auto finalResult = expression->Evaluate<LogicExpression::ValueVariant>(recordCallback);
|
||||||
|
|
||||||
|
// Helper function to convert path string to a vector of integers for sorting
|
||||||
|
auto pathToVector = [](const std::string& path) {
|
||||||
|
std::vector<int> result;
|
||||||
|
std::stringstream ss(path);
|
||||||
|
std::string segment;
|
||||||
|
|
||||||
|
while (std::getline(ss, segment, '.')) {
|
||||||
|
try {
|
||||||
|
result.push_back(std::stoi(segment));
|
||||||
|
} catch (const std::exception&) {
|
||||||
|
// If it's not a valid integer, just skip it
|
||||||
|
result.push_back(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Sort the evaluation sequence by path
|
||||||
|
std::sort(evaluationSequence.begin(), evaluationSequence.end(), [&pathToVector](const auto& a, const auto& b) {
|
||||||
|
const auto& pathA = std::get<1>(a);
|
||||||
|
const auto& pathB = std::get<1>(b);
|
||||||
|
|
||||||
|
auto vecA = pathToVector(pathA);
|
||||||
|
auto vecB = pathToVector(pathB);
|
||||||
|
|
||||||
|
// Compare each component of the path
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < vecA.size() && i < vecB.size()) {
|
||||||
|
if (vecA[i] != vecB[i]) {
|
||||||
|
return vecA[i] < vecB[i];
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If one path is a prefix of the other, the shorter one comes first
|
||||||
|
return vecA.size() < vecB.size();
|
||||||
|
});
|
||||||
|
|
||||||
|
ExpressionEvaluation evaluation;
|
||||||
|
evaluation.Expression = std::get<0>(evaluationSequence[0]);
|
||||||
|
evaluation.Depth = std::get<2>(evaluationSequence[0]);
|
||||||
|
evaluation.Type = std::get<3>(evaluationSequence[0]);
|
||||||
|
evaluation.Result = std::get<4>(evaluationSequence[0]);
|
||||||
|
|
||||||
|
// Stack to keep track of parent nodes at each depth
|
||||||
|
std::stack<ExpressionEvaluation*> parentStack;
|
||||||
|
parentStack.push(&evaluation);
|
||||||
|
|
||||||
|
// Process remaining evaluations to build the tree
|
||||||
|
for (size_t i = 1; i < evaluationSequence.size(); ++i) {
|
||||||
|
ExpressionEvaluation child;
|
||||||
|
child.Expression = std::get<0>(evaluationSequence[i]);
|
||||||
|
child.Depth = std::get<2>(evaluationSequence[i]);
|
||||||
|
child.Type = std::get<3>(evaluationSequence[i]);
|
||||||
|
child.Result = std::get<4>(evaluationSequence[i]);
|
||||||
|
|
||||||
|
// Pop parents from stack if we're at a shallower depth
|
||||||
|
while (!parentStack.empty() && parentStack.top()->Depth >= child.Depth) {
|
||||||
|
parentStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add child to current parent
|
||||||
|
if (!parentStack.empty()) {
|
||||||
|
parentStack.top()->Children.push_back(std::move(child));
|
||||||
|
// If this child might have children, push it onto the stack
|
||||||
|
parentStack.push(&(parentStack.top()->Children.back()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return evaluation;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string ToString(const LogicExpression::ValueVariant& value) {
|
||||||
|
if (std::holds_alternative<bool>(value)) {
|
||||||
|
return std::get<bool>(value) ? "true" : "false";
|
||||||
|
} else if (std::holds_alternative<int>(value)) {
|
||||||
|
return std::to_string(std::get<int>(value));
|
||||||
|
} else if (std::holds_alternative<uint8_t>(value)) {
|
||||||
|
return std::to_string(std::get<uint8_t>(value));
|
||||||
|
} else if (std::holds_alternative<uint16_t>(value)) {
|
||||||
|
return std::to_string(std::get<uint16_t>(value));
|
||||||
|
} else {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -22,7 +22,34 @@ class LogicExpression {
|
||||||
|
|
||||||
// Add optional callback parameter to Evaluate
|
// Add optional callback parameter to Evaluate
|
||||||
template <typename T> T Evaluate(const EvaluationCallback& callback = nullptr) const {
|
template <typename T> T Evaluate(const EvaluationCallback& callback = nullptr) const {
|
||||||
return Impl::GetValue<T>(impl->Evaluate("0", 0, callback));
|
return GetValue<T>(impl->Evaluate("0", 0, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> static T GetValue(const ValueVariant& value) {
|
||||||
|
if constexpr (std::is_same_v<T, bool>) {
|
||||||
|
if (std::holds_alternative<bool>(value))
|
||||||
|
return std::get<bool>(value);
|
||||||
|
if (std::holds_alternative<int>(value))
|
||||||
|
return std::get<int>(value) != 0;
|
||||||
|
if (std::holds_alternative<uint8_t>(value))
|
||||||
|
return std::get<uint8_t>(value) != 0;
|
||||||
|
if (std::holds_alternative<uint16_t>(value))
|
||||||
|
return std::get<uint16_t>(value) != 0;
|
||||||
|
throw std::bad_variant_access();
|
||||||
|
} else if constexpr (std::is_same_v<T, int>)
|
||||||
|
return std::get<int>(value);
|
||||||
|
else if constexpr (std::is_same_v<T, uint8_t>)
|
||||||
|
return std::holds_alternative<uint8_t>(value) ? std::get<uint8_t>(value)
|
||||||
|
: static_cast<uint8_t>(std::get<int>(value));
|
||||||
|
else if constexpr (std::is_same_v<T, uint16_t>)
|
||||||
|
return std::holds_alternative<uint16_t>(value) ? std::get<uint16_t>(value)
|
||||||
|
: static_cast<uint16_t>(std::get<int>(value));
|
||||||
|
else if constexpr (std::is_enum_v<T>)
|
||||||
|
return static_cast<T>(std::get<int>(value));
|
||||||
|
else if constexpr (std::is_same_v<T, ValueVariant>)
|
||||||
|
return value;
|
||||||
|
else
|
||||||
|
static_assert(sizeof(T) == 0, "Unsupported function parameter type");
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -48,33 +75,6 @@ class LogicExpression {
|
||||||
// Helper to get a string representation of the type
|
// Helper to get a string representation of the type
|
||||||
std::string GetTypeString() const;
|
std::string GetTypeString() const;
|
||||||
|
|
||||||
template <typename T> static T GetValue(const ValueVariant& value) {
|
|
||||||
if constexpr (std::is_same_v<T, bool>) {
|
|
||||||
if (std::holds_alternative<bool>(value))
|
|
||||||
return std::get<bool>(value);
|
|
||||||
if (std::holds_alternative<int>(value))
|
|
||||||
return std::get<int>(value) != 0;
|
|
||||||
if (std::holds_alternative<uint8_t>(value))
|
|
||||||
return std::get<uint8_t>(value) != 0;
|
|
||||||
if (std::holds_alternative<uint16_t>(value))
|
|
||||||
return std::get<uint16_t>(value) != 0;
|
|
||||||
throw std::bad_variant_access();
|
|
||||||
} else if constexpr (std::is_same_v<T, int>)
|
|
||||||
return std::get<int>(value);
|
|
||||||
else if constexpr (std::is_same_v<T, uint8_t>)
|
|
||||||
return std::holds_alternative<uint8_t>(value) ? std::get<uint8_t>(value)
|
|
||||||
: static_cast<uint8_t>(std::get<int>(value));
|
|
||||||
else if constexpr (std::is_same_v<T, uint16_t>)
|
|
||||||
return std::holds_alternative<uint16_t>(value) ? std::get<uint16_t>(value)
|
|
||||||
: static_cast<uint16_t>(std::get<int>(value));
|
|
||||||
else if constexpr (std::is_enum_v<T>)
|
|
||||||
return static_cast<T>(std::get<int>(value));
|
|
||||||
else if constexpr (std::is_same_v<T, ValueVariant>)
|
|
||||||
return value;
|
|
||||||
else
|
|
||||||
static_assert(sizeof(T) == 0, "Unsupported function parameter type");
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string GetExprErrorContext() const;
|
std::string GetExprErrorContext() const;
|
||||||
// Updated to pass callback to children
|
// Updated to pass callback to children
|
||||||
|
@ -298,3 +298,15 @@ class LogicExpression {
|
||||||
friend class Parser;
|
friend class Parser;
|
||||||
friend bool IsEnumConstant(const std::string& s);
|
friend bool IsEnumConstant(const std::string& s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExpressionEvaluation {
|
||||||
|
std::string Expression;
|
||||||
|
int Depth;
|
||||||
|
std::string Type;
|
||||||
|
LogicExpression::ValueVariant Result;
|
||||||
|
std::vector<ExpressionEvaluation> Children;
|
||||||
|
};
|
||||||
|
|
||||||
|
ExpressionEvaluation EvaluateExpression(std::string condition);
|
||||||
|
|
||||||
|
std::string ToString(const LogicExpression::ValueVariant& value);
|
|
@ -69,7 +69,6 @@ typedef enum {
|
||||||
|
|
||||||
#define DEFINE_TRIAL_KEY(enum) enum,
|
#define DEFINE_TRIAL_KEY(enum) enum,
|
||||||
typedef enum {
|
typedef enum {
|
||||||
TK_NONE,
|
|
||||||
#include "randomizer_types/trialKey.h"
|
#include "randomizer_types/trialKey.h"
|
||||||
TK_MAX,
|
TK_MAX,
|
||||||
} TrialKey;
|
} TrialKey;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include "randomizer_check_tracker.h"
|
#include "randomizer_check_tracker.h"
|
||||||
#include "randomizer_entrance_tracker.h"
|
#include "randomizer_entrance_tracker.h"
|
||||||
#include "randomizer_item_tracker.h"
|
#include "randomizer_item_tracker.h"
|
||||||
|
#include "randomizer_logic_tracker.h"
|
||||||
#include "randomizerTypes.h"
|
#include "randomizerTypes.h"
|
||||||
#include "soh/OTRGlobals.h"
|
#include "soh/OTRGlobals.h"
|
||||||
#include "soh/cvar_prefixes.h"
|
#include "soh/cvar_prefixes.h"
|
||||||
|
@ -1925,6 +1926,13 @@ void DrawLocation(RandomizerCheck rc) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::PushID((std::to_string(rc) + "_SHOW_LOGIC").c_str());
|
||||||
|
if (ImGui::Button("Show Logic")) {
|
||||||
|
LogicTrackerWindow::ShowRandomizerCheck(rc);
|
||||||
|
}
|
||||||
|
ImGui::PopID();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
207
soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp
Normal file
207
soh/soh/Enhancements/randomizer/randomizer_logic_tracker.cpp
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
#include "randomizer_logic_tracker.h"
|
||||||
|
|
||||||
|
#include "location_access.h"
|
||||||
|
#include "logic_expression.h"
|
||||||
|
|
||||||
|
#include <src/Context.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "macros.h"
|
||||||
|
#include "functions.h"
|
||||||
|
#include "variables.h"
|
||||||
|
extern PlayState* gPlayState;
|
||||||
|
uint64_t GetUnixTimestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LogicTrackerCheck {
|
||||||
|
struct Region {
|
||||||
|
std::string RegionName;
|
||||||
|
std::unique_ptr<ExpressionEvaluation> ChildDay;
|
||||||
|
std::unique_ptr<ExpressionEvaluation> ChildNight;
|
||||||
|
std::unique_ptr<ExpressionEvaluation> AdultDay;
|
||||||
|
std::unique_ptr<ExpressionEvaluation> AdultNight;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string CheckName;
|
||||||
|
std::vector<Region> Regions;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<LogicTrackerCheck> checks;
|
||||||
|
|
||||||
|
void LogicTrackerWindow::ShowRandomizerCheck(RandomizerCheck check) {
|
||||||
|
checks.clear();
|
||||||
|
|
||||||
|
const auto& location = Rando::StaticData::GetLocation(check);
|
||||||
|
|
||||||
|
LogicTrackerCheck logicTrackerCheck;
|
||||||
|
logicTrackerCheck.CheckName = location->GetName();
|
||||||
|
|
||||||
|
for (const auto& region : areaTable) {
|
||||||
|
for (const auto& locationAccess : region.locations) {
|
||||||
|
if (locationAccess.GetLocation() == check) {
|
||||||
|
LogicTrackerCheck::Region regionAgeTime;
|
||||||
|
regionAgeTime.RegionName = region.regionName;
|
||||||
|
|
||||||
|
if (region.childDay) {
|
||||||
|
logic->IsChild = true;
|
||||||
|
logic->AtDay = true;
|
||||||
|
|
||||||
|
regionAgeTime.ChildDay =
|
||||||
|
std::make_unique<ExpressionEvaluation>(EvaluateExpression(locationAccess.GetConditionStr()));
|
||||||
|
|
||||||
|
logic->IsChild = false;
|
||||||
|
logic->AtDay = false;
|
||||||
|
}
|
||||||
|
if (region.childNight) {
|
||||||
|
logic->IsChild = true;
|
||||||
|
logic->AtNight = true;
|
||||||
|
|
||||||
|
regionAgeTime.ChildNight =
|
||||||
|
std::make_unique<ExpressionEvaluation>(EvaluateExpression(locationAccess.GetConditionStr()));
|
||||||
|
|
||||||
|
logic->IsChild = false;
|
||||||
|
logic->AtNight = false;
|
||||||
|
}
|
||||||
|
if (region.adultDay) {
|
||||||
|
logic->IsAdult = true;
|
||||||
|
logic->AtDay = true;
|
||||||
|
|
||||||
|
regionAgeTime.AdultDay =
|
||||||
|
std::make_unique<ExpressionEvaluation>(EvaluateExpression(locationAccess.GetConditionStr()));
|
||||||
|
|
||||||
|
logic->IsAdult = false;
|
||||||
|
logic->AtDay = false;
|
||||||
|
}
|
||||||
|
if (region.adultNight) {
|
||||||
|
logic->IsAdult = true;
|
||||||
|
logic->AtNight = true;
|
||||||
|
|
||||||
|
regionAgeTime.AdultNight =
|
||||||
|
std::make_unique<ExpressionEvaluation>(EvaluateExpression(locationAccess.GetConditionStr()));
|
||||||
|
|
||||||
|
logic->IsAdult = false;
|
||||||
|
logic->AtNight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
logicTrackerCheck.Regions.emplace_back(std::move(regionAgeTime));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
checks.emplace_back(std::move(logicTrackerCheck));
|
||||||
|
|
||||||
|
Ship::Context::GetInstance()->GetWindow()->GetGui()->GetGuiWindow("Logic Tracker")->Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TruncateText(const std::string& text, float maxWidth) {
|
||||||
|
ImVec2 textSize = ImGui::CalcTextSize(text.c_str());
|
||||||
|
if (textSize.x <= maxWidth)
|
||||||
|
return text;
|
||||||
|
|
||||||
|
std::string truncated = text;
|
||||||
|
// Remove characters until the text fits with the ellipsis appended
|
||||||
|
while (!truncated.empty() && ImGui::CalcTextSize((truncated + "...").c_str()).x > maxWidth) {
|
||||||
|
truncated.pop_back();
|
||||||
|
}
|
||||||
|
return truncated + "...";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DrawExpression(const ExpressionEvaluation& expression) {
|
||||||
|
ImGuiTreeNodeFlags treeNodeFlags =
|
||||||
|
expression.Children.empty() ? ImGuiTreeNodeFlags_Leaf : ImGuiTreeNodeFlags_DefaultOpen;
|
||||||
|
|
||||||
|
float availableWidth = ImGui::GetContentRegionAvail().x - ImGui::GetTreeNodeToLabelSpacing();
|
||||||
|
auto text = TruncateText(ToString(expression.Result) + " = " + expression.Expression, availableWidth);
|
||||||
|
|
||||||
|
if (ImGui::TreeNodeEx(&expression, treeNodeFlags, "%s", text.c_str())) {
|
||||||
|
if (!expression.Children.empty()) {
|
||||||
|
for (const auto& child : expression.Children) {
|
||||||
|
DrawExpression(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DrawCheckRegion(const LogicTrackerCheck::Region& region) {
|
||||||
|
if (ImGui::TreeNodeEx(region.RegionName.c_str(), ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
|
if (region.ChildDay != nullptr) {
|
||||||
|
bool resultString = LogicExpression::GetValue<bool>(region.ChildDay->Result);
|
||||||
|
if (ImGui::TreeNodeEx(region.ChildDay.get(), ImGuiTreeNodeFlags_DefaultOpen, "Child-Day Result: %s",
|
||||||
|
resultString ? "true" : "false")) {
|
||||||
|
DrawExpression(*region.ChildDay);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::TreeNodeEx("Child-Day Inaccessible", ImGuiTreeNodeFlags_Leaf)) {
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region.ChildNight != nullptr) {
|
||||||
|
bool resultString = LogicExpression::GetValue<bool>(region.ChildNight->Result);
|
||||||
|
if (ImGui::TreeNodeEx(region.ChildNight.get(), ImGuiTreeNodeFlags_DefaultOpen, "Child-Night Result: %s",
|
||||||
|
resultString ? "true" : "false")) {
|
||||||
|
DrawExpression(*region.ChildNight);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::TreeNodeEx("Child-Night Inaccessible", ImGuiTreeNodeFlags_Leaf)) {
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region.AdultDay != nullptr) {
|
||||||
|
bool resultString = LogicExpression::GetValue<bool>(region.AdultDay->Result);
|
||||||
|
if (ImGui::TreeNodeEx(region.AdultDay.get(), ImGuiTreeNodeFlags_DefaultOpen, "Adult-Day Result: %s",
|
||||||
|
resultString ? "true" : "false")) {
|
||||||
|
DrawExpression(*region.AdultDay);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::TreeNodeEx("Adult-Day Inaccessible", ImGuiTreeNodeFlags_Leaf)) {
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (region.AdultNight != nullptr) {
|
||||||
|
bool resultString = LogicExpression::GetValue<bool>(region.AdultNight->Result);
|
||||||
|
if (ImGui::TreeNodeEx(region.AdultNight.get(), ImGuiTreeNodeFlags_DefaultOpen, "Adult-Night Result: %s",
|
||||||
|
resultString ? "true" : "false")) {
|
||||||
|
DrawExpression(*region.AdultNight);
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (ImGui::TreeNodeEx("Adult-Night Inaccessible", ImGuiTreeNodeFlags_Leaf)) {
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void DrawCheck(const LogicTrackerCheck& check) {
|
||||||
|
ImGui::SeparatorText(("Check: " + check.CheckName).c_str());
|
||||||
|
if (check.Regions.empty()) {
|
||||||
|
ImGui::Text("No regions found for this check.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const auto& region : check.Regions) {
|
||||||
|
DrawCheckRegion(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicTrackerWindow::DrawElement() {
|
||||||
|
for (const auto& check : checks) {
|
||||||
|
DrawCheck(check);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicTrackerWindow::InitElement() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogicTrackerWindow::UpdateElement() {
|
||||||
|
return;
|
||||||
|
}
|
15
soh/soh/Enhancements/randomizer/randomizer_logic_tracker.h
Normal file
15
soh/soh/Enhancements/randomizer/randomizer_logic_tracker.h
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <libultraship/libultraship.h>
|
||||||
|
|
||||||
|
class LogicTrackerWindow : public Ship::GuiWindow {
|
||||||
|
public:
|
||||||
|
using GuiWindow::GuiWindow;
|
||||||
|
void DrawElement() override;
|
||||||
|
|
||||||
|
static void ShowRandomizerCheck(RandomizerCheck check);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InitElement() override;
|
||||||
|
void UpdateElement() override;
|
||||||
|
};
|
|
@ -97,6 +97,7 @@ std::shared_ptr<RandomizerSettingsWindow> mRandomizerSettingsWindow;
|
||||||
std::shared_ptr<SohModalWindow> mModalWindow;
|
std::shared_ptr<SohModalWindow> mModalWindow;
|
||||||
std::shared_ptr<Notification::Window> mNotificationWindow;
|
std::shared_ptr<Notification::Window> mNotificationWindow;
|
||||||
std::shared_ptr<TimeDisplayWindow> mTimeDisplayWindow;
|
std::shared_ptr<TimeDisplayWindow> mTimeDisplayWindow;
|
||||||
|
std::shared_ptr<LogicTrackerWindow> mLogicTrackerWindow;
|
||||||
|
|
||||||
UIWidgets::Colors GetMenuThemeColor() {
|
UIWidgets::Colors GetMenuThemeColor() {
|
||||||
return mSohMenu->GetMenuThemeColor();
|
return mSohMenu->GetMenuThemeColor();
|
||||||
|
@ -202,6 +203,8 @@ void SetupGuiElements() {
|
||||||
mNotificationWindow->Show();
|
mNotificationWindow->Show();
|
||||||
mTimeDisplayWindow = std::make_shared<TimeDisplayWindow>(CVAR_WINDOW("TimeDisplayEnabled"), "Additional Timers");
|
mTimeDisplayWindow = std::make_shared<TimeDisplayWindow>(CVAR_WINDOW("TimeDisplayEnabled"), "Additional Timers");
|
||||||
gui->AddGuiWindow(mTimeDisplayWindow);
|
gui->AddGuiWindow(mTimeDisplayWindow);
|
||||||
|
mLogicTrackerWindow = std::make_shared<LogicTrackerWindow>(CVAR_WINDOW("LogicTrackerEnabled"), "Logic Tracker");
|
||||||
|
gui->AddGuiWindow(mLogicTrackerWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Destroy() {
|
void Destroy() {
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "soh/Enhancements/timesplits/TimeSplits.h"
|
#include "soh/Enhancements/timesplits/TimeSplits.h"
|
||||||
#include "soh/Enhancements/randomizer/Plandomizer.h"
|
#include "soh/Enhancements/randomizer/Plandomizer.h"
|
||||||
#include "SohModals.h"
|
#include "SohModals.h"
|
||||||
|
#include "soh/Enhancements/randomizer/randomizer_logic_tracker.h"
|
||||||
|
|
||||||
namespace SohGui {
|
namespace SohGui {
|
||||||
void SetupHooks();
|
void SetupHooks();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue