diff --git a/src/creatures/creature.cpp b/src/creatures/creature.cpp index 3dc2d1448ff..78294e7011d 100644 --- a/src/creatures/creature.cpp +++ b/src/creatures/creature.cpp @@ -498,13 +498,17 @@ void Creature::onDeath() { bool lastHitUnjustified = false; bool mostDamageUnjustified = false; const auto &lastHitCreature = g_game().getCreatureByID(lastHitCreatureId); + const auto &thisPlayer = getPlayer(); + const auto &thisCreature = getCreature(); + const auto &thisMaster = getMaster(); + const auto &thisMonster = getMonster(); std::shared_ptr lastHitCreatureMaster; - if (lastHitCreature && getPlayer()) { + if (lastHitCreature && thisPlayer) { /** * @deprecated -- This is here to trigger the deprecated onKill events in lua */ - lastHitCreature->deprecatedOnKilledCreature(getCreature(), true); - lastHitUnjustified = lastHitCreature->onKilledPlayer(getPlayer(), true); + lastHitCreature->deprecatedOnKilledCreature(thisCreature, true); + lastHitUnjustified = lastHitCreature->onKilledPlayer(thisPlayer, true); lastHitCreatureMaster = lastHitCreature->getMaster(); } else { lastHitCreatureMaster = nullptr; @@ -517,6 +521,7 @@ void Creature::onDeath() { int32_t mostDamage = 0; std::map, uint64_t> experienceMap; std::unordered_set> killers; + for (const auto &[creatureId, damageInfo] : damageMap) { if (creatureId == 0) { continue; @@ -533,12 +538,10 @@ void Creature::onDeath() { mostDamageCreature = attacker; } - if (attacker != getCreature()) { + if (attacker != thisCreature) { const uint64_t gainExp = getGainedExperience(attacker); const auto &attackerMaster = attacker->getMaster() ? attacker->getMaster() : attacker; - if (auto attackerPlayer = attackerMaster->getPlayer()) { - attackerPlayer->removeAttacked(getPlayer()); - + if (const auto &attackerPlayer = attackerMaster->getPlayer()) { const auto &party = attackerPlayer->getParty(); killers.insert(attackerPlayer); if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) { @@ -563,36 +566,44 @@ void Creature::onDeath() { } for (const auto &[creature, experience] : experienceMap) { - creature->onGainExperience(experience, getCreature()); + creature->onGainExperience(experience, thisCreature); } - mostDamageCreature = mostDamageCreature && mostDamageCreature->getMaster() ? mostDamageCreature->getMaster() : mostDamageCreature; + const auto &mostDamageCreatureMaster = mostDamageCreature ? mostDamageCreature->getMaster() : nullptr; + mostDamageCreature = mostDamageCreatureMaster ? mostDamageCreatureMaster : mostDamageCreature; + for (const auto &killer : killers) { - if (const auto &monster = getMonster()) { - killer->onKilledMonster(monster); - } else if (const auto &player = getPlayer(); player && mostDamageCreature != killer) { - killer->onKilledPlayer(player, false); + if (thisMonster) { + killer->onKilledMonster(thisMonster); + } else if (thisPlayer) { + bool isResponsible = mostDamageCreature == killer || (mostDamageCreatureMaster && mostDamageCreatureMaster == killer); + if (isResponsible) { + killer->onKilledPlayer(thisPlayer, false); + } + + killer->removeAttacked(thisPlayer); } } /** * @deprecated -- This is here to trigger the deprecated onKill events in lua */ - const auto &mostDamageCreatureMaster = mostDamageCreature ? mostDamageCreature->getMaster() : nullptr; - if (mostDamageCreature && (mostDamageCreature != lastHitCreature || getMonster()) && mostDamageCreature != lastHitCreatureMaster) { + if (mostDamageCreature && (mostDamageCreature != lastHitCreature || thisMonster) && mostDamageCreature != lastHitCreatureMaster) { if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) { - mostDamageUnjustified = mostDamageCreature->deprecatedOnKilledCreature(getCreature(), false); + mostDamageUnjustified = mostDamageCreature->deprecatedOnKilledCreature(thisCreature, false); } } - bool killedByPlayer = (mostDamageCreature && mostDamageCreature->getPlayer()) || (mostDamageCreatureMaster && mostDamageCreatureMaster->getPlayer()); - if (getPlayer()) { + const auto &mostDamagePlayer = mostDamageCreature ? mostDamageCreature->getPlayer() : nullptr; + const auto &mostMasterPlayer = mostDamageCreatureMaster ? mostDamageCreatureMaster->getPlayer() : nullptr; + bool killedByPlayer = mostDamagePlayer || mostMasterPlayer; + if (thisPlayer) { g_metrics().addCounter( "player_death", 1, { { "name", getNameDescription() }, - { "level", std::to_string(getPlayer()->getLevel()) }, + { "level", std::to_string(thisPlayer->getLevel()) }, { "most_damage_creature", mostDamageCreature ? mostDamageCreature->getName() : "(none)" }, { "last_hit_creature", lastHitCreature ? lastHitCreature->getName() : "(none)" }, { "most_damage_dealt", std::to_string(mostDamage) }, @@ -613,7 +624,7 @@ void Creature::onDeath() { { { "name", getName() }, { "killer", killerName }, - { "is_summon", std::to_string(getMaster() ? true : false) }, + { "is_summon", std::to_string(thisMaster ? true : false) }, { "by_player", std::to_string(killedByPlayer) }, } ); @@ -622,11 +633,11 @@ void Creature::onDeath() { bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified); death(lastHitCreature); - if (droppedCorpse && !getPlayer()) { - g_game().removeCreature(static_self_cast(), false); + if (droppedCorpse && !thisPlayer) { + g_game().removeCreature(thisCreature, false); } - if (getMaster()) { + if (thisMaster) { removeMaster(); } }