Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 33 additions & 4 deletions source/D2Debugger/src/D2Debugger.Game.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <imgui.h>
#include <cstdio>
#include <vector>
#include "D2Debugger.h"
#include <GAME/Game.h>
Expand Down Expand Up @@ -34,8 +35,11 @@ D2FUNC(D2Game, SpawnMonster_6FC69F10, D2UnitStrc*, __fastcall, (D2GameStrc* pGam
std::vector<char> GetUTF8CharBufferFromStringIndex(uint16_t index)
{
const Unicode* nameUnicode = (const Unicode*)D2LANG_GetStringFromTblIndex(index);
std::vector<char> utf8CharBuffer(Unicode::strlen(nameUnicode) * 3, 0);
Unicode::toUtf(utf8CharBuffer.data(), nameUnicode, utf8CharBuffer.size() - 2 /*See toUtf doc*/);
// toUtf can write a 3-byte character when only (count - 1) bytes are left, plus the terminator,
// so it needs 2 bytes past count (see toUtf doc). The 3 extra bytes keep the last character of
// a full-width string, and keep the buffer non-empty for an empty string.
std::vector<char> utf8CharBuffer(Unicode::strlen(nameUnicode) * 3 + 3, 0);
Unicode::toUtf(utf8CharBuffer.data(), nameUnicode, utf8CharBuffer.size() - 2);
return utf8CharBuffer;
}

Expand Down Expand Up @@ -240,12 +244,22 @@ const std::vector<char>& GetNOTFOUNDCharBuffer()
return notFoundBuffer;
}

// Several records can share a display name (e.g. many monsters are "Fallen"), so labels carry the id too.
template<typename NAMEGETTER>
std::vector<char> GetIdAndName(int id, NAMEGETTER&& NameGetter)
{
const std::vector<char> name = NameGetter(id);
std::vector<char> label(name.size() + 16, 0);
std::snprintf(label.data(), label.size(), "%d: %s", id, name.data());
return label;
}

template<typename NAMEGETTER>
void D2ComboBox(const char* Title, int& selectedID, size_t count,NAMEGETTER&& NameGetter)
{

static bool bWasComboOpen = false;
if (ImGui::BeginCombo(Title, NameGetter(selectedID).data()))
if (ImGui::BeginCombo(Title, GetIdAndName(selectedID, NameGetter).data()))
{
ImGuiListClipper clipper;
clipper.Begin(count);
Expand All @@ -261,7 +275,7 @@ void D2ComboBox(const char* Title, int& selectedID, size_t count,NAMEGETTER&& Na
for (int id = clipper.DisplayStart; id < clipper.DisplayEnd; id++)
{
const bool bSelected = selectedID == id;
if (ImGui::Selectable(NameGetter(id).data(), bSelected))
if (ImGui::Selectable(GetIdAndName(id, NameGetter).data(), bSelected))
selectedID = id;
if (bSelected)
ImGui::SetItemDefaultFocus();
Expand All @@ -276,6 +290,18 @@ void D2ComboBox(const char* Title, int& selectedID, size_t count,NAMEGETTER&& Na
}
}

// Lets the user type a record id instead of scrolling the combo box to it.
void D2IdInput(const char* Label, int& selectedID, size_t count)
{
if (ImGui::InputInt(Label, &selectedID) && count > 0)
{
if (selectedID < 0)
selectedID = 0;
else if (size_t(selectedID) >= count)
selectedID = int(count - 1);
}
}

void D2DebugUnitSpawner(D2GameStrc* pGame)
{
#ifdef HAS_SPAWN_FUNCTIONS
Expand Down Expand Up @@ -312,6 +338,8 @@ void D2DebugUnitSpawner(D2GameStrc* pGame)
}
}

D2IdInput("SuperUnique id", currentSuperUniqueSelectionId, DATATBLS_GetSuperUniquesTxtRecordCount());

static int currentNormalSelectionId = 0;
auto GetNormalMonsterUTF8Name = [](int id)
{
Expand All @@ -337,6 +365,7 @@ void D2DebugUnitSpawner(D2GameStrc* pGame)
}
}

D2IdInput("Normal id", currentNormalSelectionId, DATATBLS_GetMonStatsTxtRecordCount());


bool bOpened_Unused = true;
Expand Down
Loading