mirror of
https://github.com/liyunfan1223/azerothcore-wotlk.git
synced 2026-08-08 15:58:04 +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_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_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),
|
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_regenTimer = CREATURE_REGEN_INTERVAL;
|
||||||
m_valuesCount = UNIT_END;
|
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);
|
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)
|
if (_playerDamageReq)
|
||||||
_playerDamageReq > unDamage ? _playerDamageReq -= unDamage : _playerDamageReq = 0;
|
_playerDamageReq > unDamage ? _playerDamageReq -= unDamage : _playerDamageReq = 0;
|
||||||
@@ -3845,12 +3845,16 @@ void Creature::LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer /*= tr
|
|||||||
{
|
{
|
||||||
_damagedByPlayer = damagedByPlayer;
|
_damagedByPlayer = damagedByPlayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (attackerLevel > _highestPlayerAttackerLevel)
|
||||||
|
_highestPlayerAttackerLevel = attackerLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Creature::ResetPlayerDamageReq()
|
void Creature::ResetPlayerDamageReq()
|
||||||
{
|
{
|
||||||
_playerDamageReq = GetHealth() / 2;
|
_playerDamageReq = GetHealth() / 2;
|
||||||
_damagedByPlayer = false;
|
_damagedByPlayer = false;
|
||||||
|
_highestPlayerAttackerLevel = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 Creature::GetPlayerDamageReq() const
|
uint32 Creature::GetPlayerDamageReq() const
|
||||||
|
|||||||
@@ -380,9 +380,10 @@ public:
|
|||||||
void SetLootRewardDisabled(bool disable) { DisableLootReward = disable; }
|
void SetLootRewardDisabled(bool disable) { DisableLootReward = disable; }
|
||||||
[[nodiscard]] bool IsLootRewardDisabled() const { return DisableLootReward; }
|
[[nodiscard]] bool IsLootRewardDisabled() const { return DisableLootReward; }
|
||||||
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
|
[[nodiscard]] bool IsDamageEnoughForLootingAndReward() const;
|
||||||
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true);
|
void LowerPlayerDamageReq(uint32 unDamage, bool damagedByPlayer = true, uint8 attackerLevel = 0);
|
||||||
void ResetPlayerDamageReq();
|
void ResetPlayerDamageReq();
|
||||||
[[nodiscard]] uint32 GetPlayerDamageReq() const;
|
[[nodiscard]] uint32 GetPlayerDamageReq() const;
|
||||||
|
[[nodiscard]] uint8 GetHighestPlayerAttackerLevel() const { return _highestPlayerAttackerLevel; }
|
||||||
|
|
||||||
[[nodiscard]] uint32 GetOriginalEntry() const { return m_originalEntry; }
|
[[nodiscard]] uint32 GetOriginalEntry() const { return m_originalEntry; }
|
||||||
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
void SetOriginalEntry(uint32 entry) { m_originalEntry = entry; }
|
||||||
@@ -554,6 +555,7 @@ private:
|
|||||||
|
|
||||||
uint32 _playerDamageReq;
|
uint32 _playerDamageReq;
|
||||||
bool _damagedByPlayer;
|
bool _damagedByPlayer;
|
||||||
|
uint8 _highestPlayerAttackerLevel;
|
||||||
bool _isCombatMovementAllowed;
|
bool _isCombatMovementAllowed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "KillRewarder.h"
|
#include "KillRewarder.h"
|
||||||
|
#include "Creature.h"
|
||||||
#include "Formulas.h"
|
#include "Formulas.h"
|
||||||
#include "Group.h"
|
#include "Group.h"
|
||||||
#include "Pet.h"
|
#include "Pet.h"
|
||||||
@@ -161,6 +162,19 @@ void KillRewarder::_RewardXP(Player* player, float rate)
|
|||||||
else
|
else
|
||||||
xp = 0;
|
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)
|
if (xp)
|
||||||
{
|
{
|
||||||
// 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT).
|
// 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;
|
uint32 unDamage = health < damage ? health : damage;
|
||||||
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr
|
bool damagedByPlayer = unDamage && attacker && (attacker->IsPlayer() || attacker->m_movedByPlayer != nullptr
|
||||||
|| attacker->GetCharmerGUID().IsPlayer());
|
|| 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