PRing for review

This commit is contained in:
Caladius 2024-02-19 17:17:36 -05:00
parent 4db8de6ef5
commit 413cb1ce02
3 changed files with 214 additions and 74 deletions

View File

@ -245,36 +245,6 @@ const char* const countMappings[] = {
char itemTimestampDisplayName[TIMESTAMP_MAX][21] = { "" };
ImVec4 itemTimestampDisplayColor[TIMESTAMP_MAX];
static const char* splitEntries[156] {
"Deku Stick", "Deku Nut", "Bombs", "Fairy Bow", "Fire Arrow", "Din's Fire",
"Slingshot", "Fairy Ocarina", "Ocarina of Time", "Bombchus", "Hookshot", "Longshot",
"Ice Arrow", "Farore's Wind", "Boomerang", "Lens of Truth", "Magic Beans", "Megaton Hammer",
"Light Arrow", "Nayru's Love", "Bottle", "Red Potion", "Green Potion", "Blue Potion",
"Fairy", "Fish", "Milk (Full)", "Ruto's Letter", "Blue Fire", "Bugs",
"Big Poe", "Milk (Half)", "Poe", "Weird Egg", "Chicken", "Zelda's Letter",
"Keaton Mask", "Skull Mask", "Spooky Mask", "Bunny Hood", "Goron Mask", "Zora Mask",
"Gerudo Mask", "Mask of Truth", "Sold Out", "Pocket Egg", "Pocket Cucco", "Cojiro",
"Odd Mushroom", "Odd Potion", "Poacher's Saw", "Broken Goron Sword", "Prescription", "Eyeball Frog",
"Eye Drops", "Claim Check", "SPLIT_BOW_ARROW_FIRE", "SPLIT_BOW_ARROW_ICE", "SPLIT_BOW_ARROW_LIGHT", "Kokiri Sword",
"Master Sword", "Biggoron's Sword", "Deku Shield", "Hylian Shield", "Mirror Shield", "Kokiri Tunic",
"Goron Tunic", "Zora Tunic", "Kokiri Boots", "Iron Boots", "Hover Boots", "Bullet Bag (30)",
"Bullet Bag (40)", "Bullet Bag (50)", "Quiver (30)", "Quiver (40)", "Quiver (50)", "Bomb Bag (20)",
"Bomb Bag (30)", "Bomb Bag (40)", "Goron's Bracelet", "Silver Gauntlets", "Gold Gauntlets", "Silver Scale",
"Golden Scale", "Giant's Knife", "Adult Wallet", "Giant's Wallet", "Seeds", "Fishing Pole",
"Minuet of Forest", "Bolero of Fire", "Serenade of Water", "Requiem of Spirit", "Nocturne of Shadow", "Prelude of Light",
"Zelda's Lullaby", "Epona's Song", "Saria's Song", "Sun's Song", "Song of Time", "Song of Storms",
"Forest Medallion", "Fire Medallion", "Water Medallion", "Spirit Medallion", "Shadow Medallion", "Light Medallion",
"Kokiri's Emerald", "Goron's Ruby", "Zora's Sapphire", "Stone of Agony", "Gerudo Membership Card", "Skulltula Token",
"Heart Container", "Piece of Heart", "Boss Key", "Compass", "Map", "Small Key",
"Magic Refill (Small)", "Magic Refill (Large)", "Piece of Heart (2)", "Magic Meter (Single)", "Magic Meter (Double)", "Double Defense",
"Null 4", "Null 5", "Null 6", "Null 7", "Milk", "Recovery Heart",
"Green Rupee", "Blue Rupee", "Red Rupee", "Purple Rupee", "Gold Rupee", "Null 8",
"Deku Sticks (5)", "Deku Sticks (10)", "Deku Nuts (5)", "Deku Nuts (10)", "Bombs (5)", "Bombs (10)",
"Bombs (20)", "Bombs (30)", "Arrows (Small)", "Arrows (Medium)", "Arrows (Large)", "Seeds (30)",
"Bombchus (5)", "Bombchus (10)", "Deku Stick Upgrade (20)", "Deku Stick Upgrade (30)",
"Deku Nut Upgrade (30)","Deku Nut Upgrade (40)",
};
typedef struct {
char name[40];
u32 time;

View File

@ -5,9 +5,15 @@
#include "soh/SaveManager.h"
#include "soh/util.h"
#include <vector>
#include "include/z64item.h"
#include "nlohmann-json/include/nlohmann/json.hpp"
#include <fstream>
#include <filesystem>
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/debugger/debugSaveEditor.h"
extern "C" {
extern SaveContext gSaveContext;
@ -16,7 +22,9 @@ extern "C" {
// ImVec4 Colors
#define COLOR_WHITE ImVec4(1.00f, 1.00f, 1.00f, 1.00f)
#define COLOR_LIGHT_RED ImVec4(1.0f, 0.05f, 0.0f, 1.0f)
#define COLOR_RED ImVec4(1.00f, 0.00f, 0.00f, 1.00f)
#define COLOR_LIGHT_GREEN ImVec4(0.52f, 1.0f, 0.23f, 1.0f)
#define COLOR_GREEN ImVec4(0.10f, 1.00f, 0.10f, 1.00f)
#define COLOR_BLUE ImVec4(0.00f, 0.33f, 1.00f, 1.00f)
#define COLOR_PURPLE ImVec4(0.54f, 0.19f, 0.89f, 1.00f)
@ -25,14 +33,21 @@ extern "C" {
#define COLOR_LIGHT_BLUE ImVec4(0.00f, 0.88f, 1.00f, 1.00f)
#define COLOR_GREY ImVec4(0.78f, 0.78f, 0.78f, 1.00f)
static std::vector<int> splitItem;
static std::vector<std::string> splitTime;
static std::vector<int> splitStatus;
static std::vector<uint32_t> splitItem;
static std::vector<uint32_t> splitTime;
static std::vector<uint32_t> splitBest;
static std::vector<uint32_t> splitPreviousBest;
static std::vector<uint32_t> splitStatus;
static uint32_t itemReference = ITEM_STICK;
static std::string status = "";
static ImVec4 statusColor = COLOR_WHITE;
std::time_t convertedTime;
const char* itemTime;
static uint32_t splitCurNum = 0;
std::string splitAttempt = "Attempt #: 0";
static std::string splitNumDisp = "Attempt #: ";
static ImVec4 colorChoice = ImVec4(0.0f, 0.0f, 0.0f, 1.0f);
static const char* backgroundColor;
using json = nlohmann::json;
std::string formatTimestampTimeSplit(uint32_t value) {
uint32_t sec = value / 10;
@ -43,25 +58,18 @@ std::string formatTimestampTimeSplit(uint32_t value) {
return fmt::format("{}:{:0>2}:{:0>2}.{}", hh, mm, ss, ds);
}
void TimeSplitTimeHandler() {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
itemTime = temp.c_str();
}
void TimeSplitSplitsHandler(GetItemEntry itemEntry) {
if (itemEntry.modIndex != 0) {
return;
}
uint32_t loopCounter = 0;
for (auto& str : splitItem) {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
const char* timeValue = temp.c_str();
if (itemEntry.itemId == splitItem[loopCounter]) {
splitTime[loopCounter] = timeValue;
splitTime[loopCounter] = GAMEPLAYSTAT_TOTAL_TIME;
splitStatus[loopCounter] = 1;
if (splitTime[loopCounter] < splitBest[loopCounter]) {
splitBest[loopCounter] = splitTime[loopCounter];
}
}
loopCounter++;
}
@ -69,38 +77,61 @@ void TimeSplitSplitsHandler(GetItemEntry itemEntry) {
void DrawTimeSplitSplits(){
uint32_t loopCounter = 0;
ImGui::TextColored(COLOR_YELLOW, (splitAttempt).c_str());
ImGui::BeginTable("Splits", 4);
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Items");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Current Times");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "+/-");
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_LIGHT_BLUE, "Previous Best");
ImGui::BeginTable("Splits", 5, ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable);
ImGui::TableSetupColumn("Item Image", ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHeaderLabel, 22.0f);
ImGui::TableSetupColumn("Item Name");
ImGui::TableSetupColumn("Current Time", ImGuiTableColumnFlags_WidthFixed, 90.0f);
ImGui::TableSetupColumn("+/-", ImGuiTableColumnFlags_WidthFixed, 80.0f);
ImGui::TableSetupColumn("Prev. Best", ImGuiTableColumnFlags_WidthFixed, 90.0f);
ImGui::TableHeadersRow();
for (auto& str : splitItem) {
ImGui::TableNextColumn();
ImGui::TextColored(COLOR_WHITE, SohUtils::itemNames[splitItem[loopCounter]].c_str());
// Item Image
ImGui::Image(LUS::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(itemImage[splitItem[loopCounter]]), ImVec2(24.0f, 24.0f), ImVec2(0, 0), ImVec2(1, 1));
ImGui::TableNextColumn();
if (splitStatus[loopCounter] == 0) {
uint32_t num = GAMEPLAYSTAT_TOTAL_TIME;
std::string temp = formatTimestampTimeSplit(num);
itemTime = temp.c_str();
//TimeSplitTimeHandler();
ImGui::TextColored(COLOR_WHITE, itemTime);
// Item Name
ImGui::Text(SohUtils::itemNames[splitItem[loopCounter]].c_str());
ImGui::TableNextColumn();
// Current Time
if (splitTime[loopCounter] == 0) {
ImGui::Text(formatTimestampTimeSplit(GAMEPLAYSTAT_TOTAL_TIME).c_str());
} else {
ImGui::TextColored(COLOR_GREEN, splitTime[loopCounter].c_str());
ImGui::Text(formatTimestampTimeSplit(splitTime[loopCounter]).c_str());
}
ImGui::TableNextColumn();
// to-do: split difference +/- with colored indicators
ImGui::TextColored(COLOR_WHITE, "Not Supported");
// +/-
if (splitStatus[loopCounter] == 0) {
if (splitPreviousBest[loopCounter] == 0) {
ImGui::TextColored(COLOR_WHITE, formatTimestampTimeSplit(GAMEPLAYSTAT_TOTAL_TIME).c_str());
} else {
if (GAMEPLAYSTAT_TOTAL_TIME < splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_LIGHT_GREEN, formatTimestampTimeSplit(splitPreviousBest[loopCounter] - GAMEPLAYSTAT_TOTAL_TIME).c_str());
} else if (GAMEPLAYSTAT_TOTAL_TIME == splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_WHITE, formatTimestampTimeSplit(splitPreviousBest[loopCounter]).c_str());
} else if (GAMEPLAYSTAT_TOTAL_TIME > splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_LIGHT_RED, formatTimestampTimeSplit(GAMEPLAYSTAT_TOTAL_TIME - splitPreviousBest[loopCounter]).c_str());
}
}
} else {
if (splitPreviousBest[loopCounter] == 0) {
ImGui::TextColored(COLOR_GREEN, formatTimestampTimeSplit(splitTime[loopCounter]).c_str());
} else {
if (splitTime[loopCounter] < splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_GREEN, formatTimestampTimeSplit(splitPreviousBest[loopCounter] - splitTime[loopCounter]).c_str());
} else if (splitTime[loopCounter] == splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_WHITE, formatTimestampTimeSplit(splitTime[loopCounter] - splitPreviousBest[loopCounter]).c_str());
} else if (splitTime[loopCounter] > splitPreviousBest[loopCounter]) {
ImGui::TextColored(COLOR_RED, formatTimestampTimeSplit(splitTime[loopCounter] - splitPreviousBest[loopCounter]).c_str());
}
}
}
ImGui::TableNextColumn();
ImGui::Text("0:00:00.0");
// Previous Best
ImGui::Text(formatTimestampTimeSplit(splitPreviousBest[loopCounter]).c_str());
loopCounter++;
}
ImGui::EndTable();
@ -119,7 +150,9 @@ void DrawTimeSplitOptions() {
if (ImGui::Button("Add Item")) {
splitItem.push_back(itemReference);
splitTime.push_back("");
splitTime.push_back(0);
splitPreviousBest.push_back(0);
splitBest.push_back(100000);
splitStatus.push_back(0);
std::string itemEntry = SohUtils::itemNames[itemReference];
status = itemEntry + std::string(" Added to List");
@ -130,21 +163,127 @@ void DrawTimeSplitOptions() {
splitItem.clear();
splitTime.clear();
splitStatus.clear();
splitPreviousBest.clear();
status = "List has been reset";
statusColor = COLOR_RED;
}
ImGui::SameLine(0);
if (ImGui::Button("Save List")) {
json j;
j["splitItem"] = splitItem;
j["splitTime"] = splitTime;
j["splitPreviousBest"] = splitPreviousBest;
j["backgroundColor.r"] = colorChoice.x;
j["backgroundColor.g"] = colorChoice.y;
j["backgroundColor.b"] = colorChoice.z;
j["backgroundColor.a"] = colorChoice.w;
std::ofstream file("SplitofHarkinian.json");
file << j.dump(4);
file.close();
status = "List has been saved to disk";
statusColor = COLOR_LIGHT_BLUE;
}
ImGui::SameLine(0);
if (ImGui::Button("Load List")) {
std::ifstream file("SplitofHarkinian.json");
json j;
if (file.is_open()) {
file >> j;
file.close();
}
int itemSize = j["splitItem"].size();
splitItem.clear();
splitTime.clear();
splitPreviousBest.clear();
splitBest.clear();
splitStatus.clear();
for (int i = 0; i < itemSize; i++) {
splitItem.push_back(0);
splitTime.push_back(0);
splitPreviousBest.push_back(0);
splitBest.push_back(100000);
splitStatus.push_back(0);
}
splitItem = j["splitItem"].get<std::vector<uint32_t>>();
splitTime = j["splitTime"].get<std::vector<uint32_t>>();
splitPreviousBest = j["splitPreviousBest"].get<std::vector<uint32_t>>();
colorChoice.x = j["backgroundColor.r"];
colorChoice.y = j["backgroundColor.g"];
colorChoice.z = j["backgroundColor.b"];
colorChoice.w = j["backgroundColor.a"];
file.close();
status = "List has been loaded from Save Data";
statusColor = COLOR_LIGHT_BLUE;
}
if (ImGui::Button("New Attempt")) {
splitStatus.clear();
splitTime.clear();
for (int i = 0; i < splitItem.size(); i++) {
splitStatus.push_back(0);
splitTime.push_back(0);
}
splitCurNum++;
std::stringstream ss;
ss << splitCurNum;
splitAttempt = (splitNumDisp).c_str() + ss.str();
DrawTimeSplitSplits();
}
ImGui::SameLine();
if (ImGui::Button("Update Splits")) {
for (int i = 0; i < splitItem.size(); i++) {
if (splitPreviousBest[i] == 0) {
splitPreviousBest[i] = splitBest[i];
} else if (splitPreviousBest[i] > splitBest[i]) {
splitPreviousBest[i] = splitBest[i];
}
}
DrawTimeSplitSplits();
}
if (ImGui::ColorEdit4("Background Color", (float*)&colorChoice, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel)) {
Color_RGBA8 color;
color.r = colorChoice.x;
color.g = colorChoice.y;
color.b = colorChoice.z;
color.a = colorChoice.w;
}
ImGui::SameLine();
if (ImGui::Button("Reset")) {
colorChoice = { 0.0f, 0.0f, 0.0f, 1.0f };
}
ImGui::TextColored(statusColor, status.c_str());
UIWidgets::PaddedSeparator();
}
void InitializeSplitFile() {
if (!std::filesystem::exists("SplitofHarkinian.json")) {
json j;
j["splitItem"] = splitItem;
j["splitTime"] = splitTime;
j["splitPreviousBest"] = splitPreviousBest;
j["backgroundColor.r"] = colorChoice.x;
j["backgroundColor.g"] = colorChoice.y;
j["backgroundColor.b"] = colorChoice.z;
j["backgroundColor.a"] = colorChoice.w;
std::ofstream file("SplitofHarkinian.json");
file << j.dump(4);
file.close();
}
}
static bool initialized = false;
void TimeSplitWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(520, 600), ImGuiCond_FirstUseEver);
if (!initialized) {
InitializeSplitFile();
initialized = true;
}
ImGui::PushStyleColor(ImGuiCol_WindowBg, colorChoice);
if (!ImGui::Begin("Time Splitter Window", &mIsVisible, ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::End();
ImGui::PopStyleColor();
return;
}
if (ImGui::CollapsingHeader("Time Splitter")) {
@ -152,10 +291,11 @@ void TimeSplitWindow::DrawElement() {
}
DrawTimeSplitSplits();
ImGui::End();
ImGui::PopStyleColor();
}
void TimeSplitWindow::InitElement() {
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnItemReceive>([](GetItemEntry itemEntry) {
TimeSplitSplitsHandler(itemEntry);
TimeSplitSplitsHandler(itemEntry);
});
}

View File

@ -12,4 +12,34 @@ class TimeSplitWindow : public LUS::GuiWindow {
void UpdateElement() override{};
};
#endif
#endif
static const char* itemImage[156] {
"ITEM_STICK", "ITEM_NUT", "ITEM_BOMB", "ITEM_BOW", "ITEM_ARROW_FIRE", "ITEM_DINS_FIRE",
"ITEM_SLINGSHOT", "ITEM_OCARINA_FAIRY", "ITEM_OCARINA_TIME", "ITEM_BOMBCHU", "ITEM_HOOKSHOT", "ITEM_LONGSHOT",
"ITEM_ARROW_ICE", "ITEM_FARORES_WIND", "ITEM_BOOMERANG", "ITEM_LENS", "ITEM_BEAN", "ITEM_HAMMER",
"ITEM_ARROW_LIGHT", "ITEM_NAYRUS_LOVE", "ITEM_BOTTLE", "ITEM_POTION_RED", "ITEM_POTION_GREEN", "ITEM_POTION_BLUE",
"ITEM_FAIRY", "ITEM_FISH", "ITEM_MILK_BOTTLE", "ITEM_LETTER_RUTO", "ITEM_BLUE_FIRE", "ITEM_BUG",
"ITEM_BIG_POE", "ITEM_MILK_HALF", "ITEM_POE", "ITEM_WEIRD_EGG", "ITEM_CHICKEN", "ITEM_LETTER_ZELDA",
"ITEM_MASK_KEATON", "ITEM_MASK_SKULL", "ITEM_MASK_SPOOKY", "ITEM_MASK_BUNNY", "ITEM_MASK_GORON", "ITEM_MASK_ZORA",
"ITEM_MASK_GERUDO", "ITEM_MASK_TRUTH", "ITEM_SOLD_OUT", "ITEM_POCKET_EGG", "ITEM_POCKET_CUCCO", "ITEM_COJIRO",
"ITEM_ODD_MUSHROOM", "ITEM_ODD_POTION", "ITEM_SAW", "ITEM_SWORD_BROKEN", "ITEM_PRESCRIPTION", "ITEM_FROG",
"ITEM_EYEDROPS", "ITEM_CLAIM_CHECK", "ITEM_BOW_ARROW_FIRE", "ITEM_BOW_ARROW_ICE", "ITEM_BOW_ARROW_LIGHT", "ITEM_SWORD_KOKIRI",
"ITEM_SWORD_MASTER", "ITEM_SWORD_BGS", "ITEM_SHIELD_DEKU", "ITEM_SHIELD_HYLIAN", "ITEM_SHIELD_MIRROR", "ITEM_TUNIC_KOKIRI",
"ITEM_TUNIC_GORON", "ITEM_TUNIC_ZORA", "ITEM_BOOTS_KOKIRI", "ITEM_BOOTS_IRON", "ITEM_BOOTS_HOVER", "ITEM_BULLET_BAG_30",
"ITEM_BULLET_BAG_40", "ITEM_BULLET_BAG_50", "ITEM_QUIVER_30", "ITEM_QUIVER_40", "ITEM_QUIVER_50", "ITEM_BOMB_BAG_20",
"ITEM_BOMB_BAG_30", "ITEM_BOMB_BAG_40", "ITEM_BRACELET", "ITEM_GAUNTLETS_SILVER", "ITEM_GAUNTLETS_GOLD", "ITEM_SCALE_SILVER",
"ITEM_SCALE_GOLDEN", "ITEM_SWORD_KNIFE", "ITEM_WALLET_ADULT", "ITEM_WALLET_GIANT", "ITEM_SEEDS", "ITEM_FISHING_POLE",
"QUEST_SONG_MINUET", "QUEST_SONG_BOLERO", "QUEST_SONG_SERENADE", "QUEST_SONG_REQUIEM", "QUEST_SONG_NOCTURNE", "QUEST_SONG_PRELUDE",
"QUEST_SONG_LULLABY", "QUEST_SONG_EPONA", "QUEST_SONG_SARIA", "QUEST_SONG_SUN", "QUEST_SONG_TIME", "QUEST_SONG_STORMS",
"QUEST_MEDALLION_FOREST", "QUEST_MEDALLION_FIRE", "QUEST_MEDALLION_WATER", "QUEST_MEDALLION_SPIRIT", "QUEST_MEDALLION_SHADOW", "QUEST_MEDALLION_LIGHT",
"QUEST_KOKIRI_EMERALD", "QUEST_GORON_RUBY", "QUEST_ZORA_SAPPHIRE", "QUEST_STONE_OF_AGONY", "QUEST_GERUDO_CARD", "QUEST_SKULL_TOKEN",
"ITEM_HEART_CONTAINER", "ITEM_HEART_PIECE", "ITEM_KEY_BOSS", "ITEM_COMPASS", "ITEM_DUNGEON_MAP", "ITEM_KEY_SMALL",
"ITEM_MAGIC_SMALL", "ITEM_MAGIC_LARGE", "ITEM_HEART_PIECE_2", "ITEM_SINGLE_MAGIC", "ITEM_DOUBLE_MAGIC", "ITEM_DOUBLE_DEFENSE",
"ITEM_INVALID_4", "ITEM_INVALID_5", "ITEM_INVALID_6", "ITEM_INVALID_7", "ITEM_MILK", "ITEM_HEART",
"ITEM_RUPEE_GREEN", "ITEM_RUPEE_BLUE", "ITEM_RUPEE_RED", "ITEM_RUPEE_PURPLE", "ITEM_RUPEE_GOLD", "ITEM_INVALID_8",
"ITEM_STICKS_5", "ITEM_STICKS_10", "ITEM_NUTS_5", "ITEM_NUTS_10", "ITEM_BOMBS_5", "ITEM_BOMBS_10",
"ITEM_BOMBS_20", "ITEM_BOMBS_30", "ITEM_ARROWS_SMALL", "ITEM_ARROWS_MEDIUM", "ITEM_ARROWS_LARGE", "ITEM_SEEDS_30",
"ITEM_BOMBCHUS_5", "ITEM_BOMBCHUS_20", "ITEM_STICK_UPGRADE_20", "ITEM_STICK_UPGRADE_30", "ITEM_NUT_UPGRADE_30", "ITEM_NUT_UPGRADE_40"
};