mirror of
https://github.com/Kelsidavis/WoWee.git
synced 2026-05-03 08:03:50 +00:00
Improve combat messages: power-type-aware errors, fix chat line breaks, better wording
- getSpellCastResultString now returns "Not enough rage/energy/focus/runic power" based on player power type instead of always "Not enough mana" - Fix NPC combat messages concatenating onto previous lines by combining prefix+body into single renderTextWithLinks call instead of TextWrapped+SameLine - Improve generic error strings to be more WoW-authentic (Invalid target, Target not in line of sight, etc.)
This commit is contained in:
parent
d0a0cf6e5e
commit
4dcc0f1d79
3 changed files with 54 additions and 58 deletions
|
|
@ -76,7 +76,7 @@ struct SpellCooldownEntry {
|
||||||
/**
|
/**
|
||||||
* Get human-readable spell cast failure reason (WoW 3.3.5a SpellCastResult)
|
* Get human-readable spell cast failure reason (WoW 3.3.5a SpellCastResult)
|
||||||
*/
|
*/
|
||||||
inline const char* getSpellCastResultString(uint8_t result) {
|
inline const char* getSpellCastResultString(uint8_t result, int powerType = -1) {
|
||||||
// AzerothCore 3.3.5a SpellCastResult enum (SharedDefines.h)
|
// AzerothCore 3.3.5a SpellCastResult enum (SharedDefines.h)
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case 0: return nullptr; // SUCCESS — not a failure
|
case 0: return nullptr; // SUCCESS — not a failure
|
||||||
|
|
@ -91,7 +91,7 @@ inline const char* getSpellCastResultString(uint8_t result) {
|
||||||
case 9: return "Aura bounced";
|
case 9: return "Aura bounced";
|
||||||
case 10: return "Autotrack interrupted";
|
case 10: return "Autotrack interrupted";
|
||||||
case 11: return "Bad implicit targets";
|
case 11: return "Bad implicit targets";
|
||||||
case 12: return "Bad targets";
|
case 12: return "Invalid target";
|
||||||
case 13: return "Can't be charmed";
|
case 13: return "Can't be charmed";
|
||||||
case 14: return "Can't be disenchanted";
|
case 14: return "Can't be disenchanted";
|
||||||
case 15: return "Can't be disenchanted (skill)";
|
case 15: return "Can't be disenchanted (skill)";
|
||||||
|
|
@ -126,11 +126,11 @@ inline const char* getSpellCastResultString(uint8_t result) {
|
||||||
case 44: return "Item not found";
|
case 44: return "Item not found";
|
||||||
case 45: return "Item not ready";
|
case 45: return "Item not ready";
|
||||||
case 46: return "Level requirement";
|
case 46: return "Level requirement";
|
||||||
case 47: return "Line of sight";
|
case 47: return "Target not in line of sight";
|
||||||
case 48: return "Target too low level";
|
case 48: return "Target too low level";
|
||||||
case 49: return "Low cast level";
|
case 49: return "Low cast level";
|
||||||
case 50: return "Mainhand empty";
|
case 50: return "Mainhand empty";
|
||||||
case 51: return "Moving";
|
case 51: return "Can't do that while moving";
|
||||||
case 52: return "Need ammo";
|
case 52: return "Need ammo";
|
||||||
case 53: return "Need ammo pouch";
|
case 53: return "Need ammo pouch";
|
||||||
case 54: return "Need exotic ammo";
|
case 54: return "Need exotic ammo";
|
||||||
|
|
@ -140,7 +140,7 @@ inline const char* getSpellCastResultString(uint8_t result) {
|
||||||
case 58: return "Not fishable";
|
case 58: return "Not fishable";
|
||||||
case 59: return "Not flying";
|
case 59: return "Not flying";
|
||||||
case 60: return "Not here";
|
case 60: return "Not here";
|
||||||
case 61: return "Not in front";
|
case 61: return "Target needs to be in front of you";
|
||||||
case 62: return "Not in control";
|
case 62: return "Not in control";
|
||||||
case 63: return "Not known";
|
case 63: return "Not known";
|
||||||
case 64: return "Not mounted";
|
case 64: return "Not mounted";
|
||||||
|
|
@ -157,14 +157,21 @@ inline const char* getSpellCastResultString(uint8_t result) {
|
||||||
case 75: return "No ammo";
|
case 75: return "No ammo";
|
||||||
case 76: return "No charges remain";
|
case 76: return "No charges remain";
|
||||||
case 77: return "No champion";
|
case 77: return "No champion";
|
||||||
case 78: return "No combo points";
|
case 78: return "Not enough combo points";
|
||||||
case 79: return "No dueling";
|
case 79: return "No dueling";
|
||||||
case 80: return "No endurance";
|
case 80: return "No endurance";
|
||||||
case 81: return "No fish";
|
case 81: return "No fish";
|
||||||
case 82: return "No items while shapeshifted";
|
case 82: return "No items while shapeshifted";
|
||||||
case 83: return "No mounts allowed here";
|
case 83: return "No mounts allowed here";
|
||||||
case 84: return "No pet";
|
case 84: return "No pet";
|
||||||
case 85: return "Not enough mana";
|
case 85:
|
||||||
|
switch (powerType) {
|
||||||
|
case 1: return "Not enough rage";
|
||||||
|
case 2: return "Not enough focus";
|
||||||
|
case 3: return "Not enough energy";
|
||||||
|
case 6: return "Not enough runic power";
|
||||||
|
default: return "Not enough mana";
|
||||||
|
}
|
||||||
case 86: return "Nothing to dispel";
|
case 86: return "Nothing to dispel";
|
||||||
case 87: return "Nothing to steal";
|
case 87: return "Nothing to steal";
|
||||||
case 88: return "Only above water";
|
case 88: return "Only above water";
|
||||||
|
|
@ -182,8 +189,8 @@ inline const char* getSpellCastResultString(uint8_t result) {
|
||||||
case 100: return "Reagents required";
|
case 100: return "Reagents required";
|
||||||
case 101: return "Requires area";
|
case 101: return "Requires area";
|
||||||
case 102: return "Requires spell focus";
|
case 102: return "Requires spell focus";
|
||||||
case 103: return "Rooted";
|
case 103: return "Can't do that while rooted";
|
||||||
case 104: return "Silenced";
|
case 104: return "Can't do that while silenced";
|
||||||
case 105: return "Spell in progress";
|
case 105: return "Spell in progress";
|
||||||
case 106: return "Spell learned";
|
case 106: return "Spell learned";
|
||||||
case 107: return "Spell unavailable";
|
case 107: return "Spell unavailable";
|
||||||
|
|
|
||||||
|
|
@ -4147,9 +4147,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
constexpr uint32_t UNIT_DYNFLAG_LOOTABLE = 0x0001;
|
constexpr uint32_t UNIT_DYNFLAG_LOOTABLE = 0x0001;
|
||||||
bool unitInitiallyDead = false;
|
bool unitInitiallyDead = false;
|
||||||
const uint16_t ufHealth = fieldIndex(UF::UNIT_FIELD_HEALTH);
|
const uint16_t ufHealth = fieldIndex(UF::UNIT_FIELD_HEALTH);
|
||||||
const uint16_t ufPower = fieldIndex(UF::UNIT_FIELD_POWER1);
|
const uint16_t ufPowerBase = fieldIndex(UF::UNIT_FIELD_POWER1);
|
||||||
const uint16_t ufMaxHealth = fieldIndex(UF::UNIT_FIELD_MAXHEALTH);
|
const uint16_t ufMaxHealth = fieldIndex(UF::UNIT_FIELD_MAXHEALTH);
|
||||||
const uint16_t ufMaxPower = fieldIndex(UF::UNIT_FIELD_MAXPOWER1);
|
const uint16_t ufMaxPowerBase = fieldIndex(UF::UNIT_FIELD_MAXPOWER1);
|
||||||
const uint16_t ufLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
const uint16_t ufLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
||||||
const uint16_t ufFaction = fieldIndex(UF::UNIT_FIELD_FACTIONTEMPLATE);
|
const uint16_t ufFaction = fieldIndex(UF::UNIT_FIELD_FACTIONTEMPLATE);
|
||||||
const uint16_t ufFlags = fieldIndex(UF::UNIT_FIELD_FLAGS);
|
const uint16_t ufFlags = fieldIndex(UF::UNIT_FIELD_FLAGS);
|
||||||
|
|
@ -4157,6 +4157,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
const uint16_t ufDisplayId = fieldIndex(UF::UNIT_FIELD_DISPLAYID);
|
const uint16_t ufDisplayId = fieldIndex(UF::UNIT_FIELD_DISPLAYID);
|
||||||
const uint16_t ufMountDisplayId = fieldIndex(UF::UNIT_FIELD_MOUNTDISPLAYID);
|
const uint16_t ufMountDisplayId = fieldIndex(UF::UNIT_FIELD_MOUNTDISPLAYID);
|
||||||
const uint16_t ufNpcFlags = fieldIndex(UF::UNIT_NPC_FLAGS);
|
const uint16_t ufNpcFlags = fieldIndex(UF::UNIT_NPC_FLAGS);
|
||||||
|
const uint16_t ufBytes0 = fieldIndex(UF::UNIT_FIELD_BYTES_0);
|
||||||
for (const auto& [key, val] : block.fields) {
|
for (const auto& [key, val] : block.fields) {
|
||||||
if (key == ufHealth) {
|
if (key == ufHealth) {
|
||||||
unit->setHealth(val);
|
unit->setHealth(val);
|
||||||
|
|
@ -4167,9 +4168,14 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
playerDead_ = true;
|
playerDead_ = true;
|
||||||
LOG_INFO("Player logged in dead");
|
LOG_INFO("Player logged in dead");
|
||||||
}
|
}
|
||||||
} else if (key == ufPower) { unit->setPower(val); }
|
} else if (key == ufBytes0) {
|
||||||
else if (key == ufMaxHealth) { unit->setMaxHealth(val); }
|
unit->setPowerType(static_cast<uint8_t>((val >> 24) & 0xFF));
|
||||||
else if (key == ufMaxPower) { unit->setMaxPower(val); }
|
} else if (key >= ufPowerBase && key < ufPowerBase + 7) {
|
||||||
|
unit->setPowerByType(static_cast<uint8_t>(key - ufPowerBase), val);
|
||||||
|
} else if (key == ufMaxHealth) { unit->setMaxHealth(val); }
|
||||||
|
else if (key >= ufMaxPowerBase && key < ufMaxPowerBase + 7) {
|
||||||
|
unit->setMaxPowerByType(static_cast<uint8_t>(key - ufMaxPowerBase), val);
|
||||||
|
}
|
||||||
else if (key == ufFaction) { unit->setFactionTemplate(val); }
|
else if (key == ufFaction) { unit->setFactionTemplate(val); }
|
||||||
else if (key == ufFlags) { unit->setUnitFlags(val); }
|
else if (key == ufFlags) { unit->setUnitFlags(val); }
|
||||||
else if (key == ufDynFlags) {
|
else if (key == ufDynFlags) {
|
||||||
|
|
@ -4505,9 +4511,9 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
bool npcDeathNotified = false;
|
bool npcDeathNotified = false;
|
||||||
bool npcRespawnNotified = false;
|
bool npcRespawnNotified = false;
|
||||||
const uint16_t ufHealth = fieldIndex(UF::UNIT_FIELD_HEALTH);
|
const uint16_t ufHealth = fieldIndex(UF::UNIT_FIELD_HEALTH);
|
||||||
const uint16_t ufPower = fieldIndex(UF::UNIT_FIELD_POWER1);
|
const uint16_t ufPowerBase = fieldIndex(UF::UNIT_FIELD_POWER1);
|
||||||
const uint16_t ufMaxHealth = fieldIndex(UF::UNIT_FIELD_MAXHEALTH);
|
const uint16_t ufMaxHealth = fieldIndex(UF::UNIT_FIELD_MAXHEALTH);
|
||||||
const uint16_t ufMaxPower = fieldIndex(UF::UNIT_FIELD_MAXPOWER1);
|
const uint16_t ufMaxPowerBase = fieldIndex(UF::UNIT_FIELD_MAXPOWER1);
|
||||||
const uint16_t ufLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
const uint16_t ufLevel = fieldIndex(UF::UNIT_FIELD_LEVEL);
|
||||||
const uint16_t ufFaction = fieldIndex(UF::UNIT_FIELD_FACTIONTEMPLATE);
|
const uint16_t ufFaction = fieldIndex(UF::UNIT_FIELD_FACTIONTEMPLATE);
|
||||||
const uint16_t ufFlags = fieldIndex(UF::UNIT_FIELD_FLAGS);
|
const uint16_t ufFlags = fieldIndex(UF::UNIT_FIELD_FLAGS);
|
||||||
|
|
@ -4515,6 +4521,7 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
const uint16_t ufDisplayId = fieldIndex(UF::UNIT_FIELD_DISPLAYID);
|
const uint16_t ufDisplayId = fieldIndex(UF::UNIT_FIELD_DISPLAYID);
|
||||||
const uint16_t ufMountDisplayId = fieldIndex(UF::UNIT_FIELD_MOUNTDISPLAYID);
|
const uint16_t ufMountDisplayId = fieldIndex(UF::UNIT_FIELD_MOUNTDISPLAYID);
|
||||||
const uint16_t ufNpcFlags = fieldIndex(UF::UNIT_NPC_FLAGS);
|
const uint16_t ufNpcFlags = fieldIndex(UF::UNIT_NPC_FLAGS);
|
||||||
|
const uint16_t ufBytes0 = fieldIndex(UF::UNIT_FIELD_BYTES_0);
|
||||||
for (const auto& [key, val] : block.fields) {
|
for (const auto& [key, val] : block.fields) {
|
||||||
if (key == ufHealth) {
|
if (key == ufHealth) {
|
||||||
uint32_t oldHealth = unit->getHealth();
|
uint32_t oldHealth = unit->getHealth();
|
||||||
|
|
@ -4548,9 +4555,14 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
|
||||||
npcRespawnNotified = true;
|
npcRespawnNotified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (key == ufPower) { unit->setPower(val); }
|
} else if (key == ufBytes0) {
|
||||||
else if (key == ufMaxHealth) { unit->setMaxHealth(val); }
|
unit->setPowerType(static_cast<uint8_t>((val >> 24) & 0xFF));
|
||||||
else if (key == ufMaxPower) { unit->setMaxPower(val); }
|
} else if (key >= ufPowerBase && key < ufPowerBase + 7) {
|
||||||
|
unit->setPowerByType(static_cast<uint8_t>(key - ufPowerBase), val);
|
||||||
|
} else if (key == ufMaxHealth) { unit->setMaxHealth(val); }
|
||||||
|
else if (key >= ufMaxPowerBase && key < ufMaxPowerBase + 7) {
|
||||||
|
unit->setMaxPowerByType(static_cast<uint8_t>(key - ufMaxPowerBase), val);
|
||||||
|
}
|
||||||
else if (key == ufFlags) { unit->setUnitFlags(val); }
|
else if (key == ufFlags) { unit->setUnitFlags(val); }
|
||||||
else if (key == ufDynFlags) {
|
else if (key == ufDynFlags) {
|
||||||
uint32_t oldDyn = unit->getDynamicFlags();
|
uint32_t oldDyn = unit->getDynamicFlags();
|
||||||
|
|
@ -8109,7 +8121,12 @@ void GameHandler::handleCastFailed(network::Packet& packet) {
|
||||||
castTimeRemaining = 0.0f;
|
castTimeRemaining = 0.0f;
|
||||||
|
|
||||||
// Add system message about failed cast with readable reason
|
// Add system message about failed cast with readable reason
|
||||||
const char* reason = getSpellCastResultString(data.result);
|
int powerType = -1;
|
||||||
|
auto playerEntity = entityManager.getEntity(playerGuid);
|
||||||
|
if (auto playerUnit = std::dynamic_pointer_cast<Unit>(playerEntity)) {
|
||||||
|
powerType = playerUnit->getPowerType();
|
||||||
|
}
|
||||||
|
const char* reason = getSpellCastResultString(data.result, powerType);
|
||||||
MessageChatData msg;
|
MessageChatData msg;
|
||||||
msg.type = ChatType::SYSTEM;
|
msg.type = ChatType::SYSTEM;
|
||||||
msg.language = ChatLanguage::UNIVERSAL;
|
msg.language = ChatLanguage::UNIVERSAL;
|
||||||
|
|
|
||||||
|
|
@ -1054,55 +1054,27 @@ void GameScreen::renderChatWindow(game::GameHandler& gameHandler) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (msg.type == game::ChatType::SYSTEM) {
|
if (msg.type == game::ChatType::SYSTEM) {
|
||||||
if (!tsPrefix.empty()) {
|
renderTextWithLinks(tsPrefix + processedMessage, color);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
|
|
||||||
ImGui::TextWrapped("%s", tsPrefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
}
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
} else if (msg.type == game::ChatType::TEXT_EMOTE) {
|
} else if (msg.type == game::ChatType::TEXT_EMOTE) {
|
||||||
if (!tsPrefix.empty()) {
|
renderTextWithLinks(tsPrefix + processedMessage, color);
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.6f, 0.6f, 0.6f, 1.0f));
|
|
||||||
ImGui::TextWrapped("%s", tsPrefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
}
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
} else if (!msg.senderName.empty()) {
|
} else if (!msg.senderName.empty()) {
|
||||||
if (msg.type == game::ChatType::MONSTER_SAY || msg.type == game::ChatType::MONSTER_YELL) {
|
if (msg.type == game::ChatType::MONSTER_SAY || msg.type == game::ChatType::MONSTER_YELL) {
|
||||||
std::string prefix = tsPrefix + msg.senderName + " says: ";
|
std::string fullMsg = tsPrefix + msg.senderName + " says: " + processedMessage;
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
renderTextWithLinks(fullMsg, color);
|
||||||
ImGui::TextWrapped("%s", prefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
} else if (msg.type == game::ChatType::CHANNEL && !msg.channelName.empty()) {
|
} else if (msg.type == game::ChatType::CHANNEL && !msg.channelName.empty()) {
|
||||||
int chIdx = gameHandler.getChannelIndex(msg.channelName);
|
int chIdx = gameHandler.getChannelIndex(msg.channelName);
|
||||||
std::string chDisplay = chIdx > 0
|
std::string chDisplay = chIdx > 0
|
||||||
? "[" + std::to_string(chIdx) + ". " + msg.channelName + "]"
|
? "[" + std::to_string(chIdx) + ". " + msg.channelName + "]"
|
||||||
: "[" + msg.channelName + "]";
|
: "[" + msg.channelName + "]";
|
||||||
std::string prefix = tsPrefix + chDisplay + " [" + msg.senderName + "]: ";
|
std::string fullMsg = tsPrefix + chDisplay + " [" + msg.senderName + "]: " + processedMessage;
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
renderTextWithLinks(fullMsg, color);
|
||||||
ImGui::TextWrapped("%s", prefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
} else {
|
} else {
|
||||||
std::string prefix = tsPrefix + "[" + std::string(getChatTypeName(msg.type)) + "] " + msg.senderName + ": ";
|
std::string fullMsg = tsPrefix + "[" + std::string(getChatTypeName(msg.type)) + "] " + msg.senderName + ": " + processedMessage;
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
renderTextWithLinks(fullMsg, color);
|
||||||
ImGui::TextWrapped("%s", prefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::string prefix = tsPrefix + "[" + std::string(getChatTypeName(msg.type)) + "] ";
|
std::string fullMsg = tsPrefix + "[" + std::string(getChatTypeName(msg.type)) + "] " + processedMessage;
|
||||||
ImGui::PushStyleColor(ImGuiCol_Text, color);
|
renderTextWithLinks(fullMsg, color);
|
||||||
ImGui::TextWrapped("%s", prefix.c_str());
|
|
||||||
ImGui::PopStyleColor();
|
|
||||||
ImGui::SameLine(0, 0);
|
|
||||||
renderTextWithLinks(processedMessage, color);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue