Item tracker (#707)
Some checks failed
generate-builds / generate-2ship-otr (push) Has been cancelled
generate-builds / build-macos (push) Has been cancelled
generate-builds / build-linux (push) Has been cancelled
generate-builds / build-windows (push) Has been cancelled

* Core tracker code mostly done.

* Format

* Clean up enums.

* Format

* Header cleanup

* Update

* use CVars

* format

* Add editor to modern menu

* format

* Fix item tracker cvar loading/saving and add item tracker button for modern menu

* update button label

---------

Co-authored-by: Archez <archez39@me.com>
This commit is contained in:
louist103 2024-11-08 11:51:58 -05:00 committed by GitHub
parent d1bbba626d
commit be70a5a123
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 717 additions and 1 deletions

View File

@ -21,6 +21,9 @@
#include "include/global.h"
#include "include/z64audio.h"
#include "Enhancements/Trackers/ItemTracker.h"
#include "Enhancements/Trackers/ItemTrackerSettings.h"
namespace BenGui {
// MARK: - Delegates
@ -38,6 +41,8 @@ std::shared_ptr<EventLogWindow> mEventLogWindow;
std::shared_ptr<BenMenu> mBenMenu;
std::shared_ptr<BenInputEditorWindow> mBenInputEditorWindow;
std::shared_ptr<Notification::Window> mNotificationWindow;
std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
void SetupGuiElements() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
@ -94,6 +99,13 @@ void SetupGuiElements() {
mEventLogWindow = std::make_shared<EventLogWindow>("gWindows.EventLog", "Event Log", ImVec2(520, 600));
gui->AddGuiWindow(mEventLogWindow);
mItemTrackerWindow = std::make_shared<ItemTrackerWindow>("gWindows.ItemTracker", "Item Tracker");
gui->AddGuiWindow(mItemTrackerWindow);
mItemTrackerSettingsWindow = std::make_shared<ItemTrackerSettingsWindow>("gWindows.ItemTrackerSettings",
"Item Tracker Settings", ImVec2(800, 400));
gui->AddGuiWindow(mItemTrackerSettingsWindow);
gui->SetPadBtnTogglesMenu();
mNotificationWindow = std::make_shared<Notification::Window>("gWindows.Notifications", "Notifications Window");
@ -102,6 +114,9 @@ void SetupGuiElements() {
}
void Destroy() {
auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui();
gui->RemoveAllGuiWindows();
mBenMenuBar = nullptr;
mBenMenu = nullptr;
mStatsWindow = nullptr;
@ -111,9 +126,10 @@ void Destroy() {
mCollisionViewerWindow = nullptr;
mEventLogWindow = nullptr;
mNotificationWindow = nullptr;
mSaveEditorWindow = nullptr;
mHudEditorWindow = nullptr;
mActorViewerWindow = nullptr;
mItemTrackerWindow = nullptr;
mItemTrackerSettingsWindow = nullptr;
}
} // namespace BenGui

View File

@ -12,6 +12,9 @@
#include "2s2h/DeveloperTools/DeveloperTools.h"
#include "HudEditor.h"
#include "2s2h/Enhancements/Trackers/ItemTracker.h"
#include "2s2h/Enhancements/Trackers/ItemTrackerSettings.h"
extern "C" {
#include "z64.h"
#include "functions.h"
@ -345,6 +348,8 @@ void DrawSettingsMenu() {
}
extern std::shared_ptr<HudEditorWindow> mHudEditorWindow;
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
extern std::shared_ptr<ItemTrackerSettingsWindow> mItemTrackerSettingsWindow;
void DrawEnhancementsMenu() {
if (UIWidgets::BeginMenu("Enhancements")) {
@ -799,6 +804,15 @@ void DrawEnhancementsMenu() {
{ .tooltip = "Enables the Hud Editor window, allowing you to edit your hud" });
}
if (mItemTrackerWindow) {
UIWidgets::WindowButton("Item Tracker", "gWindows.ItemTracker", mItemTrackerWindow);
}
if (mItemTrackerSettingsWindow) {
UIWidgets::WindowButton("Item Tracker Settings", "gWindows.ItemTrackerSettings",
mItemTrackerSettingsWindow);
}
ImGui::EndMenu();
}
}

View File

@ -1424,6 +1424,15 @@ void AddEnhancements() {
"Enables the HUD Editor window, allowing you to modify your HUD",
WIDGET_WINDOW_BUTTON,
{ .size = UIWidgets::Sizes::Inline, .windowName = "HUD Editor" } } } } });
enhancementsSidebar.push_back(
{ "Item Tracker",
1,
{ // Item Tracker Settings
{ { "Popout Item Tracker Settings",
"gWindows.ItemTrackerSettings",
"",
WIDGET_WINDOW_BUTTON,
{ .size = UIWidgets::Sizes::Inline, .windowName = "Item Tracker Settings" } } } } });
}
void AddDevTools() {

View File

@ -0,0 +1,506 @@
#include "ItemTracker.h"
#include "Context.h"
#include "config/Config.h"
#include "assets/archives/icon_item_static/icon_item_static_yar.h"
#include "assets/archives/icon_item_24_static/icon_item_24_static_yar.h"
#define CFG_TRACKER_ITEM(var) ("ItemTracker." var)
using namespace Ship;
ItemTrackerWindow::~ItemTrackerWindow() {
auto config = Context::GetInstance()->GetConsoleVariables();
config->SetFloat(CFG_TRACKER_ITEM("BgColorR"), mBgColor.x);
config->SetFloat(CFG_TRACKER_ITEM("BgColorG"), mBgColor.y);
config->SetFloat(CFG_TRACKER_ITEM("BgColorB"), mBgColor.z);
config->SetFloat(CFG_TRACKER_ITEM("BgColorA"), mBgColor.w);
config->SetFloat(CFG_TRACKER_ITEM("IconSize"), mIconSize);
config->SetFloat(CFG_TRACKER_ITEM("IconSpacing"), mIconSpacing);
config->SetFloat(CFG_TRACKER_ITEM("TextSize"), mTextSize);
config->SetFloat(CFG_TRACKER_ITEM("TextOffset"), mTextOffset);
config->SetInteger(CFG_TRACKER_ITEM("WindowType"), (int8_t)mWindowType);
config->SetInteger(CFG_TRACKER_ITEM("IsDraggable"), mIsDraggable);
config->SetInteger(CFG_TRACKER_ITEM("OnlyDrawPaused"), mOnlyDrawPaused);
config->SetInteger(CFG_TRACKER_ITEM("DrawCurrentAmmo"), mCapacityModes[ItemTrackerCapacityMode::DrawCurrent]);
config->SetInteger(CFG_TRACKER_ITEM("DrawMaxAmmo"), mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity]);
config->SetInteger(CFG_TRACKER_ITEM("DrawMaxCapacity"), mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]);
config->SetInteger(CFG_TRACKER_ITEM("InventoryDrawMode"), (int8_t)mItemDrawModes[SECTION_INVENTORY]);
config->SetInteger(CFG_TRACKER_ITEM("MasksDrawMode"), (int8_t)mItemDrawModes[SECTION_MASKS]);
config->SetInteger(CFG_TRACKER_ITEM("SongsDrawMode"), (int8_t)mItemDrawModes[SECTION_SONGS]);
config->SetInteger(CFG_TRACKER_ITEM("DungeonDrawMode"), (int8_t)mItemDrawModes[SECTION_DUNGEON]);
config->Save();
}
void ItemTrackerWindow::LoadSettings() {
auto config = Context::GetInstance()->GetConsoleVariables();
mCapacityModes.fill(false);
mBgColor.x = config->GetFloat(CFG_TRACKER_ITEM("BgColorR"), 0.0f);
mBgColor.y = config->GetFloat(CFG_TRACKER_ITEM("BgColorG"), 0.0f);
mBgColor.z = config->GetFloat(CFG_TRACKER_ITEM("BgColorB"), 0.0f);
mBgColor.w = config->GetFloat(CFG_TRACKER_ITEM("BgColorA"), 0.0f);
mIconSize = config->GetFloat(CFG_TRACKER_ITEM("IconSize"), 13.0f);
mIconSpacing = config->GetFloat(CFG_TRACKER_ITEM("IconSpacing"), 12.0f);
mTextSize = config->GetFloat(CFG_TRACKER_ITEM("TextSize"), 13.0f);
mTextOffset = config->GetFloat(CFG_TRACKER_ITEM("TextOffset"), 0.0f);
mWindowType =
(TrackerWindowType)config->GetInteger(CFG_TRACKER_ITEM("WindowType"), (int8_t)TrackerWindowType::Floating);
mIsDraggable = config->GetInteger(CFG_TRACKER_ITEM("IsDraggable"), false);
mOnlyDrawPaused = config->GetInteger(CFG_TRACKER_ITEM("OnlyDrawPaused"), false);
mCapacityModes[ItemTrackerCapacityMode::DrawCurrent] =
config->GetInteger(CFG_TRACKER_ITEM("DrawCurrentAmmo"), false);
mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity] =
config->GetInteger(CFG_TRACKER_ITEM("DrawMaxAmmo"), false);
mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity] =
config->GetInteger(CFG_TRACKER_ITEM("DrawMaxCapacity"), false);
mItemDrawModes[SECTION_INVENTORY] = (ItemTrackerDisplayType)config->GetInteger(
CFG_TRACKER_ITEM("InventoryDrawMode"), (int32_t)ItemTrackerDisplayType::Hidden);
mItemDrawModes[SECTION_MASKS] = (ItemTrackerDisplayType)config->GetInteger(CFG_TRACKER_ITEM("MasksDrawMode"),
(int32_t)ItemTrackerDisplayType::Hidden);
mItemDrawModes[SECTION_SONGS] = (ItemTrackerDisplayType)config->GetInteger(CFG_TRACKER_ITEM("SongsDrawMode"),
(int32_t)ItemTrackerDisplayType::Hidden);
mItemDrawModes[SECTION_DUNGEON] = (ItemTrackerDisplayType)config->GetInteger(
CFG_TRACKER_ITEM("DungeonDrawMode"), (int32_t)ItemTrackerDisplayType::Hidden);
}
void ItemTrackerWindow::BeginFloatingWindows(const char* name, ImGuiWindowFlags flags) {
ImGuiWindowFlags windowFlags = flags;
if (windowFlags == 0) {
windowFlags |=
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize;
}
if (mWindowType == TrackerWindowType::Floating) {
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
windowFlags |= ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoTitleBar |
ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar;
if (!mIsDraggable) {
windowFlags |= ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove;
}
}
ImGui::PushStyleColor(ImGuiCol_WindowBg, mBgColor);
ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0, 0, 0, 0));
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 4.0f);
ImGui::Begin(name, nullptr, windowFlags);
}
void EndFloatingWindows() {
ImGui::PopStyleVar();
ImGui::PopStyleColor();
ImGui::PopStyleColor();
ImGui::End();
}
static constexpr ImVec4 opaqueTex = { 1.0f, 1.0f, 1.0f, 1.0f };
static constexpr ImVec4 fadedTex = { 0.5f, 0.5f, 0.5f, 0.5f };
void DrawItem(char* tex, bool drawFaded, float itemSize) {
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(tex), ImVec2(itemSize, itemSize),
ImVec2(0, 0), ImVec2(1, 1), drawFaded ? fadedTex : opaqueTex);
}
static constexpr std::array<ImVec4, 5> songInfo = {
ImVec4(0.588f, 1.0f, 0.392f, 1.0f), // QUEST_SONG_SONATA
ImVec4(1.0f, 0.313f, 0.156f, 1.0f), // QUEST_SONG_LULLABY
ImVec4(0.392f, 0.588f, 1.0f, 1.0f), // QUEST_SONG_BOSSA_NOVA
ImVec4(1.0f, 0.627f, 0.0f, 1.0f), // QUEST_SONG_ELEGY
ImVec4(1.0f, 0.392f, 1.0f, 1.0f), // QUEST_SONG_OATH
};
void ItemTrackerWindow::DrawNote(size_t songIndex, bool drawFaded) {
ImVec4 color;
// Scale the note to 24*36 from 16*24 because all other items assume 36*36.
constexpr float noteTo36scale = 36.0f / 24.0f;
const float iconScale = mIconSize / 36.0f;
// Scale the note icon with the rest of the items.
const ImVec2 scaledNoteSize(noteTo36scale * 16.0f * iconScale, noteTo36scale * 24.0f * iconScale);
if (songIndex >= 5) {
color = songInfo[songIndex - 5];
} else {
color = { 1.0f, 1.0f, 1.0f, 1.0f };
}
if (drawFaded) {
color.w = .5f;
}
ImGui::Image(Ship::Context::GetInstance()->GetWindow()->GetGui()->GetTextureByName(gItemIconSongNoteTex),
scaledNoteSize, ImVec2(0, 0), ImVec2(1, 1), color);
}
extern "C" {
#include "z64save.h"
#include "macros.h"
#include "z64.h"
extern void* gItemIcons[131];
extern uint8_t gItemSlots[77];
extern SaveContext gSaveContext;
extern u32 gBitFlags[32];
extern PlayState* gPlayState;
extern u16 gUpgradeCapacities[][4];
extern u32 gUpgradeMasks[];
extern u8 gUpgradeShifts[];
}
// The textures in gItemIcons aren't in the same order as the subscreen
static constexpr std::array<const char*, 24> sMaskTextures = {
gItemIconPostmansHatTex, gItemIconAllNightMaskTex, gItemIconBlastMaskTex, gItemIconStoneMaskTex,
gItemIconGreatFairyMaskTex, gItemIconDekuMaskTex, gItemIconKeatonMaskTex, gItemIconBremenMaskTex,
gItemIconBunnyHoodTex, gItemIconDonGeroMaskTex, gItemIconMaskOfScentsTex, gItemIconGoronMaskTex,
gItemIconRomaniMaskTex, gItemIconCircusLeaderMaskTex, gItemIconKafeisMaskTex, gItemIconCouplesMaskTex,
gItemIconMaskOfTruthTex, gItemIconZoraMaskTex, gItemIconKamaroMaskTex, gItemIconGibdoMaskTex,
gItemIconGaroMaskTex, gItemIconCaptainsHatTex, gItemIconGiantsMaskTex, gItemIconFierceDeityMaskTex,
};
// The songs in the enum are in the wrong order and has the unused songs
static constexpr std::array<uint8_t, 10> sSongBits = {
QUEST_SONG_TIME, QUEST_SONG_HEALING, QUEST_SONG_EPONA, QUEST_SONG_SOARING, QUEST_SONG_STORMS,
QUEST_SONG_SONATA, QUEST_SONG_LULLABY, QUEST_SONG_BOSSA_NOVA, QUEST_SONG_ELEGY, QUEST_SONG_OATH,
};
bool ItemTrackerWindow::HasAmmoCount(int itemId) {
switch (itemId) {
case ITEM_BOW:
case ITEM_BOMB:
case ITEM_BOMBCHU:
case ITEM_DEKU_STICK:
case ITEM_DEKU_NUT:
return true;
default:
return false;
}
}
ItemTrackerWindow::AmmoInfo ItemTrackerWindow::GetAmmoInfo(int itemId) {
AmmoInfo info;
switch (itemId) {
case ITEM_BOW:
info = { .cur = (uint8_t)AMMO(ITEM_BOW), .curCap = (uint8_t)CUR_CAPACITY(UPG_QUIVER), .maxCap = 50 };
break;
case ITEM_BOMB:
info = { .cur = (uint8_t)AMMO(ITEM_BOMB), .curCap = (uint8_t)CUR_CAPACITY(UPG_BOMB_BAG), .maxCap = 40 };
break;
case ITEM_BOMBCHU:
info = { .cur = (uint8_t)AMMO(ITEM_BOMBCHU), .curCap = (uint8_t)CUR_CAPACITY(UPG_BOMB_BAG), .maxCap = 40 };
break;
case ITEM_DEKU_STICK:
info = { .cur = (uint8_t)AMMO(ITEM_DEKU_STICK),
.curCap = (uint8_t)CUR_CAPACITY(UPG_DEKU_STICKS),
.maxCap = 30 };
break;
case ITEM_DEKU_NUT:
info = { .cur = (uint8_t)AMMO(ITEM_DEKU_NUT),
.curCap = (uint8_t)CUR_CAPACITY(UPG_DEKU_NUTS),
.maxCap = 40 };
break;
default:
info = { 0 };
}
return info;
}
void ItemTrackerWindow::DrawAmmoCount(int itemId, const ImVec2& iconPos) {
// Zeroing 16 bytes is a little more optimized than 10
char ammoStr[16] = { 0 };
char curStr[4] = { 0 };
char curCapStr[4] = { 0 };
char maxCapStr[4] = { 0 };
AmmoInfo info;
if (!HasAmmoCount(itemId)) {
return;
}
info = GetAmmoInfo(itemId);
if (mCapacityModes[ItemTrackerCapacityMode::DrawCurrent]) {
snprintf(curStr, std::size(curStr), "%d", info.cur);
if (mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity] ||
mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) {
strncat(curStr, "/", 1);
}
}
if (mCapacityModes[ItemTrackerCapacityMode::DrawCurCapacity]) {
snprintf(curCapStr, std::size(curStr), "%d", info.curCap);
if (mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) {
strncat(curCapStr, "/", 1);
}
}
if (mCapacityModes[ItemTrackerCapacityMode::DrawMaxCapacity]) {
snprintf(maxCapStr, std::size(curStr), "%d", info.maxCap);
}
ImGui::SetWindowFontScale(mTextSize / 13.0f);
ImVec2 iconPos2 = ImGui::GetCursorScreenPos();
snprintf(ammoStr, std::size(ammoStr), "%s%s%s", curStr, curCapStr, maxCapStr);
float x = iconPos2.x + (mIconSize / 2.0f) - (ImGui::CalcTextSize(ammoStr).x / 2.0f);
// Normalize the offset based on the icon being 36x36 to account for larger icons.
ImGui::SetCursorScreenPos({ x, iconPos2.y - (mTextOffset / 36.0f) * mIconSize });
ImGui::Text("%s", ammoStr);
}
int ItemTrackerWindow::DrawItems(int columns, int prevDrawnColumns) {
int topPadding = 0;
size_t i = 0;
// Draw items minus bottles
for (; i < 24 - BOTTLE_MAX; i++) {
bool drawFaded = false;
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
char* texToDraw;
const ImVec2 pos = { (column * (mIconSize + mIconSpacing) + 8.0f),
(row * (mIconSize + mIconSpacing)) + 8.0f + topPadding };
ImGui::SetCursorPos(pos);
if (gSaveContext.save.saveInfo.inventory.items[i] == ITEM_NONE) {
if (column == 5) {
// BENTODO these slots can hold multiple items. Something fun to do would be to draw the multitile
// design here instead of nothing DrawMultiItem(nullptr, false, row, column);
continue;
}
texToDraw = (char*)gItemIcons[i];
drawFaded = true;
} else {
texToDraw = (char*)gItemIcons[gSaveContext.save.saveInfo.inventory.items[i]];
}
ImGui::BeginGroup();
DrawItem(texToDraw, drawFaded, mIconSize);
DrawAmmoCount((int)i, pos);
ImGui::EndGroup();
}
// DrawBottles
for (; i < 24; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f),
(row * (mIconSize + mIconSpacing)) + 8.0f + topPadding));
if (gSaveContext.save.saveInfo.inventory.items[i] == ITEM_NONE) {
DrawItem(const_cast<char*>(gItemIconEmptyBottleTex), true, mIconSize);
} else {
DrawItem((char*)gItemIcons[gSaveContext.save.saveInfo.inventory.items[i]], false, mIconSize);
}
}
return 4;
}
int ItemTrackerWindow::DrawMasks(int columns, int prevDrawnColumns) {
int topPadding = 0;
// Masks
for (size_t i = 0; i < 24; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f),
(row * (mIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawItem(const_cast<char*>(sMaskTextures[i]), gSaveContext.save.saveInfo.inventory.items[i + 24] == ITEM_NONE,
mIconSize);
}
return 4;
}
static int RoundDown(int orig, int nearest) {
int res = orig % nearest;
return orig - res;
}
int ItemTrackerWindow::DrawSongs(int columns, int prevDrawnColumns) {
int topPadding = 0;
for (size_t i = 0; i < sSongBits.size(); i++) {
int row = prevDrawnColumns + (i / 5);
int column = i % 5;
ImGui::SetCursorPos(ImVec2((column * (mIconSize + mIconSpacing) + 8.0f),
(row * (mIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawNote(i, !CHECK_QUEST_ITEM(sSongBits[i]));
}
return 2;
}
int ItemTrackerWindow::DrawDungeonItemsVert(int columns, int prevDrawnColumns) {
int topPadding = 0;
// The icon size is based on 36x36.
float iconScale = mIconSize / 36.0f;
// Yes this does nothing. But for other icon sizes it will.
float squareIconSize = iconScale * 36.0f;
float rectIconSize = iconScale * 36.0f;
for (size_t i = 0; i < 4; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (squareIconSize + mIconSpacing) + 8.0f),
(row * (squareIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawItem(static_cast<char*>(gItemIcons[i + ITEM_REMAINS_ODOLWA]), !CHECK_QUEST_ITEM(i), squareIconSize);
}
prevDrawnColumns++;
for (size_t i = 0; i < 4; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f),
(row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawItem(const_cast<char*>(gQuestIconBossKeyTex), !CHECK_DUNGEON_ITEM(DUNGEON_BOSS_KEY, i), rectIconSize);
}
prevDrawnColumns++;
for (size_t i = 0; i < 4; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f),
(row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawItem(const_cast<char*>(gQuestIconCompassTex), !CHECK_DUNGEON_ITEM(DUNGEON_COMPASS, i), rectIconSize);
}
prevDrawnColumns++;
for (size_t i = 0; i < 4; i++) {
int row = prevDrawnColumns + (i / columns);
int column = i % columns;
ImGui::SetCursorPos(ImVec2((column * (rectIconSize + mIconSpacing) + 8.0f),
(row * (rectIconSize + mIconSpacing)) + 8.0f + topPadding));
DrawItem(const_cast<char*>(gQuestIconDungeonMapTex), !CHECK_DUNGEON_ITEM(DUNGEON_MAP, i), rectIconSize);
}
return 4;
}
void ItemTrackerWindow::DrawItemsInRows(int columns) {
float iconSize = mIconSize;
float iconSpacing = mIconSpacing;
int topPadding = 0;
int mainWindowPos = 0;
int advancedBy = 0;
if (gPlayState == nullptr) {
ImGui::Text("Item tracker not available");
return;
}
if (mOnlyDrawPaused && gPlayState->pauseCtx.state == 0) {
return;
}
if (mItemDrawModes[SECTION_INVENTORY] != ItemTrackerDisplayType::Hidden) {
if (mItemDrawModes[SECTION_INVENTORY] == ItemTrackerDisplayType::Seperate) {
BeginFloatingWindows("Items");
}
advancedBy = DrawItems(6, mainWindowPos);
if (mItemDrawModes[SECTION_INVENTORY] == ItemTrackerDisplayType::Seperate) {
EndFloatingWindows();
} else {
mainWindowPos += advancedBy;
}
}
if (mItemDrawModes[SECTION_MASKS] != ItemTrackerDisplayType::Hidden) {
int drawPos = mainWindowPos;
if (mItemDrawModes[SECTION_MASKS] == ItemTrackerDisplayType::Seperate) {
drawPos = 0;
BeginFloatingWindows("Masks");
}
advancedBy = DrawMasks(6, drawPos);
if (mItemDrawModes[SECTION_MASKS] == ItemTrackerDisplayType::Seperate) {
EndFloatingWindows();
} else {
mainWindowPos += advancedBy;
}
}
if (mItemDrawModes[SECTION_SONGS] != ItemTrackerDisplayType::Hidden) {
int drawPos = mainWindowPos;
if (mItemDrawModes[SECTION_SONGS] == ItemTrackerDisplayType::Seperate) {
drawPos = 0;
BeginFloatingWindows("Songs");
}
advancedBy = DrawSongs(5, drawPos);
if (mItemDrawModes[SECTION_SONGS] == ItemTrackerDisplayType::Seperate) {
EndFloatingWindows();
} else {
mainWindowPos += advancedBy;
}
}
if (mItemDrawModes[SECTION_DUNGEON] != ItemTrackerDisplayType::Hidden) {
int drawPos = mainWindowPos;
if (mItemDrawModes[SECTION_DUNGEON] == ItemTrackerDisplayType::Seperate) {
drawPos = 0;
BeginFloatingWindows("Dungeon Items");
}
advancedBy = DrawDungeonItemsVert(6, drawPos);
if (mItemDrawModes[SECTION_DUNGEON] == ItemTrackerDisplayType::Seperate) {
EndFloatingWindows();
} else {
mainWindowPos += advancedBy;
}
}
}
ImVec4* ItemTrackerWindow::GetBgColorPtr() {
return &mBgColor;
}
float* ItemTrackerWindow::GetIconSizePtr() {
return &mIconSize;
}
float* ItemTrackerWindow::GetIconSpacingPtr() {
return &mIconSpacing;
}
float* ItemTrackerWindow::GetTextSizePtr() {
return &mTextSize;
}
float* ItemTrackerWindow::GetTextOffsetPtr() {
return &mTextOffset;
}
TrackerWindowType* ItemTrackerWindow::GetWindowTypePtr() {
return &mWindowType;
}
bool* ItemTrackerWindow::GetIsDraggablePtr() {
return &mIsDraggable;
}
bool* ItemTrackerWindow::GetOnlyShowPausedPtr() {
return &mOnlyDrawPaused;
}
ItemTrackerDisplayType* ItemTrackerWindow::GetDrawModePtr(ItemTrackerSection type) {
return &mItemDrawModes[type];
}
bool* ItemTrackerWindow::GetCapacityModePtr(ItemTrackerCapacityMode mode) {
return &mCapacityModes[mode];
}
void ItemTrackerWindow::Draw() {
if (!IsVisible()) {
return;
}
BeginFloatingWindows("Inventory Items Tracker");
DrawItemsInRows();
EndFloatingWindows();
}
void ItemTrackerWindow::InitElement() {
LoadSettings();
}
void ItemTrackerWindow::DrawElement() {
}

View File

@ -0,0 +1,82 @@
#include "window/gui/Gui.h"
#include "window/gui/GuiWindow.h"
#include <array>
typedef enum class TrackerWindowType : uint8_t {
Floating,
Window,
} TrackerWindowType;
typedef enum class ItemTrackerDisplayType : int8_t {
Hidden,
MainWindow,
Seperate,
} ItemTrackerDisplayType;
typedef enum {
SECTION_INVENTORY,
SECTION_MASKS,
SECTION_SONGS,
SECTION_DUNGEON,
SECTION_MAX,
} ItemTrackerSection;
typedef enum {
DrawCurrent,
DrawCurCapacity,
DrawMaxCapacity,
DrawCapacityMax,
} ItemTrackerCapacityMode;
class ItemTrackerWindow : public Ship::GuiWindow {
typedef struct AmmoInfo {
uint8_t cur;
uint8_t curCap;
uint8_t maxCap;
} AmmoInfo;
public:
using GuiWindow::GuiWindow;
~ItemTrackerWindow();
void Draw() override;
ImVec4* GetBgColorPtr();
float* GetIconSizePtr();
float* GetIconSpacingPtr();
float* GetTextSizePtr();
float* GetTextOffsetPtr();
TrackerWindowType* GetWindowTypePtr();
bool* GetIsDraggablePtr();
bool* GetOnlyShowPausedPtr();
ItemTrackerDisplayType* GetDrawModePtr(ItemTrackerSection type);
bool* GetCapacityModePtr(ItemTrackerCapacityMode mode);
void LoadSettings();
protected:
void InitElement() override;
void DrawElement() override;
void UpdateElement() override{};
private:
void BeginFloatingWindows(const char* name, ImGuiWindowFlags flags = 0);
void DrawItemsInRows(int columns = 6);
int DrawItems(int columns, int startAt);
int DrawMasks(int columns, int startAt);
int DrawSongs(int columns, int startAt);
void DrawNote(size_t songIndex, bool drawFaded);
int DrawDungeonItemsVert(int columns, int startAt);
void DrawAmmoCount(int itemId, const ImVec2& iconPos);
bool HasAmmoCount(int itemId);
AmmoInfo GetAmmoInfo(int itemId);
ImVec4 mBgColor;
float mIconSize = 36.0f;
float mIconSpacing = 12.0f;
float mTextSize = 13.0f;
float mTextOffset = 0.0f;
TrackerWindowType mWindowType = TrackerWindowType::Floating;
bool mIsDraggable = false;
bool mOnlyDrawPaused = false;
std::array<bool, DrawCapacityMax> mCapacityModes;
std::array<ItemTrackerDisplayType, SECTION_MAX> mItemDrawModes;
};

View File

@ -0,0 +1,77 @@
#include "ItemTrackerSettings.h"
#include "ItemTracker.h"
#include "../../BenGui/UIWidgets.hpp"
namespace BenGui {
extern std::shared_ptr<ItemTrackerWindow> mItemTrackerWindow;
}
using namespace BenGui;
void ItemTrackerSettingsWindow::UpdateElement() {
}
void ItemTrackerSettingsWindow::InitElement() {
}
static const char* windowTypes[2] = { "Floating", "Window" };
static const char* displayTypes[3] = { "Hidden", "Main Window", "Separate" };
static const char* displayModes[2] = { "Always", "Combo Button Hold" };
void ItemTrackerSettingsWindow::DrawElement() {
ImGui::SetNextWindowSize(ImVec2(733, 472), ImGuiCond_FirstUseEver);
const UIWidgets::FloatSliderOptions sliderOpts = { .format = "%.0f", .step = 1.0f };
if (!ImGui::BeginChild("Item Tracker Settings")) {
ImGui::EndChild();
return;
}
UIWidgets::WindowButton("Show/Hide Item Tracker", "gWindows.ItemTracker", mItemTrackerWindow,
{ .size = UIWidgets::Sizes::Inline });
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, { 8.0f, 8.0f });
ImGui::BeginTable("itemTrackerSettingsTable", 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::Text("BG Color");
ImGui::SameLine();
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
ImGui::ColorEdit4("BG Color", (float*)mItemTrackerWindow->GetBgColorPtr(),
ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_NoLabel);
UIWidgets::Combobox("Window Type", mItemTrackerWindow->GetWindowTypePtr(), windowTypes);
UIWidgets::Checkbox("Enable Dragging", mItemTrackerWindow->GetIsDraggablePtr());
UIWidgets::Checkbox("Only enable while paused", mItemTrackerWindow->GetOnlyShowPausedPtr());
UIWidgets::SliderFloat("Icon size : %.0fpx", mItemTrackerWindow->GetIconSizePtr(), 0.0f, 128.0f, sliderOpts);
UIWidgets::SliderFloat("Icon margins : %.0fpx", mItemTrackerWindow->GetIconSpacingPtr(), -5.0f, 50.0f, sliderOpts);
UIWidgets::SliderFloat("Text size : %.0fpx", mItemTrackerWindow->GetTextSizePtr(), 1.0f, 30.0f, sliderOpts);
UIWidgets::SliderFloat("Text Offset : %0.fpx", mItemTrackerWindow->GetTextOffsetPtr(), 0.0f, 40.0f, sliderOpts);
ImGui::TableNextColumn();
UIWidgets::Combobox("Inventory", mItemTrackerWindow->GetDrawModePtr(SECTION_INVENTORY), displayTypes);
UIWidgets::Combobox("Masks", mItemTrackerWindow->GetDrawModePtr(SECTION_MASKS), displayTypes);
UIWidgets::Combobox("Songs", mItemTrackerWindow->GetDrawModePtr(SECTION_SONGS), displayTypes);
UIWidgets::Combobox("Dungeon Items", mItemTrackerWindow->GetDrawModePtr(SECTION_DUNGEON), displayTypes);
UIWidgets::Checkbox("Draw Current Ammo",
mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawCurrent));
UIWidgets::Checkbox("Draw Current Capacity",
mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawCurCapacity));
UIWidgets::Checkbox("Draw Max Capacity",
mItemTrackerWindow->GetCapacityModePtr(ItemTrackerCapacityMode::DrawMaxCapacity));
ImGui::PopStyleVar(1);
ImGui::EndTable();
ImGui::EndChild();
}

View File

@ -0,0 +1,12 @@
#include "window/gui/Gui.h"
#include "window/gui/GuiWindow.h"
class ItemTrackerSettingsWindow : public Ship::GuiWindow {
public:
using GuiWindow::GuiWindow;
protected:
void InitElement() override;
void DrawElement() override;
void UpdateElement() override;
};