Add player death handling, race-aware faction hostility, and all-race texture support

- Death screen with "Release Spirit" button sends CMSG_REPOP_REQUEST
- Detect player death/resurrection via health updates (VALUES and CREATE)
- Faction hostility map now built per-character race instead of hardcoded Human
- CharSections.dbc texture lookup enabled for all races (was Human-only)
- Fallback texture paths use race folder names instead of hardcoded Human
- Player name in unit frame is clickable for self-targeting
This commit is contained in:
Kelsi 2026-02-06 17:27:20 -08:00
parent 046111d037
commit 7436420cd1
9 changed files with 270 additions and 102 deletions

View file

@ -2562,7 +2562,14 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
auto unit = std::static_pointer_cast<Unit>(entity);
for (const auto& [key, val] : block.fields) {
switch (key) {
case 24: unit->setHealth(val); break;
case 24:
unit->setHealth(val);
// Detect dead player on login
if (block.guid == playerGuid && val == 0) {
playerDead_ = true;
LOG_INFO("Player logged in dead");
}
break;
case 25: unit->setPower(val); break;
case 32: unit->setMaxHealth(val); break;
case 33: unit->setMaxPower(val); break;
@ -2659,11 +2666,22 @@ void GameHandler::handleUpdateObject(network::Packet& packet) {
if (block.guid == autoAttackTarget) {
stopAutoAttack();
}
// Player death
if (block.guid == playerGuid) {
playerDead_ = true;
stopAutoAttack();
LOG_INFO("Player died!");
}
// Trigger death animation for NPC units
if (entity->getType() == ObjectType::UNIT && npcDeathCallback_) {
npcDeathCallback_(block.guid);
}
} else if (oldHealth == 0 && val > 0) {
// Player resurrection
if (block.guid == playerGuid) {
playerDead_ = false;
LOG_INFO("Player resurrected!");
}
// Respawn: health went from 0 to >0, reset animation
if (entity->getType() == ObjectType::UNIT && npcRespawnCallback_) {
npcRespawnCallback_(block.guid);
@ -2948,6 +2966,15 @@ std::shared_ptr<Entity> GameHandler::getTarget() const {
return entityManager.getEntity(targetGuid);
}
void GameHandler::releaseSpirit() {
if (!playerDead_) return;
if (socket && state == WorldState::IN_WORLD) {
auto packet = RepopRequestPacket::build();
socket->send(packet);
LOG_INFO("Sent CMSG_REPOP_REQUEST (Release Spirit)");
}
}
void GameHandler::tabTarget(float playerX, float playerY, float playerZ) {
// Rebuild cycle list if stale
if (tabCycleStale) {