diff --git a/src/game/Object/Creature.cpp b/src/game/Object/Creature.cpp index b659e1e0..eec4f78d 100644 --- a/src/game/Object/Creature.cpp +++ b/src/game/Object/Creature.cpp @@ -150,7 +150,7 @@ Creature::Creature(CreatureSubtype subtype) : Unit(), m_AlreadyCallAssistance(false), m_AlreadySearchedAssistance(false), m_AI_locked(false), m_IsDeadByDefault(false), m_temporaryFactionFlags(TEMPFACTION_NONE), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), - m_creatureInfo(NULL) + m_creatureInfo(NULL), m_PlayerDamageReq(0) { /* Loot data */ hasBeenLootedOnce = false; @@ -1251,6 +1251,8 @@ void Creature::SelectLevel(const CreatureInfo* cinfo, float percentHealth /*= 10 else { SetHealthPercent(percentHealth); } + ResetPlayerDamageReq(); + SetModifierValue(UNIT_MOD_HEALTH, BASE_VALUE, float(health)); // all power types @@ -1335,6 +1337,12 @@ float Creature::_GetDamageMod(int32 Rank) } } +void Creature::LowerPlayerDamageReq(uint32 unDamage) +{ + if (m_PlayerDamageReq) + m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0; +} + float Creature::_GetSpellDamageMod(int32 Rank) { switch (Rank) // define rates for each elite rank @@ -1651,6 +1659,7 @@ void Creature::SetDeathState(DeathState s) // Dynamic flags must be set on Tapped by default. SetUInt32Value(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_NONE); LoadCreatureAddon(true); + ResetPlayerDamageReq(); // Flags after LoadCreatureAddon. Any spell in *addon // will not be able to adjust these. diff --git a/src/game/Object/Creature.h b/src/game/Object/Creature.h index edfba0ce..ebf11da9 100644 --- a/src/game/Object/Creature.h +++ b/src/game/Object/Creature.h @@ -684,6 +684,9 @@ class Creature : public Unit Player* GetLootRecipient() const; // use group cases as prefered Group* GetGroupLootRecipient() const; bool IsTappedBy(Player const* player) const; + bool IsDamageEnoughForLootingAndReward() const { return m_PlayerDamageReq == 0; } + void LowerPlayerDamageReq(uint32 unDamage); + void ResetPlayerDamageReq() { m_PlayerDamageReq = GetHealth() / 2; } /** * function indicating whether the whether the creature has a looter recipient defined (either a group ID, either a player GUID). @@ -842,6 +845,7 @@ class Creature : public Unit MovementGeneratorType m_defaultMovementType; Cell m_currentCell; // store current cell where creature listed uint32 m_equipmentId; + uint32 m_PlayerDamageReq; // below fields has potential for optimization bool m_AlreadyCallAssistance; diff --git a/src/game/Object/CreatureAI.h b/src/game/Object/CreatureAI.h index ec9e4e34..b68262c5 100644 --- a/src/game/Object/CreatureAI.h +++ b/src/game/Object/CreatureAI.h @@ -147,7 +147,7 @@ class CreatureAI * Called for reaction at stopping attack at no attackers or targets * This is called usually in Unit::SelectHostileTarget, if no more target exists */ - virtual void EnterEvadeMode() {} + virtual void EnterEvadeMode() { m_creature->ResetPlayerDamageReq(); } /** * Called at reaching home after MoveTargetedHome diff --git a/src/game/Object/CreatureEventAI.cpp b/src/game/Object/CreatureEventAI.cpp index 0ff406a0..b9a1967f 100644 --- a/src/game/Object/CreatureEventAI.cpp +++ b/src/game/Object/CreatureEventAI.cpp @@ -1163,6 +1163,7 @@ void CreatureEventAI::EnterEvadeMode() if (i->Event.event_type == EVENT_T_EVADE) { ProcessEvent(*i); } } + m_creature->ResetPlayerDamageReq(); } void CreatureEventAI::JustDied(Unit* killer) diff --git a/src/game/Object/Player.cpp b/src/game/Object/Player.cpp index 134ea99e..0a4ad4ec 100644 --- a/src/game/Object/Player.cpp +++ b/src/game/Object/Player.cpp @@ -14071,8 +14071,8 @@ bool Player::IsTappedByMeOrMyGroup(Creature* creature) * Called from Object::BuildValuesUpdate */ bool Player::isAllowedToLoot(Creature* creature) { - /* Nobody tapped the monster (solo kill by another NPC) */ - if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED)) + /* Nobody tapped the monster (kill either solo or mostly by another NPC) */ + if (!creature->HasFlag(UNIT_DYNAMIC_FLAGS, UNIT_DYNFLAG_TAPPED) || !creature->IsDamageEnoughForLootingAndReward()) { return false; } /* If we there is a loot recipient, assign it to recipient */ diff --git a/src/game/Object/Unit.cpp b/src/game/Object/Unit.cpp index 0bf808c0..792a1341 100644 --- a/src/game/Object/Unit.cpp +++ b/src/game/Object/Unit.cpp @@ -631,8 +631,14 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa { SetContestedPvP(attackedPlayer); } } - if (pVictim->GetTypeId() == TYPEID_UNIT && !((Creature*)pVictim)->IsPet() && !((Creature*)pVictim)->HasLootRecipient()) - { ((Creature*)pVictim)->SetLootRecipient(this); } + if (Creature* victim = pVictim->ToCreature()) + { + if (!victim->IsPet() && !victim->HasLootRecipient()) + victim->SetLootRecipient(this); + + if (IsControlledByPlayer()) // more narrow: IsPet(), IsGuardian() ? + victim->LowerPlayerDamageReq(health < damage ? health : damage); + } if (health <= damage) { @@ -681,23 +687,36 @@ uint32 Unit::DealDamage(Unit* pVictim, uint32 damage, CleanDamage const* cleanDa /* * Generic Actions (ProcEvents, Combat-Log, Kill Rewards, Stop Combat) */ + bool isRewardAllowed = true; + if (Creature* creature = pVictim->ToCreature()) + { + isRewardAllowed = creature->IsDamageEnoughForLootingAndReward(); + if (!isRewardAllowed) + creature->SetLootRecipient(NULL); + } + // call kill spell proc event (before real die and combat stop to triggering auras removed at death/combat stop) if (player_tap && player_tap != pVictim) { player_tap->ProcDamageAndSpell(pVictim, PROC_FLAG_KILL, PROC_FLAG_KILLED, PROC_EX_NONE, 0); - WorldPacket data(SMSG_PARTYKILLLOG, (8 + 8)); // send event PARTY_KILL - data << player_tap->GetObjectGuid(); // player with killing blow - data << pVictim->GetObjectGuid(); // victim + if (isRewardAllowed) + { + WorldPacket data(SMSG_PARTYKILLLOG, (8 + 8)); // send event PARTY_KILL + data << player_tap->GetObjectGuid(); // player with killing blow + data << pVictim->GetObjectGuid(); // victim - if (group_tap) - { group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid()); } + if (group_tap) + { + group_tap->BroadcastPacket(&data, false, group_tap->GetMemberGroup(player_tap->GetObjectGuid()), player_tap->GetObjectGuid()); + } - player_tap->SendDirectMessage(&data); + player_tap->SendDirectMessage(&data); + } } // Reward player, his pets, and group/raid members - if (player_tap != pVictim) + if (isRewardAllowed && player_tap != pVictim) { if (group_tap) { group_tap->RewardGroupAtKill(pVictim, player_tap); } diff --git a/src/game/WorldHandlers/Spell.cpp b/src/game/WorldHandlers/Spell.cpp index d3f2e9dd..607fd4a6 100644 --- a/src/game/WorldHandlers/Spell.cpp +++ b/src/game/WorldHandlers/Spell.cpp @@ -962,6 +962,9 @@ void Spell::DoAllEffectOnTarget(TargetInfo* target) { DoSpellHitOnUnit(m_caster, mask, true); unitTarget = m_caster; + + if (m_caster->GetTypeId() == TYPEID_UNIT) + m_caster->ToCreature()->LowerPlayerDamageReq(target->damage); } } else // in 1.12.1 we need explicit miss info