mirror of
https://github.com/liyunfan1223/azerothcore-wotlk.git
synced 2026-08-04 22:07:52 +00:00
fix(Core/XP): Reduce XP when ungrouped high-level player helps kill (#25161)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Ludwig <sudlud@users.noreply.github.com>
This commit is contained in:
@@ -264,7 +264,7 @@ Creature::Creature(): Unit(), MovableMapObject(), m_groupLootTimer(0), lootingGr
|
||||
m_spawnId(0), m_equipmentId(0), m_originalEquipmentId(0), m_alreadyCallForHelp(false), m_AlreadyCallAssistance(false),
|
||||
m_AlreadySearchedAssistance(false), m_regenHealth(true), m_regenPower(true), m_AI_locked(false), m_meleeDamageSchoolMask(SPELL_SCHOOL_MASK_NORMAL), m_originalEntry(0), _gossipMenuId(0), m_moveInLineOfSightDisabled(false), m_moveInLineOfSightStrictlyDisabled(false),
|
||||
m_homePosition(), m_transportHomePosition(), m_creatureInfo(nullptr), m_creatureData(nullptr), m_detectionDistance(20.0f),_sparringPct(0.0f), m_waypointID(0), m_path_id(0), m_formation(nullptr), m_lastLeashExtensionTime(nullptr),
|
||||
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _isCombatMovementAllowed(true)
|
||||
_isMissingSwimmingFlagOutOfCombat(false), m_assistanceTimer(0), _playerDamageReq(0), _damagedByPlayer(false), _highestPlayerAttackerLevel(0), _isCombatMovementAllowed(true)
|
||||
{
|
||||
m_regenTimer = CREATURE_REGEN_INTERVAL;
|
||||
m_valuesCount = UNIT_END;
|
||||
@@ -3836,7 +3836,7 @@ bool Creature::IsDamageEnoughForLootingAndReward() const
|
||||
return m_creatureInfo->HasFlagsExtra(CREATURE_FLAG_EXTRA_NO_PLAYER_DAMAGE_REQ) || (_playerDamageReq == 0 && _damagedByPlayer);
|
||||
}
|
||||
|
||||
void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= true*/)
|
||||
void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= true*/, uint8 attackerLevel /*= 0*/)
|
||||
{
|
||||
if (_playerDamageReq)
|
||||
_playerDamageReq > unDamage ? _playerDamageReq -= unDamage : _playerDamageReq = 0;
|
||||
@@ -3845,12 +3845,16 @@ void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= tr
|
||||
{
|
||||
_damagedByPlayer = damagedByPlayer;
|
||||
}
|
||||
|
||||
if (attackerLevel > _highestPlayerAttackerLevel)
|
||||
_highestPlayerAttackerLevel = attackerLevel;
|
||||
}
|
||||
|
||||
void Creature::ResetPlayerDamageReq()
|
||||
{
|
||||
_playerDamageReq = GetHealth() / 2;
|
||||
_damagedByPlayer = false;
|
||||
_highestPlayerAttackerLevel = 0;
|
||||
}
|
||||
|
||||
uint32 Creature::GetPlayerDamageReq() const
|
||||
|
||||
@@ -380,9 +380,10 @@ public:
|
||||
void SetLootRewardDisabled(bool disable) { DisableLootReward = disable; }
|
||||
[[nodiscard]] bool IsLootRewardDisabled() const { return DisableLootReward; }
|
||||
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
|
||||
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true);
|
||||
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true, uint8 attackerLevel = 0);
|
||||
void ResetPlayerDamageReq();
|
||||
[[nodiscard]] uint32 GetPlayerDamageReq() const;
|
||||
[[nodiscard]] uint8 GetHighestPlayerAttackerLevel() const { return _highestPlayerAttackerLevel; }
|
||||
|
||||
[[nodiscard]] uint32 GetOriginalEntry() const { return m_originalEntry; }
|
||||
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
||||
@@ -554,6 +555,7 @@ private:
|
||||
|
||||
uint32 _playerDamageReq;
|
||||
bool _damagedByPlayer;
|
||||
uint8 _highestPlayerAttackerLevel;
|
||||
bool _isCombatMovementAllowed;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
*/
|
||||
|
||||
#include "KillRewarder.h"
|
||||
#include "Creature.h"
|
||||
#include "Formulas.h"
|
||||
#include "Group.h"
|
||||
#include "Pet.h"
|
||||
@@ -161,6 +162,19 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
||||
else
|
||||
xp = 0;
|
||||
}
|
||||
|
||||
// An ungrouped helper who out-levels everyone eligible for the kill and for
|
||||
// whom the victim is gray halves the tagger's XP, matching the group
|
||||
// gray-member penalty. Closes a power-leveling exploit.
|
||||
if (xp)
|
||||
if (Creature* creature = _victim->ToCreature())
|
||||
{
|
||||
uint8 const referenceLevel = _group ? _maxLevel : player->GetLevel();
|
||||
uint8 const highestLevel = creature->GetHighestPlayerAttackerLevel();
|
||||
if (highestLevel > referenceLevel && creature->GetLevel() <= Acore::XP::GetGrayLevel(highestLevel))
|
||||
xp = xp / 2 + 1;
|
||||
}
|
||||
|
||||
if (xp)
|
||||
{
|
||||
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
|
||||
|
||||
@@ -1233,7 +1233,18 @@ uint32 Unit::DealDamage(Unit* attacker, Unit* victim, uint32 damage, CleanDamage
|
||||
uint32 unDamage = health < damage ? health : damage;
|
||||
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr
|
||||
|| attacker->GetCharmerGUID().IsPlayer());
|
||||
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer);
|
||||
|
||||
uint8 attackerLevel = 0;
|
||||
if (damagedByPlayer)
|
||||
{
|
||||
Player* attackerPlayer = attacker->GetCharmerOrOwnerPlayerOrPlayerItself();
|
||||
if (!attackerPlayer && attacker->m_movedByPlayer)
|
||||
attackerPlayer = attacker->m_movedByPlayer->ToPlayer();
|
||||
if (attackerPlayer)
|
||||
attackerLevel = attackerPlayer->GetLevel();
|
||||
}
|
||||
|
||||
victim->ToCreature()->LowerPlayerDamageReq(unDamage, damagedByPlayer, attackerLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user