TrinityCore
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->GetFirstMember(); itr != nullptr; itr = itr->next())
95 {
96 if (Player* member = itr->GetSource())
97 {
98 if (killer == member || (member->IsAtGroupRewardDistance(_victim) && member->IsAlive()))
99 {
100 const uint8 lvl = member->GetLevel();
101 // 2.1. _count - number of alive group members within reward distance;
102 ++_count;
103 // 2.2. _sumLevel - sum of levels of alive group members within reward distance;
104 _sumLevel += lvl;
105 // 2.3. _maxLevel - maximum level of alive group member within reward distance;
106 if (_maxLevel < lvl)
107 _maxLevel = lvl;
108 // 2.4. _maxNotGrayMember - maximum level of alive group member within reward distance,
109 // for whom victim is not gray;
110 uint32 grayLevel = Trinity::XP::GetGrayLevel(lvl);
111 if (_victim->GetLevelForTarget(member) > grayLevel && (!_maxNotGrayMember || _maxNotGrayMember->GetLevel() < lvl))
112 _maxNotGrayMember = member;
113 }
114 }
115 }
116 // 2.5. _isFullXP - flag identifying that for all group members victim is not gray,
117 // so 100% XP will be rewarded (50% otherwise).
119 }
120 else
121 _count = 1;
122}
123
124inline void KillRewarder::_InitXP(Player* player, Player const* killer)
125{
126 // Get initial value of XP for kill.
127 // XP is given:
128 // * on battlegrounds;
129 // * otherwise, not in PvP;
130 // * not if killer is on vehicle.
131 if (_isBattleGround || (!_isPvP && !killer->GetVehicle()))
133}
134
136{
137 // Rewarded player must be alive.
138 if (player->IsAlive())
139 player->RewardHonor(_victim, _count, -1, true);
140}
141
142inline void KillRewarder::_RewardXP(Player* player, float rate)
143{
144 uint32 xp(_xp);
145 if (player->GetGroup())
146 {
147 // 4.2.1. If player is in group, adjust XP:
148 // * set to 0 if player's level is more than maximum level of not gray member;
149 // * cut XP in half if _isFullXP is false.
150 if (_maxNotGrayMember && player->IsAlive() &&
151 _maxNotGrayMember->GetLevel() >= player->GetLevel())
152 xp = _isFullXP ?
153 uint32(xp * rate) : // Reward FULL XP if all group members are not gray.
154 uint32(xp * rate / 2) + 1; // Reward only HALF of XP if some of group members are gray.
155 else
156 xp = 0;
157 }
158 if (xp)
159 {
160 // 4.2.2. Apply auras modifying rewarded XP (SPELL_AURA_MOD_XP_PCT and SPELL_AURA_MOD_XP_FROM_CREATURE_TYPE).
163
164 // 4.2.3. Give XP to player.
165 player->GiveXP(xp, _victim, _groupRate);
166 if (Pet* pet = player->GetPet())
167 // 4.2.4. If player has pet, reward pet with XP (100% for single player, 50% for group case).
168 pet->GivePetXP(player->GetGroup() ? xp / 2 : xp);
169 }
170}
171
172inline void KillRewarder::_RewardReputation(Player* player, float rate)
173{
174 // 4.3. Give reputation (player must not be on BG).
175 // Even dead players and corpses are rewarded.
176 player->RewardReputation(_victim, rate);
177}
178
180{
181 // 4.4. Give kill credit (player must not be in group, or he must be alive or without corpse).
182 if (!player->GetGroup() || player->IsAlive() || !player->GetCorpse())
183 {
184 if (Creature* target = _victim->ToCreature())
185 {
186 player->KilledMonster(target->GetCreatureTemplate(), target->GetGUID());
187 player->UpdateCriteria(CriteriaType::KillAnyCreature, target->GetCreatureType(), 1, 0, target);
188 }
189 }
190}
191
192void KillRewarder::_RewardPlayer(Player* player, bool isDungeon)
193{
194 // 4. Reward player.
195 if (!_isBattleGround)
196 {
197 // 4.1. Give honor (player must be alive and not on BG).
198 _RewardHonor(player);
199 // 4.1.1 Send player killcredit for quests with PlayerSlain
202 }
203 // Give XP only in PvE or in battlegrounds.
204 // Give reputation and kill credit only in PvE.
205 if (!_isPvP || _isBattleGround)
206 {
207 float const rate = player->GetGroup() ?
208 _groupRate * float(player->GetLevel()) / _sumLevel : // Group rate depends on summary level.
209 1.0f; // Personal rate is 100%.
210 if (_xp)
211 // 4.2. Give XP.
212 _RewardXP(player, rate);
213 if (!_isBattleGround)
214 {
215 // If killer is in dungeon then all members receive full reputation at kill.
216 _RewardReputation(player, isDungeon ? 1.0f : rate);
217 _RewardKillCredit(player);
218 }
219 }
220}
221
222void KillRewarder::_RewardGroup(Group const* group, Player const* killer)
223{
224 if (_maxLevel)
225 {
227 // 3.1.1. Initialize initial XP amount based on maximum level of group member,
228 // for whom victim is not gray.
229 _InitXP(_maxNotGrayMember, killer);
230 // To avoid unnecessary calculations and calls,
231 // proceed only if XP is not ZERO or player is not on battleground
232 // (battleground rewards only XP, that's why).
233 if (!_isBattleGround || _xp)
234 {
235 bool const isDungeon = !_isPvP && sMapStore.LookupEntry(killer->GetMapId())->IsDungeon();
236 if (!_isBattleGround)
237 {
238 // 3.1.2. Alter group rate if group is in raid (not for battlegrounds).
239 bool const isRaid = !_isPvP && sMapStore.LookupEntry(killer->GetMapId())->IsRaid() && group->isRaidGroup();
241 }
242
243 // 3.1.3. Reward each group member (even dead or corpse) within reward distance.
244 for (GroupReference const* itr = group->GetFirstMember(); itr != nullptr; itr = itr->next())
245 {
246 if (Player* member = itr->GetSource())
247 {
248 // Killer may not be at reward distance, check directly
249 if (killer == member || member->IsAtGroupRewardDistance(_victim))
250 {
251 _RewardPlayer(member, isDungeon);
252 }
253 }
254 }
255 }
256 }
257}
258
260{
261 Trinity::Containers::FlatSet<Group const*, std::less<>, boost::container::small_vector<Group const*, 3>> processedGroups;
262 for (Player* killer : _killers)
263 {
264 _InitGroupData(killer);
265
266 // 3. Reward killer (and group, if necessary).
267 if (Group* group = killer->GetGroup())
268 {
269 if (!processedGroups.insert(group).second)
270 continue;
271
272 // 3.1. If killer is in group, reward group.
273 _RewardGroup(group, killer);
274 }
275 else
276 {
277 // 3.2. Reward single killer (not group case).
278 // 3.2.1. Initialize initial XP amount based on killer's level.
279 _InitXP(killer, killer);
280 // To avoid unnecessary calculations and calls,
281 // proceed only if XP is not ZERO or player is not on battleground
282 // (battleground rewards only XP, that's why).
283 if (!_isBattleGround || _xp)
284 // 3.2.2. Reward killer.
285 _RewardPlayer(killer, false);
286 }
287 }
288
289 // 5. Credit instance encounter.
290 // 6. Update guild achievements.
291 // 7. Credit scenario criterias
292 if (Creature* victim = _victim->ToCreature())
293 {
294 if (_killers.begin() != _killers.end())
295 {
296 if (ObjectGuid::LowType guildId = victim->GetMap()->GetOwnerGuildId())
297 if (Guild* guild = sGuildMgr->GetGuildById(guildId))
298 guild->UpdateCriteria(CriteriaType::KillCreature, victim->GetEntry(), 1, 0, victim, *_killers.begin());
299
300 if (Scenario* scenario = victim->GetScenario())
301 scenario->UpdateCriteria(CriteriaType::KillCreature, victim->GetEntry(), 1, 0, victim, *_killers.begin());
302 }
303 }
304}
DB2Storage< MapEntry > sMapStore("Map.db2", &MapLoadInfo::Instance)
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
uint32_t uint32
Definition: Define.h:142
#define sGuildMgr
Definition: GuildMgr.h:70
@ TYPEID_PLAYER
Definition: ObjectGuid.h:41
@ SPELL_AURA_MOD_XP_FROM_CREATURE_TYPE
@ SPELL_AURA_MOD_XP_PCT
GroupReference * next()
Definition: Group.h:197
GroupReference * GetFirstMember()
Definition: Group.h:325
bool isRaidGroup() const
Definition: Group.cpp:1638
Definition: Guild.h:329
uint8 _maxLevel
Definition: KillRewarder.h:54
void _InitGroupData(Player const *killer)
uint32 _count
Definition: KillRewarder.h:50
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
Definition: KillRewarder.h:46
float _groupRate
Definition: KillRewarder.h:48
void _RewardReputation(Player *player, float rate)
uint32 _sumLevel
Definition: KillRewarder.h:51
Player * _maxNotGrayMember
Definition: KillRewarder.h:49
Unit * _victim
Definition: KillRewarder.h:47
bool _isBattleGround
Definition: KillRewarder.h:55
void _InitXP(Player *player, Player const *killer)
void _RewardXP(Player *player, float rate)
void _RewardKillCredit(Player *player)
bool IsPlayer() const
Definition: ObjectGuid.h:326
uint64 LowType
Definition: ObjectGuid.h:278
static Creature * ToCreature(Object *o)
Definition: Object.h:219
TypeID GetTypeId() const
Definition: Object.h:173
static ObjectGuid GetGUID(Object const *o)
Definition: Object.h:159
Definition: Pet.h:40
void GiveXP(uint32 xp, Unit *victim, float group_rate=1.0f)
Definition: Player.cpp:2210
Pet * GetPet() const
Definition: Player.cpp:21513
bool IsAtGroupRewardDistance(WorldObject const *pRewardSource) const
Definition: Player.cpp:25673
void KilledMonster(CreatureTemplate const *cInfo, ObjectGuid guid)
Definition: Player.cpp:16668
void KilledPlayerCredit(ObjectGuid victimGuid)
Definition: Player.cpp:16698
void UpdateCriteria(CriteriaType type, uint64 miscValue1=0, uint64 miscValue2=0, uint64 miscValue3=0, WorldObject *ref=nullptr)
Definition: Player.cpp:26767
Corpse * GetCorpse() const
Definition: Player.cpp:4606
void RewardReputation(Unit *victim, float rate)
Definition: Player.cpp:6593
bool RewardHonor(Unit *victim, uint32 groupsize, int32 honor=-1, bool pvptoken=false)
Definition: Player.cpp:6726
Group * GetGroup(Optional< uint8 > partyIndex)
Definition: Player.h:2606
std::pair< iterator, bool > insert(Key const &key)
Definition: FlatSet.h:73
constexpr end_iterator end() const
Definition: IteratorPair.h:39
constexpr iterator begin() const
Definition: IteratorPair.h:38
Definition: Unit.h:627
bool IsVehicle() const
Definition: Unit.h:743
Vehicle * GetVehicle() const
Definition: Unit.h:1713
bool IsAlive() const
Definition: Unit.h:1164
ObjectGuid GetCharmerOrOwnerGUID() const override
Definition: Unit.h:1195
float GetTotalAuraMultiplier(AuraType auraType) const
Definition: Unit.cpp:4934
uint32 GetCreatureType() const
Definition: Unit.cpp:8880
float GetTotalAuraMultiplierByMiscValue(AuraType auraType, int32 misc_value) const
Definition: Unit.cpp:4999
uint8 GetLevelForTarget(WorldObject const *) const override
Definition: Unit.h:747
uint8 GetLevel() const
Definition: Unit.h:746
constexpr uint32 GetMapId() const
Definition: Position.h:201
uint32 Gain(Player *player, Unit *u, bool isBattleGround=false)
Definition: Formulas.h:177
float xp_in_group_rate(uint32 count, bool isRaid)
Definition: Formulas.h:217
uint8 GetGrayLevel(uint8 pl_level)
Definition: Formulas.h:66