TrinityCore
Loading...
Searching...
No Matches
KillRewarder.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "KillRewarder.h"
19#include "Creature.h"
20#include "DB2Stores.h"
21#include "FlatSet.h"
22#include "Formulas.h"
23#include "Group.h"
24#include "Guild.h"
25#include "GuildMgr.h"
26#include "Pet.h"
27#include "Player.h"
28#include "Scenario.h"
29#include "SpellAuraEffects.h"
30#include <boost/container/small_vector.hpp>
31
32 // == KillRewarder ====================================================
33 // KillRewarder encapsulates logic of rewarding player upon kill with:
34 // * XP;
35 // * honor;
36 // * reputation;
37 // * kill credit (for quest objectives).
38 // Rewarding is initiated in two cases: when player kills unit in Unit::Kill()
39 // and on battlegrounds in Battleground::RewardXPAtKill().
40 //
41 // Rewarding algorithm is:
42 // 1. Initialize internal variables to default values.
43 // 2. In case when player is in group, initialize variables necessary for group calculations:
44 // 2.1. _count - number of alive group members within reward distance;
45 // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
46 // 2.3. _maxLevel - maximum level of alive group member within reward distance;
47 // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
48 // for whom victim is not gray;
49 // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
50 // so 100% XP will be rewarded (50% otherwise).
51 // 3. Reward killer (and group, if necessary).
52 // 3.1. If killer is in group, reward group.
53 // 3.1.1. Initialize initial XP amount based on maximum level of group member,
54 // for whom victim is not gray.
55 // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
56 // 3.1.3. Reward each group member (even dead) within reward distance (see 4. for more details).
57 // 3.2. Reward single killer (not group case).
58 // 3.2.1. Initialize initial XP amount based on killer's level.
59 // 3.2.2. Reward killer (see 4. for more details).
60 // 4. Reward player.
61 // 4.1. Give honor (player must be alive and not on BG).
62 // 4.2. Give XP.
63 // 4.2.1. If player is in group, adjust XP:
64 // * set to 0 if player's level is more than maximum level of not gray member;
65 // * cut XP in half if _isFullXP is false.
66 // 4.2.2. Apply auras modifying rewarded XP.
67 // 4.2.3. Give XP to player.
68 // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
69 // 4.3. Give reputation (player must not be on BG).
70 // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
71 // 5. Credit instance encounter.
72 // 6. Update guild achievements.
73 // 7. Scenario credit
74
75KillRewarder::KillRewarder(Trinity::IteratorPair<Player**> killers, Unit* victim, bool isBattleGround) :
76 // 1. Initialize internal variables to default values.
77 _killers(killers), _victim(victim),
78 _groupRate(1.0f), _maxNotGrayMember(nullptr), _count(0), _sumLevel(0), _xp(0),
79 _isFullXP(false), _maxLevel(0), _isBattleGround(isBattleGround), _isPvP(false)
80{
81 // mark the credit as pvp if victim is player
82 if (victim->GetTypeId() == TYPEID_PLAYER)
83 _isPvP = true;
84 // or if its owned by player and its not a vehicle
85 else if (victim->GetCharmerOrOwnerGUID().IsPlayer())
86 _isPvP = !victim->IsVehicle();
87}
88
89inline void KillRewarder::_InitGroupData(Player const* killer)
90{
91 if (Group const* group = killer->GetGroup())
92 {
93 // 2. In case when player is in group, initialize variables necessary for group calculations:
94 for (GroupReference const& itr : group->GetMembers())
95 {
96 Player* member = itr.GetSource();
97 if (killer == member || (member->IsAtGroupRewardDistance(_victim) && member->IsAlive()))
98 {
99 const uint8 lvl = member->GetLevel();
100 // 2.1. _count - number of alive group members within reward distance;
101 ++_count;
102 // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
103 _sumLevel += lvl;
104 // 2.3. _maxLevel - maximum level of alive group member within reward distance;
105 if (_maxLevel < lvl)
106 _maxLevel = lvl;
107 // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
108 // for whom victim is not gray;
109 uint32 grayLevel = Trinity::XP::GetGrayLevel(lvl);
110 if (_victim->GetLevelForTarget(member) > grayLevel && (!_maxNotGrayMember || _maxNotGrayMember->GetLevel() < lvl))
111 _maxNotGrayMember = member;
112 }
113 }
114 // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
115 // so 100% XP will be rewarded (50% otherwise).
117 }
118 else
119 _count = 1;
120}
121
122inline void KillRewarder::_InitXP(Player* player, Player const* killer)
123{
124 // Get initial value of XP for kill.
125 // XP is given:
126 // * on battlegrounds;
127 // * otherwise, not in PvP;
128 // * not if killer is on vehicle.
129 if (_isBattleGround || (!_isPvP && !killer->GetVehicle()))
131}
132
134{
135 // Rewarded player must be alive.
136 if (player->IsAlive())
138}
139
140inline void KillRewarder::_RewardXP(Player* player, float rate)
141{
142 uint32 xp(_xp);
143 if (player->GetGroup())
144 {
145 // 4.2.1. If player is in group, adjust XP:
146 // * set to 0 if player's level is more than maximum level of not gray member;
147 // * cut XP in half if _isFullXP is false.
148 if (_maxNotGrayMember && player->IsAlive() &&
149 _maxNotGrayMember->GetLevel() >= player->GetLevel())
150 xp = _isFullXP ?
151 uint32(xp * rate) : // Reward FULL XP if all group members are not gray.
152 uint32(xp * rate / 2) + 1; // Reward only HALF of XP if some of group members are gray.
153 else
154 xp = 0;
155 }
156 if (xp)
157 {
158 // 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT and SPELL_AURA_MOD_XP_FROM_CREATURE_TYPE).
161
162 // 4.2.3. Give XP to player.
163 player->GiveXP(xp, _victim, _groupRate);
164 if (Pet* pet = player->GetPet())
165 // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
166 pet->GivePetXP(player->GetGroup() ? xp / 2 : xp);
167 }
168}
169
170inline void KillRewarder::_RewardReputation(Player* player, float rate)
171{
172 // 4.3. Give reputation (player must not be on BG).
173 // Even dead players and corpses are rewarded.
174 player->RewardReputation(_victim, rate);
175}
176
178{
179 // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
180 if (!player->GetGroup() || player->IsAlive() || !player->GetCorpse())
181 {
182 if (Creature* target = _victim->ToCreature())
183 {
184 player->KilledMonster(target);
185 player->UpdateCriteria(CriteriaType::KillAnyCreature, target->GetCreatureType(), 1, 0, target);
186 }
187 }
188}
189
190void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
191{
192 // 4. Reward player.
193 if (!_isBattleGround)
194 {
195 // 4.1. Give honor (player must be alive and not on BG).
196 _RewardHonor(player);
197 // 4.1.1 Send player killcredit for quests with PlayerSlain
200 }
201 // Give XP only in PvE or in battlegrounds.
202 // Give reputation and kill credit only in PvE.
203 if (!_isPvP || _isBattleGround)
204 {
205 float const rate = player->GetGroup() ?
206 _groupRate * float(player->GetLevel()) / _sumLevel : // Group rate depends on summary level.
207 1.0f; // Personal rate is 100%.
208 if (_xp)
209 // 4.2. Give XP.
210 _RewardXP(player, rate);
211 if (!_isBattleGround)
212 {
213 // If killer is in dungeon then all members receive full reputation at kill.
214 _RewardReputation(player, isDungeon ? 1.0f : rate);
215 _RewardKillCredit(player);
216 }
217 }
218}
219
220void KillRewarder::_RewardGroup(Group const* group, Player const* killer)
221{
222 if (_maxLevel)
223 {
225 // 3.1.1. Initialize initial XP amount based on maximum level of group member,
226 // for whom victim is not gray.
227 _InitXP(_maxNotGrayMember, killer);
228 // To avoid unnecessary calculations and calls,
229 // proceed only if XP is not ZERO or player is not on battleground
230 // (battleground rewards only XP, that's why).
231 if (!_isBattleGround || _xp)
232 {
233 bool const isDungeon = !_isPvP && sMapStore.LookupEntry(killer->GetMapId())->IsDungeon();
234 if (!_isBattleGround)
235 {
236 // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
237 bool const isRaid = !_isPvP && sMapStore.LookupEntry(killer->GetMapId())->IsRaid() && group->isRaidGroup();
239 }
240
241 // 3.1.3. Reward each group member (even dead or corpse) within reward distance.
242 for (GroupReference const& itr : group->GetMembers())
243 {
244 Player* member = itr.GetSource();
245 // Killer may not be at reward distance, check directly
246 if (killer == member || member->IsAtGroupRewardDistance(_victim))
247 _RewardPlayer(member, isDungeon);
248 }
249 }
250 }
251}
252
254{
255 Trinity::Containers::FlatSet<Group const*, std::less<>, boost::container::small_vector<Group const*, 3>> processedGroups;
256 for (Player* killer : _killers)
257 {
258 _InitGroupData(killer);
259
260 // 3. Reward killer (and group, if necessary).
261 if (Group* group = killer->GetGroup())
262 {
263 if (!processedGroups.insert(group).second)
264 continue;
265
266 // 3.1. If killer is in group, reward group.
267 _RewardGroup(group, killer);
268 }
269 else
270 {
271 // 3.2. Reward single killer (not group case).
272 // 3.2.1. Initialize initial XP amount based on killer's level.
273 _InitXP(killer, killer);
274 // To avoid unnecessary calculations and calls,
275 // proceed only if XP is not ZERO or player is not on battleground
276 // (battleground rewards only XP, that's why).
277 if (!_isBattleGround || _xp)
278 // 3.2.2. Reward killer.
279 _RewardPlayer(killer, false);
280 }
281 }
282
283 // 5. Credit instance encounter.
284 // 6. Update guild achievements.
285 // 7. Credit scenario criterias
286 if (Creature* victim = _victim->ToCreature())
287 {
288 if (_killers.begin() != _killers.end())
289 {
290 if (ObjectGuid::LowType guildId = victim->GetMap()->GetOwnerGuildId())
291 if (Guild* guild = sGuildMgr->GetGuildById(guildId))
292 guild->UpdateCriteria(CriteriaType::KillCreature, victim->GetEntry(), 1, 0, victim, *_killers.begin());
293
294 if (Scenario* scenario = victim->GetScenario())
295 scenario->UpdateCriteria(CriteriaType::KillCreature, victim->GetEntry(), 1, 0, victim, *_killers.begin());
296 }
297 }
298}
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
uint8_t uint8
Definition Define.h:156
int32_t int32
Definition Define.h:150
uint32_t uint32
Definition Define.h:154
#define sGuildMgr
Definition GuildMgr.h:76
@ TYPEID_PLAYER
Definition ObjectGuid.h:44
@ SPELL_AURA_MOD_XP_FROM_CREATURE_TYPE
@ SPELL_AURA_MOD_XP_PCT
ObjectGuid const & GetGUID() const
Definition BaseEntity.h:163
TypeID GetTypeId() const
Definition BaseEntity.h:166
Definition Group.h:205
GroupRefManager & GetMembers()
Definition Group.h:332
bool isRaidGroup() const
Definition Group.cpp:1628
Definition Guild.h:329
void _InitGroupData(Player const *killer)
KillRewarder(Trinity::IteratorPair< Player ** > killers, Unit *victim, bool isBattleGround)
void _RewardGroup(Group const *group, Player const *killer)
void _RewardHonor(Player *player)
void _RewardPlayer(Player *player, bool isDungeon)
Trinity::IteratorPair< Player ** > _killers
void _RewardReputation(Player *player, float rate)
uint32 _sumLevel
Player * _maxNotGrayMember
bool _isBattleGround
void _InitXP(Player *player, Player const *killer)
void _RewardXP(Player *player, float rate)
void _RewardKillCredit(Player *player)
bool IsPlayer() const
Definition ObjectGuid.h:369
uint64 LowType
Definition ObjectGuid.h:321
Creature * ToCreature()
Definition Object.h:121
Definition Pet.h:40
void KilledMonster(Creature const *creature)
Definition Player.cpp:16663
bool RewardHonor(Unit *victim, uint32 groupsize, int32 honor=-1, HonorGainSource source=HonorGainSource::Kill)
Definition Player.cpp:6763
void GiveXP(uint32 xp, Unit *victim, float group_rate=1.0f)
Definition Player.cpp:2199
Pet * GetPet() const
Definition Player.cpp:22060
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition Player.cpp:26434
void KilledPlayerCredit(ObjectGuid victimGuid)
Definition Player.cpp:16697
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition Player.cpp:27588
Corpse * GetCorpse() const
Definition Player.cpp:4562
void RewardReputation(Unit *victim, float rate)
Definition Player.cpp:6630
Group * GetGroup(Optional< uint8 > partyIndex)
Definition Player.h:2796
std::pair< iterator, bool > insert(Key const &key)
Definition FlatSet.h:82
Utility class to enable range for loop syntax for multimap.equal_range uses.
constexpr end_iterator end() const
constexpr iterator begin() const
Definition Unit.h:635
bool IsVehicle() const
Definition Unit.h:754
Vehicle * GetVehicle() const
Definition Unit.h:1784
bool IsAlive() const
Definition Unit.h:1185
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition Unit.h:1216
float GetTotalAuraMultiplier(AuraType auraType) const
Definition Unit.cpp:5074
uint32 GetCreatureType() const
Definition Unit.cpp:9451
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition Unit.cpp:5139
uint8 GetLevelForTarget(WorldObject const *) const override
Definition Unit.h:759
uint8 GetLevel() const
Definition Unit.h:757
constexpr uint32 GetMapId() const
Definition Position.h:216
uint32 Gain(Player *player, Unit *u, bool isBattleGround=false)
Definition Formulas.h:181
float xp_in_group_rate(uint32 count, bool isRaid)
Definition Formulas.h:221
uint8 GetGrayLevel(uint8 pl_level)
Definition Formulas.h:70