feat: show environmental damage type in combat text and log

Fall, lava, drowning, fatigue, slime, and fire damage now display their
specific type instead of generic "Environmental damage" in both floating
combat text and the combat log window. The envType byte from
SMSG_ENVIRONMENTAL_DAMAGE_LOG is propagated via the powerType field to
the display layer. Added powerType to CombatLogEntry for consistent
access in the persistent combat log.
This commit is contained in:
Kelsi 2026-03-17 10:54:07 -07:00
parent 1152a70201
commit 2d53ff0c07
3 changed files with 31 additions and 8 deletions

View file

@ -4259,17 +4259,17 @@ void GameHandler::handlePacket(network::Packet& packet) {
}
case Opcode::SMSG_ENVIRONMENTAL_DAMAGE_LOG: {
// uint64 victimGuid + uint8 envDmgType + uint32 damage + uint32 absorbed + uint32 resisted
// envDmgType: 1=Exhausted(fatigue), 2=Drowning, 3=Fall, 4=Lava, 5=Slime, 6=Fire
// envDmgType: 0=Exhausted(fatigue), 1=Drowning, 2=Fall, 3=Lava, 4=Slime, 5=Fire
if (packet.getSize() - packet.getReadPos() < 21) { packet.setReadPos(packet.getSize()); break; }
uint64_t victimGuid = packet.readUInt64();
/*uint8_t envType =*/ packet.readUInt8();
uint8_t envType = packet.readUInt8();
uint32_t dmg = packet.readUInt32();
uint32_t envAbs = packet.readUInt32();
uint32_t envRes = packet.readUInt32();
if (victimGuid == playerGuid) {
// Environmental damage: no caster GUID, victim = player
// Environmental damage: pass envType via powerType field for display differentiation
if (dmg > 0)
addCombatText(CombatTextEntry::ENVIRONMENTAL, static_cast<int32_t>(dmg), 0, false, 0, 0, victimGuid);
addCombatText(CombatTextEntry::ENVIRONMENTAL, static_cast<int32_t>(dmg), 0, false, envType, 0, victimGuid);
if (envAbs > 0)
addCombatText(CombatTextEntry::ABSORB, static_cast<int32_t>(envAbs), 0, false, 0, 0, victimGuid);
if (envRes > 0)
@ -15160,6 +15160,7 @@ void GameHandler::addCombatText(CombatTextEntry::Type type, int32_t amount, uint
log.amount = amount;
log.spellId = spellId;
log.isPlayerSource = isPlayerSource;
log.powerType = powerType;
log.timestamp = std::time(nullptr);
// If the caller provided an explicit destination GUID but left source GUID as 0,
// preserve "unknown/no source" (e.g. environmental damage) instead of

View file

@ -8467,10 +8467,21 @@ void GameScreen::renderCombatText(game::GameHandler& gameHandler) {
snprintf(text, sizeof(text), "+%d", entry.amount);
color = ImVec4(0.4f, 1.0f, 0.5f, alpha);
break;
case game::CombatTextEntry::ENVIRONMENTAL:
snprintf(text, sizeof(text), "-%d", entry.amount);
case game::CombatTextEntry::ENVIRONMENTAL: {
const char* envLabel = "";
switch (entry.powerType) {
case 0: envLabel = "Fatigue "; break;
case 1: envLabel = "Drowning "; break;
case 2: envLabel = ""; break; // Fall: just show the number (WoW convention)
case 3: envLabel = "Lava "; break;
case 4: envLabel = "Slime "; break;
case 5: envLabel = "Fire "; break;
default: envLabel = ""; break;
}
snprintf(text, sizeof(text), "%s-%d", envLabel, entry.amount);
color = ImVec4(0.9f, 0.5f, 0.2f, alpha); // Orange for environmental
break;
}
case game::CombatTextEntry::ENERGIZE:
snprintf(text, sizeof(text), "+%d", entry.amount);
switch (entry.powerType) {
@ -20538,10 +20549,20 @@ void GameScreen::renderCombatLog(game::GameHandler& gameHandler) {
snprintf(desc, sizeof(desc), "%s reflects %s's attack", tgt, src);
color = ImVec4(0.8f, 0.7f, 1.0f, 1.0f);
break;
case T::ENVIRONMENTAL:
snprintf(desc, sizeof(desc), "Environmental damage: %d", e.amount);
case T::ENVIRONMENTAL: {
const char* envName = "Environmental";
switch (e.powerType) {
case 0: envName = "Fatigue"; break;
case 1: envName = "Drowning"; break;
case 2: envName = "Falling"; break;
case 3: envName = "Lava"; break;
case 4: envName = "Slime"; break;
case 5: envName = "Fire"; break;
}
snprintf(desc, sizeof(desc), "%s damage: %d", envName, e.amount);
color = ImVec4(1.0f, 0.5f, 0.2f, 1.0f);
break;
}
case T::ENERGIZE:
if (spell)
snprintf(desc, sizeof(desc), "%s gains %d power (%s)", tgt, e.amount, spell);