Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
BattlePet.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "BattlePet.h"
7#include "Common.h"
8#include "DB2Enums.h"
9#include "DB2Stores.h"
10#include "DBCStores.h"
11
12#include <algorithm>
13#include <cmath>
14#include <unordered_map>
15
16namespace
17{
18 enum BattlePetAbilityEffectProperties
19 {
20 BATTLE_PET_EFFECT_DAMAGE = 24,
21 BATTLE_PET_EFFECT_RAMPING_DAMAGE = 27,
22 BATTLE_PET_EFFECT_DAMAGE_TOGGLE_AURA = 76,
23 BATTLE_PET_EFFECT_DAMAGE_HIT_STATE = 96,
24 BATTLE_PET_EFFECT_EXTRA_ATTACK_FIRST = 103,
25 BATTLE_PET_EFFECT_DAMAGE_NON_LETHAL = 149
26 };
27
28 typedef std::unordered_map<uint32, BattlePetAbilityEffectEntry const*> BattlePetAbilityEffectByTurnCache;
29 typedef std::unordered_map<uint64, int32> BattlePetAbilityStateCache;
30 typedef std::unordered_map<uint32, uint16> BattlePetSpeciesByNpcCache;
31
32 bool BattlePetAbilityEffectDealsDamage(uint32 propertiesId)
33 {
34 switch (propertiesId)
35 {
36 case BATTLE_PET_EFFECT_DAMAGE:
37 case BATTLE_PET_EFFECT_RAMPING_DAMAGE:
38 case BATTLE_PET_EFFECT_DAMAGE_TOGGLE_AURA:
39 case BATTLE_PET_EFFECT_DAMAGE_HIT_STATE:
40 case BATTLE_PET_EFFECT_EXTRA_ATTACK_FIRST:
41 case BATTLE_PET_EFFECT_DAMAGE_NON_LETHAL:
42 return true;
43 default:
44 return false;
45 }
46 }
47
48 BattlePetSpeciesByNpcCache const& BattlePetSpeciesByNpc()
49 {
50 static BattlePetSpeciesByNpcCache speciesByNpc;
51 if (!speciesByNpc.empty())
52 return speciesByNpc;
53
54 for (uint32 speciesId = 0; speciesId < sBattlePetSpeciesStore.GetNumRows(); ++speciesId)
55 {
56 BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(speciesId);
57 if (speciesEntry && speciesEntry->NpcId)
58 speciesByNpc[speciesEntry->NpcId] = uint16(speciesId);
59 }
60
61 return speciesByNpc;
62 }
63
64 void BuildBattlePetAbilityEffectCaches(BattlePetAbilityEffectByTurnCache& firstEffectByTurn,
65 BattlePetAbilityEffectByTurnCache& firstDamageEffectByTurn)
66 {
67 if (!firstEffectByTurn.empty())
68 return;
69
70 for (uint32 i = 0; i < sBattlePetAbilityEffectStore.GetNumRows(); ++i)
71 {
72 BattlePetAbilityEffectEntry const* effectEntry = sBattlePetAbilityEffectStore.LookupEntry(i);
73 if (!effectEntry)
74 continue;
75
76 if (firstEffectByTurn.find(effectEntry->TurnEntryId) == firstEffectByTurn.end())
77 firstEffectByTurn[effectEntry->TurnEntryId] = effectEntry;
78
79 if (BattlePetAbilityEffectDealsDamage(effectEntry->PropertiesId)
80 && firstDamageEffectByTurn.find(effectEntry->TurnEntryId) == firstDamageEffectByTurn.end())
81 firstDamageEffectByTurn[effectEntry->TurnEntryId] = effectEntry;
82 }
83 }
84
85 BattlePetAbilityEffectEntry const* BattlePetAbilityEffectForTurn(uint32 turnId, bool damageOnly)
86 {
87 static BattlePetAbilityEffectByTurnCache firstEffectByTurn;
88 static BattlePetAbilityEffectByTurnCache firstDamageEffectByTurn;
89 BuildBattlePetAbilityEffectCaches(firstEffectByTurn, firstDamageEffectByTurn);
90
91 BattlePetAbilityEffectByTurnCache::const_iterator itr = firstDamageEffectByTurn.find(turnId);
92 if (itr != firstDamageEffectByTurn.end())
93 return itr->second;
94
95 if (damageOnly)
96 return nullptr;
97
98 itr = firstEffectByTurn.find(turnId);
99 return itr != firstEffectByTurn.end() ? itr->second : nullptr;
100 }
101
102 uint64 BattlePetAbilityStateKey(uint32 abilityId, uint32 stateId)
103 {
104 return (uint64(abilityId) << 32) | stateId;
105 }
106
107 BattlePetAbilityStateCache const& BattlePetAbilityStates()
108 {
109 static BattlePetAbilityStateCache abilityStates;
110 if (!abilityStates.empty())
111 return abilityStates;
112
113 for (uint32 i = 0; i < sBattlePetAbilityStateStore.GetNumRows(); ++i)
114 {
115 BattlePetAbilityStateEntry const* stateEntry = sBattlePetAbilityStateStore.LookupEntry(i);
116 if (stateEntry)
117 abilityStates[BattlePetAbilityStateKey(stateEntry->AbilityId, stateEntry->StateId)] = int32(stateEntry->Value);
118 }
119
120 return abilityStates;
121 }
122}
123
125{
126 if (!maxHealth || !percent)
127 return 0;
128
129 if (percent >= 100)
130 return maxHealth;
131
132 return uint16(std::min<uint32>(maxHealth, (uint32(maxHealth) * percent + 99) / 100));
133}
134
136{
137 if (!level || level >= BATTLE_PET_MAX_LEVEL)
138 return 0;
139
140 uint32 const levelIndex = uint32(level) - 1;
141 GtBattlePetXpEntry const* base = sGtBattlePetXpStore.LookupEntry(100 + levelIndex);
142 GtBattlePetXpEntry const* multiplier = sGtBattlePetXpStore.LookupEntry(levelIndex);
143 if (base && multiplier)
144 {
145 float const threshold = base->value * multiplier->value;
146 if (threshold > 0.0f)
147 return uint16(std::min<uint32>(uint32(threshold + 0.5f), 0xFFFF));
148 }
149
150 return uint16(level) * 100;
151}
152
153uint16 BattlePetExperienceReward(uint8 petLevel, uint8 enemyLevel, uint8 participatingPetCount)
154{
155 if (!petLevel || !enemyLevel || !participatingPetCount || petLevel >= BATTLE_PET_MAX_LEVEL)
156 return 0;
157
158 int32 levelDifference = int32(enemyLevel) - int32(petLevel);
159 levelDifference = std::min<int32>(levelDifference, 2);
160 levelDifference = std::max<int32>(levelDifference, -4);
161
162 uint32 const reward = (uint32(enemyLevel) + 9) * uint32(levelDifference + 5);
163 return uint16(std::min<uint32>(reward / participatingPetCount, 0xFFFF));
164}
165
167{
168 if (!level)
169 return 1;
170
171 return std::min<uint8>(level, BATTLE_PET_MAX_LEVEL);
172}
173
175{
176 return (flags & BATTLE_PET_FLAG_NOT_TAMEABLE) == 0;
177}
178
180{
181 if (!npcId)
182 return 0;
183
184 BattlePetSpeciesByNpcCache const& speciesByNpc = BattlePetSpeciesByNpc();
185 BattlePetSpeciesByNpcCache::const_iterator itr = speciesByNpc.find(npcId);
186 return itr != speciesByNpc.end() ? itr->second : 0;
187}
188
190{
191 BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(speciesId);
192 return speciesEntry ? speciesEntry->NpcId : 0;
193}
194
196{
197 BattlePetSpeciesEntry const* speciesEntry = sBattlePetSpeciesStore.LookupEntry(speciesId);
198 if (!speciesEntry || speciesEntry->FamilyId >= 32)
199 return 0;
200
201 return uint32(1) << speciesEntry->FamilyId;
202}
203
205{
206 std::pair<BattlePetAbilityTurnByAbilityStore::const_iterator, BattlePetAbilityTurnByAbilityStore::const_iterator> turnRange =
207 sBattlePetAbilityTurnByAbilityStore.equal_range(abilityId);
208
209 BattlePetAbilityEffectEntry const* firstEffect = nullptr;
210
211 for (BattlePetAbilityTurnByAbilityStore::const_iterator itr = turnRange.first; itr != turnRange.second; ++itr)
212 {
213 BattlePetAbilityEffectEntry const* effectEntry = BattlePetAbilityEffectForTurn(itr->second.first, damageOnly);
214 if (!effectEntry)
215 continue;
216
217 if (damageOnly || BattlePetAbilityEffectDealsDamage(effectEntry->PropertiesId))
218 return effectEntry;
219
220 if (!firstEffect)
221 firstEffect = effectEntry;
222 }
223
224 return damageOnly ? nullptr : firstEffect;
225}
226
228{
229 BattlePetAbilityStateCache const& abilityStates = BattlePetAbilityStates();
230 BattlePetAbilityStateCache::const_iterator itr = abilityStates.find(BattlePetAbilityStateKey(abilityId, stateId));
231 return itr != abilityStates.end() ? itr->second : 0;
232}
233
235{
236 BattlePetAbilityEffectEntry const* damageEffect = BattlePetAbilityEffectForAbility(abilityId, true);
237 return damageEffect ? damageEffect->PropertyValues[0] : 0;
238}
239
241{
242 if (!points)
243 return 0;
244
245 uint32 const safeLevel = std::max<uint32>(level, 1);
246 uint32 const safePower = std::max<uint32>(power, safeLevel * 8);
247 uint32 const powerBonusPct = (safePower * 5) / 100;
248 uint32 const scaledPoints = points + ((points * powerBonusPct) / 100);
249 return std::max<uint32>(1, scaledPoints);
250}
251
253{
254 if (!abilityId)
255 return 0;
256
257 return BattlePetScalePointsFromStats(BattlePetAbilityBasePoints(abilityId), power, level);
258}
259
261{
262 if (!species)
263 return level * 8;
264
265 float const basePower = BattlePetSpeciesMainStat(BATTLE_PET_STATE_STAT_POWER, species) +
267 float const qualityMod = BattlePetQualityMultiplier(quality);
268 return uint16(std::max<float>(1.0f, std::floor((basePower * std::max<uint8>(level, 1) * qualityMod) + 0.5f)));
269}
270
272{
273 if (!abilityId)
274 return 0;
275
276 if (!caster)
277 return BattlePetDamageFromStats(abilityId, 0, 1);
278
279 return BattlePetDamageFromStats(abilityId, caster->GetPower(), caster->GetLevel());
280}
281
283{
284 BattlePetAbilityEntry const* abilityEntry = sBattlePetAbilityStore.LookupEntry(abilityId);
285 if (!abilityEntry || !abilityEntry->AuraAbilityId)
286 return 0;
287
288 int32 const stateValue = BattlePetAbilityStateValue(
290 if (stateValue >= 0)
291 return 0;
292
293 return BattlePetScalePointsFromStats(uint32(std::abs(stateValue)), power, level);
294}
295
297{
298 BattlePetAbilityEntry const* abilityEntry = sBattlePetAbilityStore.LookupEntry(abilityId);
299 if (!abilityEntry || !abilityEntry->AuraAbilityId)
300 return 0;
301
302 return uint8(std::min<uint32>(abilityEntry->AuraDuration, 255));
303}
304
306{
307 if (!abilityId)
308 return 0;
309
310 if (!caster)
311 return BattlePetIncomingDamageReductionFromStats(abilityId, 0, 1);
312
313 return BattlePetIncomingDamageReductionFromStats(abilityId, caster->GetPower(), caster->GetLevel());
314}
315
317{
318 BattlePetAbilityEntry const* abilityEntry = sBattlePetAbilityStore.LookupEntry(abilityId);
319 if (!abilityEntry)
320 return 0;
321
322 return uint16(abilityEntry->Cooldown);
323}
324
326{
327 BattlePetAbilityEffectEntry const* effectEntry = BattlePetAbilityEffectForAbility(abilityId, false);
328 return effectEntry ? effectEntry->Id : 0;
329}
330
331void BattlePet::CalculateStats(bool currentHealth)
332{
339
340 float qualityMod = BattlePetQualityMultiplier(m_quality);
341
342 // No round in older cpp, just for compatibility
343 m_maxHealth = floor(((baseHealth * 5.0f * m_level * qualityMod) + 100.0f) + 0.5f);
344
345 if (currentHealth)
347
348 m_power = floor((basePower * m_level * qualityMod) + 0.5f);
349 m_speed = floor((baseSpeed * m_level * qualityMod) + 0.5f);
350
352}
353
354void BattlePet::SetNickname(std::string const& nickname)
355{
356 m_nickname = nickname;
358}
359
361{
362 if (m_timestamp == timestamp)
363 return;
364
365 m_timestamp = timestamp;
367}
368
370{
371 m_quality = quality;
372 CalculateStats(false);
373}
374
376{
377 if (m_xp == xp)
378 return;
379
380 m_xp = xp;
382}
383
385{
386 uint16 const newHealth = std::min<uint16>(health, m_maxHealth);
387 if (m_curHealth == newHealth)
388 return;
389
390 m_curHealth = newHealth;
392}
393
395{
396 if (HasFlag(flag))
397 return;
398
399 m_flags |= flag;
401}
402
404{
405 if (!HasFlag(flag))
406 return;
407
408 m_flags &= ~flag;
410}
411
413{
414 if (!level)
415 level = 1;
416 else if (level > BATTLE_PET_MAX_LEVEL)
417 level = BATTLE_PET_MAX_LEVEL;
418
419 if (m_level == level)
420 return;
421
422 m_level = level;
423 CalculateStats(true);
424}
425
427{
428 if (!xp || m_level >= BATTLE_PET_MAX_LEVEL)
429 return 0;
430
431 uint32 remainingXp = uint32(m_xp) + xp;
433 {
435 if (!nextLevelXp || remainingXp < nextLevelXp)
436 break;
437
438 remainingXp -= nextLevelXp;
439 SetLevel(m_level + 1);
440 }
441
443 remainingXp = 0;
444
445 SetXp(uint16(std::min<uint32>(remainingXp, 0xFFFF)));
446 return xp;
447}
uint32 BattlePetInputEffectForAbility(uint32 abilityId)
bool BattlePetSpeciesFlagsAllowWildCapture(uint32 flags)
uint8 BattlePetNormalizeWildLevel(uint8 level)
int32 BattlePetAbilityStateValue(uint32 abilityId, uint32 stateId)
BattlePetAbilityEffectEntry const * BattlePetAbilityEffectForAbility(uint32 abilityId, bool damageOnly)
uint16 BattlePetExperienceReward(uint8 petLevel, uint8 enemyLevel, uint8 participatingPetCount)
uint32 BattlePetAbilityBasePoints(uint32 abilityId)
uint16 BattlePetSpeciesIdByNpcId(uint32 npcId)
uint32 BattlePetDamageFromStats(uint32 abilityId, uint16 power, uint8 level)
uint8 BattlePetIncomingDamageReductionRounds(uint32 abilityId)
uint16 BattlePetHealthFromPercent(uint16 maxHealth, uint8 percent)
uint32 BattlePetInputIncomingDamageReductionForAbility(uint32 abilityId, BattlePet const *caster)
uint16 BattlePetAbilityCooldown(uint32 abilityId)
uint16 BattlePetExperienceForNextLevel(uint8 level)
uint16 BattlePetPowerFromBattleState(uint16 species, uint8 level, uint8 quality, uint8 breed)
uint32 BattlePetScalePointsFromStats(uint32 points, uint16 power, uint8 level)
uint32 BattlePetInputDamageForAbility(uint32 abilityId, BattlePet const *caster)
uint32 BattlePetIncomingDamageReductionFromStats(uint32 abilityId, uint16 power, uint8 level)
uint32 BattlePetSpeciesFamilyMask(uint16 speciesId)
uint32 BattlePetSpeciesNpcId(uint16 speciesId)
#define BATTLE_PET_MAX_LEVEL
Definition BattlePet.h:12
@ BATTLE_PET_STATE_STAT_STAMINA
Definition BattlePet.h:153
@ BATTLE_PET_STATE_STAT_SPEED
Definition BattlePet.h:154
@ BATTLE_PET_STATE_STAT_POWER
Definition BattlePet.h:152
@ BATTLE_PET_STATE_DAMAGE_TAKEN_FLAT
Definition BattlePet.h:155
uint16 BattlePetExperienceForNextLevel(uint8 level)
@ BATTLE_PET_FLAG_NOT_TAMEABLE
Definition DB2Enums.h:17
DB2Storage< BattlePetAbilityEntry > sBattlePetAbilityStore(BattlePetAbilityfmt)
float BattlePetSpeciesMainStat(uint16 stateId, uint16 speciesId)
DB2Storage< BattlePetAbilityStateEntry > sBattlePetAbilityStateStore(BattlePetAbilityStatefmt)
float BattlePetBreedMainStatModifier(uint16 stateId, uint8 breedId)
float BattlePetQualityMultiplier(uint8 quality)
DB2Storage< BattlePetSpeciesEntry > sBattlePetSpeciesStore(BattlePetSpeciesfmt)
BattlePetAbilityTurnByAbilityStore sBattlePetAbilityTurnByAbilityStore
Definition DB2Stores.cpp:49
DB2Storage< BattlePetAbilityEffectEntry > sBattlePetAbilityEffectStore(BattlePetAbilityEffectfmt)
DBCStorage< GtBattlePetXpEntry > sGtBattlePetXpStore(GtBattlePetXpfmt)
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::uint64_t uint64
Definition Define.h:76
std::uint16_t uint16
Definition Define.h:78
ItemQualities
BattlePetDbState m_dbState
Definition BattlePet.h:261
uint16 m_flags
Definition BattlePet.h:259
void SetFlag(uint16 flag)
void SetNickname(std::string const &nickname)
bool HasFlag(uint16 flag) const
Definition BattlePet.h:238
std::string m_nickname
Definition BattlePet.h:249
void UnSetFlag(uint16 flag)
uint8 m_level
Definition BattlePet.h:251
void SetLevel(uint8 level)
uint8 GetLevel() const
Definition BattlePet.h:219
void CalculateStats(bool currentHealth=false)
uint16 m_speed
Definition BattlePet.h:256
uint8 m_breed
Definition BattlePet.h:258
void SetCurrentHealth(uint16 health)
uint16 m_curHealth
Definition BattlePet.h:253
uint32 m_timestamp
Definition BattlePet.h:250
uint16 m_power
Definition BattlePet.h:255
uint16 m_species
Definition BattlePet.h:248
void SetXp(uint16 xp)
uint16 GetPower() const
Definition BattlePet.h:223
uint16 m_maxHealth
Definition BattlePet.h:254
void SetTimestamp(uint32 timestamp)
uint8 m_quality
Definition BattlePet.h:257
void SetQuality(ItemQualities quality)
uint16 m_xp
Definition BattlePet.h:252
uint16 AddExperience(uint16 xp)
uint32 TurnEntryId
uint32 PropertiesId
uint32 Id
uint32 PropertyValues[MAX_BATTLE_PET_EFFECT_PROPERTIES]
uint32 AuraAbilityId
uint32 Cooldown
uint32 AuraDuration
uint32 StateId
uint32 AbilityId
uint32 Value
uint32 FamilyId
uint32 NpcId
float value