mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-02 15:53:51 +00:00
Fix single-player spawn coords and show action bar spell names
This commit is contained in:
parent
6d22f4249f
commit
140a2e2c22
5 changed files with 79 additions and 18 deletions
|
|
@ -7,6 +7,7 @@
|
||||||
#include "ui/spellbook_screen.hpp"
|
#include "ui/spellbook_screen.hpp"
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
namespace wowee { namespace ui {
|
namespace wowee { namespace ui {
|
||||||
|
|
||||||
|
|
@ -129,6 +130,10 @@ private:
|
||||||
InventoryScreen inventoryScreen;
|
InventoryScreen inventoryScreen;
|
||||||
SpellbookScreen spellbookScreen;
|
SpellbookScreen spellbookScreen;
|
||||||
rendering::WorldMap worldMap;
|
rendering::WorldMap worldMap;
|
||||||
|
|
||||||
|
bool actionSpellDbAttempted = false;
|
||||||
|
bool actionSpellDbLoaded = false;
|
||||||
|
std::unordered_map<uint32_t, std::string> actionSpellNames;
|
||||||
};
|
};
|
||||||
|
|
||||||
}} // namespace wowee::ui
|
}} // namespace wowee::ui
|
||||||
|
|
|
||||||
|
|
@ -1058,7 +1058,7 @@ void Application::startSinglePlayer() {
|
||||||
spClass_ = activeChar->characterClass;
|
spClass_ = activeChar->characterClass;
|
||||||
spMapId_ = activeChar->mapId;
|
spMapId_ = activeChar->mapId;
|
||||||
spZoneId_ = activeChar->zoneId;
|
spZoneId_ = activeChar->zoneId;
|
||||||
spSpawnCanonical_ = core::coords::serverToCanonical(glm::vec3(activeChar->x, activeChar->y, activeChar->z));
|
spSpawnCanonical_ = glm::vec3(activeChar->x, activeChar->y, activeChar->z);
|
||||||
spYawDeg_ = 0.0f;
|
spYawDeg_ = 0.0f;
|
||||||
spPitchDeg_ = -5.0f;
|
spPitchDeg_ = -5.0f;
|
||||||
|
|
||||||
|
|
@ -1077,7 +1077,7 @@ void Application::startSinglePlayer() {
|
||||||
if (hasCreate) {
|
if (hasCreate) {
|
||||||
spMapId_ = createInfo.mapId;
|
spMapId_ = createInfo.mapId;
|
||||||
spZoneId_ = createInfo.zoneId;
|
spZoneId_ = createInfo.zoneId;
|
||||||
spSpawnCanonical_ = core::coords::serverToCanonical(glm::vec3(createInfo.x, createInfo.y, createInfo.z));
|
spSpawnCanonical_ = glm::vec3(createInfo.x, createInfo.y, createInfo.z);
|
||||||
spYawDeg_ = glm::degrees(createInfo.orientation);
|
spYawDeg_ = glm::degrees(createInfo.orientation);
|
||||||
spPitchDeg_ = -5.0f;
|
spPitchDeg_ = -5.0f;
|
||||||
spawnSnapToGround = true;
|
spawnSnapToGround = true;
|
||||||
|
|
|
||||||
|
|
@ -1597,11 +1597,10 @@ bool GameHandler::loadSinglePlayerCharacterState(uint64_t guid) {
|
||||||
localPlayerMaxHealth_ = std::max<uint32_t>(localPlayerHealth_, maxHealth);
|
localPlayerMaxHealth_ = std::max<uint32_t>(localPlayerHealth_, maxHealth);
|
||||||
playerNextLevelXp_ = xpForLevel(localPlayerLevel_);
|
playerNextLevelXp_ = xpForLevel(localPlayerLevel_);
|
||||||
|
|
||||||
// Seed movement info for spawn
|
// Seed movement info for spawn (canonical coords in DB)
|
||||||
glm::vec3 canonical = core::coords::serverToCanonical(glm::vec3(posX, posY, posZ));
|
movementInfo.x = posX;
|
||||||
movementInfo.x = canonical.x;
|
movementInfo.y = posY;
|
||||||
movementInfo.y = canonical.y;
|
movementInfo.z = posZ;
|
||||||
movementInfo.z = canonical.z;
|
|
||||||
movementInfo.orientation = orientation;
|
movementInfo.orientation = orientation;
|
||||||
|
|
||||||
spLastDirtyX_ = movementInfo.x;
|
spLastDirtyX_ = movementInfo.x;
|
||||||
|
|
@ -1631,6 +1630,7 @@ void GameHandler::applySinglePlayerStartData(Race race, Class cls) {
|
||||||
|
|
||||||
uint8_t raceVal = static_cast<uint8_t>(race);
|
uint8_t raceVal = static_cast<uint8_t>(race);
|
||||||
uint8_t classVal = static_cast<uint8_t>(cls);
|
uint8_t classVal = static_cast<uint8_t>(cls);
|
||||||
|
bool addedItem = false;
|
||||||
|
|
||||||
for (const auto& row : startDb.items) {
|
for (const auto& row : startDb.items) {
|
||||||
if (row.itemId == 0 || row.amount == 0) continue;
|
if (row.itemId == 0 || row.amount == 0) continue;
|
||||||
|
|
@ -1655,7 +1655,9 @@ void GameHandler::applySinglePlayerStartData(Race race, Class cls) {
|
||||||
def.name = "Item " + std::to_string(row.itemId);
|
def.name = "Item " + std::to_string(row.itemId);
|
||||||
}
|
}
|
||||||
|
|
||||||
inventory.addItem(def);
|
if (inventory.addItem(def)) {
|
||||||
|
addedItem = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto& row : startDb.items) {
|
for (const auto& row : startDb.items) {
|
||||||
|
|
@ -1665,6 +1667,10 @@ void GameHandler::applySinglePlayerStartData(Race race, Class cls) {
|
||||||
removeItemsFromInventory(inventory, row.itemId, static_cast<uint32_t>(-row.amount));
|
removeItemsFromInventory(inventory, row.itemId, static_cast<uint32_t>(-row.amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!addedItem && startDb.items.empty()) {
|
||||||
|
addSystemChatMessage("No starting items found in playercreateinfo_item.sql.");
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t raceMask = 1u << (raceVal > 0 ? (raceVal - 1) : 0);
|
uint32_t raceMask = 1u << (raceVal > 0 ? (raceVal - 1) : 0);
|
||||||
uint32_t classMask = 1u << (classVal > 0 ? (classVal - 1) : 0);
|
uint32_t classMask = 1u << (classVal > 0 ? (classVal - 1) : 0);
|
||||||
for (const auto& row : startDb.spells) {
|
for (const auto& row : startDb.spells) {
|
||||||
|
|
@ -1738,10 +1744,9 @@ void GameHandler::saveSinglePlayerCharacterState(bool force) {
|
||||||
sqlite3_bind_int(stmt, 1, static_cast<int>(localPlayerLevel_));
|
sqlite3_bind_int(stmt, 1, static_cast<int>(localPlayerLevel_));
|
||||||
sqlite3_bind_int(stmt, 2, static_cast<int>(active->zoneId));
|
sqlite3_bind_int(stmt, 2, static_cast<int>(active->zoneId));
|
||||||
sqlite3_bind_int(stmt, 3, static_cast<int>(active->mapId));
|
sqlite3_bind_int(stmt, 3, static_cast<int>(active->mapId));
|
||||||
glm::vec3 serverPos = core::coords::canonicalToServer(glm::vec3(movementInfo.x, movementInfo.y, movementInfo.z));
|
sqlite3_bind_double(stmt, 4, movementInfo.x);
|
||||||
sqlite3_bind_double(stmt, 4, serverPos.x);
|
sqlite3_bind_double(stmt, 5, movementInfo.y);
|
||||||
sqlite3_bind_double(stmt, 5, serverPos.y);
|
sqlite3_bind_double(stmt, 6, movementInfo.z);
|
||||||
sqlite3_bind_double(stmt, 6, serverPos.z);
|
|
||||||
sqlite3_bind_double(stmt, 7, movementInfo.orientation);
|
sqlite3_bind_double(stmt, 7, movementInfo.orientation);
|
||||||
sqlite3_bind_int64(stmt, 8, static_cast<sqlite3_int64>(playerMoneyCopper_));
|
sqlite3_bind_int64(stmt, 8, static_cast<sqlite3_int64>(playerMoneyCopper_));
|
||||||
sqlite3_bind_int(stmt, 9, static_cast<int>(playerXp_));
|
sqlite3_bind_int(stmt, 9, static_cast<int>(playerXp_));
|
||||||
|
|
@ -1901,13 +1906,12 @@ void GameHandler::saveSinglePlayerCharacterState(bool force) {
|
||||||
spPeriodicTimer_ = 0.0f;
|
spPeriodicTimer_ = 0.0f;
|
||||||
|
|
||||||
// Update cached character list position/level for UI.
|
// Update cached character list position/level for UI.
|
||||||
glm::vec3 serverPos = core::coords::canonicalToServer(glm::vec3(movementInfo.x, movementInfo.y, movementInfo.z));
|
|
||||||
for (auto& ch : characters) {
|
for (auto& ch : characters) {
|
||||||
if (ch.guid == activeCharacterGuid_) {
|
if (ch.guid == activeCharacterGuid_) {
|
||||||
ch.level = static_cast<uint8_t>(localPlayerLevel_);
|
ch.level = static_cast<uint8_t>(localPlayerLevel_);
|
||||||
ch.x = serverPos.x;
|
ch.x = movementInfo.x;
|
||||||
ch.y = serverPos.y;
|
ch.y = movementInfo.y;
|
||||||
ch.z = serverPos.z;
|
ch.z = movementInfo.z;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -589,7 +589,8 @@ std::vector<NpcSpawnDef> NpcManager::loadSpawnDefsFromAzerothCoreDb(
|
||||||
float o = std::stof(cols[10]);
|
float o = std::stof(cols[10]);
|
||||||
uint32_t curhealth = static_cast<uint32_t>(std::stoul(cols[14]));
|
uint32_t curhealth = static_cast<uint32_t>(std::stoul(cols[14]));
|
||||||
|
|
||||||
glm::vec3 canonical = core::coords::serverToCanonical(glm::vec3(sx, sy, sz));
|
// AzerothCore DB uses client/canonical coordinates.
|
||||||
|
glm::vec3 canonical = glm::vec3(sx, sy, sz);
|
||||||
float dx = canonical.x - playerCanonical.x;
|
float dx = canonical.x - playerCanonical.x;
|
||||||
float dy = canonical.y - playerCanonical.y;
|
float dy = canonical.y - playerCanonical.y;
|
||||||
if (dx * dx + dy * dy > kRadius * kRadius) return true;
|
if (dx * dx + dy * dy > kRadius * kRadius) return true;
|
||||||
|
|
|
||||||
|
|
@ -1020,6 +1020,7 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
auto* window = core::Application::getInstance().getWindow();
|
auto* window = core::Application::getInstance().getWindow();
|
||||||
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
|
float screenW = window ? static_cast<float>(window->getWidth()) : 1280.0f;
|
||||||
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
|
float screenH = window ? static_cast<float>(window->getHeight()) : 720.0f;
|
||||||
|
auto* assetMgr = core::Application::getInstance().getAssetManager();
|
||||||
|
|
||||||
float slotSize = 48.0f;
|
float slotSize = 48.0f;
|
||||||
float spacing = 4.0f;
|
float spacing = 4.0f;
|
||||||
|
|
@ -1060,9 +1061,51 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.5f, 0.9f));
|
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.3f, 0.3f, 0.5f, 0.9f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getSpellName = [&](uint32_t spellId) -> std::string {
|
||||||
|
if (!actionSpellDbAttempted) {
|
||||||
|
actionSpellDbAttempted = true;
|
||||||
|
if (assetMgr && assetMgr->isInitialized()) {
|
||||||
|
auto dbc = assetMgr->loadDBC("Spell.dbc");
|
||||||
|
if (dbc && dbc->isLoaded()) {
|
||||||
|
uint32_t fieldCount = dbc->getFieldCount();
|
||||||
|
uint32_t nameField = 136;
|
||||||
|
if (fieldCount < 137) {
|
||||||
|
if (fieldCount > 10) {
|
||||||
|
nameField = fieldCount > 140 ? 136 : 1;
|
||||||
|
} else {
|
||||||
|
nameField = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t count = dbc->getRecordCount();
|
||||||
|
actionSpellNames.reserve(count);
|
||||||
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
|
uint32_t id = dbc->getUInt32(i, 0);
|
||||||
|
std::string name = dbc->getString(i, nameField);
|
||||||
|
if (!name.empty() && id > 0) {
|
||||||
|
actionSpellNames[id] = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
actionSpellDbLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto it = actionSpellNames.find(spellId);
|
||||||
|
if (it != actionSpellNames.end()) return it->second;
|
||||||
|
return "Spell #" + std::to_string(spellId);
|
||||||
|
};
|
||||||
|
|
||||||
char label[32];
|
char label[32];
|
||||||
|
std::string spellName;
|
||||||
if (slot.type == game::ActionBarSlot::SPELL) {
|
if (slot.type == game::ActionBarSlot::SPELL) {
|
||||||
snprintf(label, sizeof(label), "S%u", slot.id);
|
spellName = getSpellName(slot.id);
|
||||||
|
if (spellName.size() > 6) {
|
||||||
|
spellName = spellName.substr(0, 6);
|
||||||
|
}
|
||||||
|
snprintf(label, sizeof(label), "%s", spellName.c_str());
|
||||||
|
} else if (slot.type == game::ActionBarSlot::ITEM) {
|
||||||
|
snprintf(label, sizeof(label), "Item");
|
||||||
|
} else if (slot.type == game::ActionBarSlot::MACRO) {
|
||||||
|
snprintf(label, sizeof(label), "Macro");
|
||||||
} else {
|
} else {
|
||||||
snprintf(label, sizeof(label), "--");
|
snprintf(label, sizeof(label), "--");
|
||||||
}
|
}
|
||||||
|
|
@ -1075,6 +1118,14 @@ void GameScreen::renderActionBar(game::GameHandler& gameHandler) {
|
||||||
}
|
}
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
|
|
||||||
|
if (ImGui::IsItemHovered() && slot.type == game::ActionBarSlot::SPELL && slot.id != 0) {
|
||||||
|
std::string fullName = getSpellName(slot.id);
|
||||||
|
ImGui::BeginTooltip();
|
||||||
|
ImGui::Text("%s", fullName.c_str());
|
||||||
|
ImGui::TextDisabled("Spell ID: %u", slot.id);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
|
||||||
// Cooldown overlay text
|
// Cooldown overlay text
|
||||||
if (onCooldown) {
|
if (onCooldown) {
|
||||||
char cdText[16];
|
char cdText[16];
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue