1 | /* |
---|
2 | * Copyright (C) 2005-2008 MaNGOS <http://www.mangosproject.org/> |
---|
3 | * |
---|
4 | * Copyright (C) 2008 Trinity <http://www.trinitycore.org/> |
---|
5 | * |
---|
6 | * This program is free software; you can redistribute it and/or modify |
---|
7 | * it under the terms of the GNU General Public License as published by |
---|
8 | * the Free Software Foundation; either version 2 of the License, or |
---|
9 | * (at your option) any later version. |
---|
10 | * |
---|
11 | * This program is distributed in the hope that it will be useful, |
---|
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | * GNU General Public License for more details. |
---|
15 | * |
---|
16 | * You should have received a copy of the GNU General Public License |
---|
17 | * along with this program; if not, write to the Free Software |
---|
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
19 | */ |
---|
20 | |
---|
21 | #include "Unit.h" |
---|
22 | #include "Player.h" |
---|
23 | #include "Pet.h" |
---|
24 | #include "Creature.h" |
---|
25 | #include "SharedDefines.h" |
---|
26 | #include "SpellAuras.h" |
---|
27 | |
---|
28 | /*####################################### |
---|
29 | ######## ######## |
---|
30 | ######## PLAYERS STAT SYSTEM ######## |
---|
31 | ######## ######## |
---|
32 | #######################################*/ |
---|
33 | |
---|
34 | bool Player::UpdateStats(Stats stat) |
---|
35 | { |
---|
36 | if(stat > STAT_SPIRIT) |
---|
37 | return false; |
---|
38 | |
---|
39 | // value = ((base_value * base_pct) + total_value) * total_pct |
---|
40 | float value = GetTotalStatValue(stat); |
---|
41 | |
---|
42 | SetStat(stat, int32(value)); |
---|
43 | |
---|
44 | if(stat == STAT_STAMINA || stat == STAT_INTELLECT) |
---|
45 | { |
---|
46 | Pet *pet = GetPet(); |
---|
47 | if(pet) |
---|
48 | pet->UpdateStats(stat); |
---|
49 | } |
---|
50 | |
---|
51 | switch(stat) |
---|
52 | { |
---|
53 | case STAT_STRENGTH: |
---|
54 | UpdateAttackPowerAndDamage(); |
---|
55 | UpdateShieldBlockValue(); |
---|
56 | break; |
---|
57 | case STAT_AGILITY: |
---|
58 | UpdateArmor(); |
---|
59 | UpdateAttackPowerAndDamage(true); |
---|
60 | if(getClass() == CLASS_ROGUE || getClass() == CLASS_HUNTER || getClass() == CLASS_DRUID && m_form==FORM_CAT) |
---|
61 | UpdateAttackPowerAndDamage(); |
---|
62 | |
---|
63 | UpdateAllCritPercentages(); |
---|
64 | UpdateDodgePercentage(); |
---|
65 | break; |
---|
66 | |
---|
67 | case STAT_STAMINA: UpdateMaxHealth(); break; |
---|
68 | case STAT_INTELLECT: |
---|
69 | UpdateMaxPower(POWER_MANA); |
---|
70 | UpdateAllSpellCritChances(); |
---|
71 | UpdateAttackPowerAndDamage(true); //SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT, only intelect currently |
---|
72 | UpdateArmor(); //SPELL_AURA_MOD_RESISTANCE_OF_INTELLECT_PERCENT, only armor currently |
---|
73 | break; |
---|
74 | |
---|
75 | case STAT_SPIRIT: |
---|
76 | break; |
---|
77 | |
---|
78 | default: |
---|
79 | break; |
---|
80 | } |
---|
81 | UpdateSpellDamageAndHealingBonus(); |
---|
82 | UpdateManaRegen(); |
---|
83 | return true; |
---|
84 | } |
---|
85 | |
---|
86 | void Player::UpdateSpellDamageAndHealingBonus() |
---|
87 | { |
---|
88 | // Magic damage modifiers implemented in Unit::SpellDamageBonus |
---|
89 | // This information for client side use only |
---|
90 | // Get healing bonus for all schools |
---|
91 | SetStatInt32Value(PLAYER_FIELD_MOD_HEALING_DONE_POS, SpellBaseHealingBonus(SPELL_SCHOOL_MASK_ALL)); |
---|
92 | // Get damage bonus for all schools |
---|
93 | for(int i = SPELL_SCHOOL_HOLY; i < MAX_SPELL_SCHOOL; i++) |
---|
94 | SetStatInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS+i, SpellBaseDamageBonus(SpellSchoolMask(1 << i))); |
---|
95 | } |
---|
96 | |
---|
97 | bool Player::UpdateAllStats() |
---|
98 | { |
---|
99 | for (int i = STAT_STRENGTH; i < MAX_STATS; i++) |
---|
100 | { |
---|
101 | float value = GetTotalStatValue(Stats(i)); |
---|
102 | SetStat(Stats(i), (int32)value); |
---|
103 | } |
---|
104 | |
---|
105 | UpdateAttackPowerAndDamage(); |
---|
106 | UpdateAttackPowerAndDamage(true); |
---|
107 | UpdateArmor(); |
---|
108 | UpdateMaxHealth(); |
---|
109 | |
---|
110 | for(int i = POWER_MANA; i < MAX_POWERS; i++) |
---|
111 | UpdateMaxPower(Powers(i)); |
---|
112 | |
---|
113 | UpdateAllCritPercentages(); |
---|
114 | UpdateAllSpellCritChances(); |
---|
115 | UpdateDefenseBonusesMod(); |
---|
116 | UpdateShieldBlockValue(); |
---|
117 | UpdateSpellDamageAndHealingBonus(); |
---|
118 | UpdateManaRegen(); |
---|
119 | UpdateExpertise(BASE_ATTACK); |
---|
120 | UpdateExpertise(OFF_ATTACK); |
---|
121 | for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) |
---|
122 | UpdateResistances(i); |
---|
123 | |
---|
124 | return true; |
---|
125 | } |
---|
126 | |
---|
127 | void Player::UpdateResistances(uint32 school) |
---|
128 | { |
---|
129 | if(school > SPELL_SCHOOL_NORMAL) |
---|
130 | { |
---|
131 | float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); |
---|
132 | SetResistance(SpellSchools(school), int32(value)); |
---|
133 | |
---|
134 | Pet *pet = GetPet(); |
---|
135 | if(pet) |
---|
136 | pet->UpdateResistances(school); |
---|
137 | } |
---|
138 | else |
---|
139 | UpdateArmor(); |
---|
140 | } |
---|
141 | |
---|
142 | void Player::UpdateArmor() |
---|
143 | { |
---|
144 | float value = 0.0f; |
---|
145 | UnitMods unitMod = UNIT_MOD_ARMOR; |
---|
146 | |
---|
147 | value = GetModifierValue(unitMod, BASE_VALUE); // base armor (from items) |
---|
148 | value *= GetModifierValue(unitMod, BASE_PCT); // armor percent from items |
---|
149 | value += GetStat(STAT_AGILITY) * 2.0f; // armor bonus from stats |
---|
150 | value += GetModifierValue(unitMod, TOTAL_VALUE); |
---|
151 | |
---|
152 | //add dynamic flat mods |
---|
153 | AuraList const& mResbyIntellect = GetAurasByType(SPELL_AURA_MOD_RESISTANCE_OF_STAT_PERCENT); |
---|
154 | for(AuraList::const_iterator i = mResbyIntellect.begin();i != mResbyIntellect.end(); ++i) |
---|
155 | { |
---|
156 | Modifier* mod = (*i)->GetModifier(); |
---|
157 | if(mod->m_miscvalue & SPELL_SCHOOL_MASK_NORMAL) |
---|
158 | value += int32(GetStat(Stats((*i)->GetMiscBValue())) * mod->m_amount / 100.0f); |
---|
159 | } |
---|
160 | |
---|
161 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
162 | |
---|
163 | SetArmor(int32(value)); |
---|
164 | |
---|
165 | Pet *pet = GetPet(); |
---|
166 | if(pet) |
---|
167 | pet->UpdateArmor(); |
---|
168 | } |
---|
169 | |
---|
170 | float Player::GetHealthBonusFromStamina() |
---|
171 | { |
---|
172 | float stamina = GetStat(STAT_STAMINA); |
---|
173 | |
---|
174 | float baseStam = stamina < 20 ? stamina : 20; |
---|
175 | float moreStam = stamina - baseStam; |
---|
176 | |
---|
177 | return baseStam + (moreStam*10.0f); |
---|
178 | } |
---|
179 | |
---|
180 | float Player::GetManaBonusFromIntellect() |
---|
181 | { |
---|
182 | float intellect = GetStat(STAT_INTELLECT); |
---|
183 | |
---|
184 | float baseInt = intellect < 20 ? intellect : 20; |
---|
185 | float moreInt = intellect - baseInt; |
---|
186 | |
---|
187 | return baseInt + (moreInt*15.0f); |
---|
188 | } |
---|
189 | |
---|
190 | void Player::UpdateMaxHealth() |
---|
191 | { |
---|
192 | UnitMods unitMod = UNIT_MOD_HEALTH; |
---|
193 | |
---|
194 | float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); |
---|
195 | value *= GetModifierValue(unitMod, BASE_PCT); |
---|
196 | value += GetModifierValue(unitMod, TOTAL_VALUE) + GetHealthBonusFromStamina(); |
---|
197 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
198 | |
---|
199 | SetMaxHealth((uint32)value); |
---|
200 | } |
---|
201 | |
---|
202 | void Player::UpdateMaxPower(Powers power) |
---|
203 | { |
---|
204 | UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); |
---|
205 | |
---|
206 | float bonusPower = (power == POWER_MANA) ? GetManaBonusFromIntellect() : 0; |
---|
207 | |
---|
208 | float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); |
---|
209 | value *= GetModifierValue(unitMod, BASE_PCT); |
---|
210 | value += GetModifierValue(unitMod, TOTAL_VALUE) + bonusPower; |
---|
211 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
212 | |
---|
213 | SetMaxPower(power, uint32(value)); |
---|
214 | } |
---|
215 | |
---|
216 | void Player::UpdateAttackPowerAndDamage(bool ranged ) |
---|
217 | { |
---|
218 | float val2 = 0.0f; |
---|
219 | float level = float(getLevel()); |
---|
220 | |
---|
221 | UnitMods unitMod = ranged ? UNIT_MOD_ATTACK_POWER_RANGED : UNIT_MOD_ATTACK_POWER; |
---|
222 | |
---|
223 | uint16 index = UNIT_FIELD_ATTACK_POWER; |
---|
224 | uint16 index_mod = UNIT_FIELD_ATTACK_POWER_MODS; |
---|
225 | uint16 index_mult = UNIT_FIELD_ATTACK_POWER_MULTIPLIER; |
---|
226 | |
---|
227 | if(ranged) |
---|
228 | { |
---|
229 | index = UNIT_FIELD_RANGED_ATTACK_POWER; |
---|
230 | index_mod = UNIT_FIELD_RANGED_ATTACK_POWER_MODS; |
---|
231 | index_mult = UNIT_FIELD_RANGED_ATTACK_POWER_MULTIPLIER; |
---|
232 | |
---|
233 | switch(getClass()) |
---|
234 | { |
---|
235 | case CLASS_HUNTER: val2 = level * 2.0f + GetStat(STAT_AGILITY) - 10.0f; break; |
---|
236 | case CLASS_ROGUE: val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; |
---|
237 | case CLASS_WARRIOR:val2 = level + GetStat(STAT_AGILITY) - 10.0f; break; |
---|
238 | case CLASS_DRUID: |
---|
239 | switch(m_form) |
---|
240 | { |
---|
241 | case FORM_CAT: |
---|
242 | case FORM_BEAR: |
---|
243 | case FORM_DIREBEAR: |
---|
244 | val2 = 0.0f; break; |
---|
245 | default: |
---|
246 | val2 = GetStat(STAT_AGILITY) - 10.0f; break; |
---|
247 | } |
---|
248 | break; |
---|
249 | default: val2 = GetStat(STAT_AGILITY) - 10.0f; break; |
---|
250 | } |
---|
251 | } |
---|
252 | else |
---|
253 | { |
---|
254 | switch(getClass()) |
---|
255 | { |
---|
256 | case CLASS_WARRIOR: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
257 | case CLASS_PALADIN: val2 = level*3.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
258 | case CLASS_ROGUE: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; |
---|
259 | case CLASS_HUNTER: val2 = level*2.0f + GetStat(STAT_STRENGTH) + GetStat(STAT_AGILITY) - 20.0f; break; |
---|
260 | case CLASS_SHAMAN: val2 = level*2.0f + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
261 | case CLASS_DRUID: |
---|
262 | { |
---|
263 | //Check if Predatory Strikes is skilled |
---|
264 | float mLevelMult = 0.0; |
---|
265 | switch(m_form) |
---|
266 | { |
---|
267 | case FORM_CAT: |
---|
268 | case FORM_BEAR: |
---|
269 | case FORM_DIREBEAR: |
---|
270 | case FORM_MOONKIN: |
---|
271 | { |
---|
272 | Unit::AuraList const& mDummy = GetAurasByType(SPELL_AURA_DUMMY); |
---|
273 | for(Unit::AuraList::const_iterator itr = mDummy.begin(); itr != mDummy.end(); ++itr) |
---|
274 | { |
---|
275 | // Predatory Strikes |
---|
276 | if ((*itr)->GetSpellProto()->SpellIconID == 1563) |
---|
277 | { |
---|
278 | mLevelMult = (*itr)->GetModifier()->m_amount / 100.0f; |
---|
279 | break; |
---|
280 | } |
---|
281 | } |
---|
282 | break; |
---|
283 | } |
---|
284 | } |
---|
285 | |
---|
286 | switch(m_form) |
---|
287 | { |
---|
288 | case FORM_CAT: |
---|
289 | val2 = getLevel()*(mLevelMult+2.0f) + GetStat(STAT_STRENGTH)*2.0f + GetStat(STAT_AGILITY) - 20.0f; break; |
---|
290 | case FORM_BEAR: |
---|
291 | case FORM_DIREBEAR: |
---|
292 | val2 = getLevel()*(mLevelMult+3.0f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
293 | case FORM_MOONKIN: |
---|
294 | val2 = getLevel()*(mLevelMult+1.5f) + GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
295 | default: |
---|
296 | val2 = GetStat(STAT_STRENGTH)*2.0f - 20.0f; break; |
---|
297 | } |
---|
298 | break; |
---|
299 | } |
---|
300 | case CLASS_MAGE: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; |
---|
301 | case CLASS_PRIEST: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; |
---|
302 | case CLASS_WARLOCK: val2 = GetStat(STAT_STRENGTH) - 10.0f; break; |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | SetModifierValue(unitMod, BASE_VALUE, val2); |
---|
307 | |
---|
308 | float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); |
---|
309 | float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); |
---|
310 | |
---|
311 | //add dynamic flat mods |
---|
312 | if( ranged && (getClassMask() & CLASSMASK_WAND_USERS)==0) |
---|
313 | { |
---|
314 | AuraList const& mRAPbyIntellect = GetAurasByType(SPELL_AURA_MOD_RANGED_ATTACK_POWER_OF_STAT_PERCENT); |
---|
315 | for(AuraList::const_iterator i = mRAPbyIntellect.begin();i != mRAPbyIntellect.end(); ++i) |
---|
316 | attPowerMod += int32(GetStat(Stats((*i)->GetModifier()->m_miscvalue)) * (*i)->GetModifier()->m_amount / 100.0f); |
---|
317 | } |
---|
318 | |
---|
319 | float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; |
---|
320 | |
---|
321 | SetUInt32Value(index, (uint32)base_attPower); //UNIT_FIELD_(RANGED)_ATTACK_POWER field |
---|
322 | SetUInt32Value(index_mod, (uint32)attPowerMod); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field |
---|
323 | SetFloatValue(index_mult, attPowerMultiplier); //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field |
---|
324 | |
---|
325 | //automatically update weapon damage after attack power modification |
---|
326 | if(ranged) |
---|
327 | { |
---|
328 | UpdateDamagePhysical(RANGED_ATTACK); |
---|
329 | |
---|
330 | Pet *pet = GetPet(); //update pet's AP |
---|
331 | if(pet) |
---|
332 | pet->UpdateAttackPowerAndDamage(); |
---|
333 | } |
---|
334 | else |
---|
335 | { |
---|
336 | UpdateDamagePhysical(BASE_ATTACK); |
---|
337 | if(CanDualWield() && haveOffhandWeapon()) //allow update offhand damage only if player knows DualWield Spec and has equipped offhand weapon |
---|
338 | UpdateDamagePhysical(OFF_ATTACK); |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | void Player::UpdateShieldBlockValue() |
---|
343 | { |
---|
344 | SetUInt32Value(PLAYER_SHIELD_BLOCK, GetShieldBlockValue()); |
---|
345 | } |
---|
346 | |
---|
347 | void Player::CalculateMinMaxDamage(WeaponAttackType attType, bool normalized, float& min_damage, float& max_damage) |
---|
348 | { |
---|
349 | UnitMods unitMod; |
---|
350 | UnitMods attPower; |
---|
351 | |
---|
352 | switch(attType) |
---|
353 | { |
---|
354 | case BASE_ATTACK: |
---|
355 | default: |
---|
356 | unitMod = UNIT_MOD_DAMAGE_MAINHAND; |
---|
357 | attPower = UNIT_MOD_ATTACK_POWER; |
---|
358 | break; |
---|
359 | case OFF_ATTACK: |
---|
360 | unitMod = UNIT_MOD_DAMAGE_OFFHAND; |
---|
361 | attPower = UNIT_MOD_ATTACK_POWER; |
---|
362 | break; |
---|
363 | case RANGED_ATTACK: |
---|
364 | unitMod = UNIT_MOD_DAMAGE_RANGED; |
---|
365 | attPower = UNIT_MOD_ATTACK_POWER_RANGED; |
---|
366 | break; |
---|
367 | } |
---|
368 | |
---|
369 | float att_speed = GetAPMultiplier(attType,normalized); |
---|
370 | |
---|
371 | float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; |
---|
372 | float base_pct = GetModifierValue(unitMod, BASE_PCT); |
---|
373 | float total_value = GetModifierValue(unitMod, TOTAL_VALUE); |
---|
374 | float total_pct = GetModifierValue(unitMod, TOTAL_PCT); |
---|
375 | |
---|
376 | float weapon_mindamage = GetWeaponDamageRange(attType, MINDAMAGE); |
---|
377 | float weapon_maxdamage = GetWeaponDamageRange(attType, MAXDAMAGE); |
---|
378 | |
---|
379 | if (IsInFeralForm()) //check if player is druid and in cat or bear forms |
---|
380 | { |
---|
381 | uint32 lvl = getLevel(); |
---|
382 | if ( lvl > 60 ) lvl = 60; |
---|
383 | |
---|
384 | weapon_mindamage = lvl*0.85*att_speed; |
---|
385 | weapon_maxdamage = lvl*1.25*att_speed; |
---|
386 | } |
---|
387 | else if(!IsUseEquipedWeapon(attType==BASE_ATTACK)) //check if player not in form but still can't use weapon (broken/etc) |
---|
388 | { |
---|
389 | weapon_mindamage = BASE_MINDAMAGE; |
---|
390 | weapon_maxdamage = BASE_MAXDAMAGE; |
---|
391 | } |
---|
392 | else if(attType == RANGED_ATTACK) //add ammo DPS to ranged damage |
---|
393 | { |
---|
394 | weapon_mindamage += GetAmmoDPS() * att_speed; |
---|
395 | weapon_maxdamage += GetAmmoDPS() * att_speed; |
---|
396 | } |
---|
397 | |
---|
398 | min_damage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; |
---|
399 | max_damage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; |
---|
400 | } |
---|
401 | |
---|
402 | void Player::UpdateDamagePhysical(WeaponAttackType attType) |
---|
403 | { |
---|
404 | float mindamage; |
---|
405 | float maxdamage; |
---|
406 | |
---|
407 | CalculateMinMaxDamage(attType,false,mindamage,maxdamage); |
---|
408 | |
---|
409 | switch(attType) |
---|
410 | { |
---|
411 | case BASE_ATTACK: |
---|
412 | default: |
---|
413 | SetStatFloatValue(UNIT_FIELD_MINDAMAGE,mindamage); |
---|
414 | SetStatFloatValue(UNIT_FIELD_MAXDAMAGE,maxdamage); |
---|
415 | break; |
---|
416 | case OFF_ATTACK: |
---|
417 | SetStatFloatValue(UNIT_FIELD_MINOFFHANDDAMAGE,mindamage); |
---|
418 | SetStatFloatValue(UNIT_FIELD_MAXOFFHANDDAMAGE,maxdamage); |
---|
419 | break; |
---|
420 | case RANGED_ATTACK: |
---|
421 | SetStatFloatValue(UNIT_FIELD_MINRANGEDDAMAGE,mindamage); |
---|
422 | SetStatFloatValue(UNIT_FIELD_MAXRANGEDDAMAGE,maxdamage); |
---|
423 | break; |
---|
424 | } |
---|
425 | } |
---|
426 | |
---|
427 | void Player::UpdateDefenseBonusesMod() |
---|
428 | { |
---|
429 | UpdateBlockPercentage(); |
---|
430 | UpdateParryPercentage(); |
---|
431 | UpdateDodgePercentage(); |
---|
432 | } |
---|
433 | |
---|
434 | void Player::UpdateBlockPercentage() |
---|
435 | { |
---|
436 | // No block |
---|
437 | float value = 0.0f; |
---|
438 | if(CanBlock()) |
---|
439 | { |
---|
440 | // Base value |
---|
441 | value = 5.0f; |
---|
442 | // Modify value from defense skill |
---|
443 | value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; |
---|
444 | // Increase from SPELL_AURA_MOD_BLOCK_PERCENT aura |
---|
445 | value += GetTotalAuraModifier(SPELL_AURA_MOD_BLOCK_PERCENT); |
---|
446 | // Increase from rating |
---|
447 | value += GetRatingBonusValue(CR_BLOCK); |
---|
448 | value = value < 0.0f ? 0.0f : value; |
---|
449 | } |
---|
450 | SetStatFloatValue(PLAYER_BLOCK_PERCENTAGE, value); |
---|
451 | } |
---|
452 | |
---|
453 | void Player::UpdateCritPercentage(WeaponAttackType attType) |
---|
454 | { |
---|
455 | BaseModGroup modGroup; |
---|
456 | uint16 index; |
---|
457 | CombatRating cr; |
---|
458 | |
---|
459 | switch(attType) |
---|
460 | { |
---|
461 | case OFF_ATTACK: |
---|
462 | modGroup = OFFHAND_CRIT_PERCENTAGE; |
---|
463 | index = PLAYER_OFFHAND_CRIT_PERCENTAGE; |
---|
464 | cr = CR_CRIT_MELEE; |
---|
465 | break; |
---|
466 | case RANGED_ATTACK: |
---|
467 | modGroup = RANGED_CRIT_PERCENTAGE; |
---|
468 | index = PLAYER_RANGED_CRIT_PERCENTAGE; |
---|
469 | cr = CR_CRIT_RANGED; |
---|
470 | break; |
---|
471 | case BASE_ATTACK: |
---|
472 | default: |
---|
473 | modGroup = CRIT_PERCENTAGE; |
---|
474 | index = PLAYER_CRIT_PERCENTAGE; |
---|
475 | cr = CR_CRIT_MELEE; |
---|
476 | break; |
---|
477 | } |
---|
478 | |
---|
479 | float value = GetTotalPercentageModValue(modGroup) + GetRatingBonusValue(cr); |
---|
480 | // Modify crit from weapon skill and maximized defense skill of same level victim difference |
---|
481 | value += (int32(GetWeaponSkillValue(attType)) - int32(GetMaxSkillValueForLevel())) * 0.04f; |
---|
482 | value = value < 0.0f ? 0.0f : value; |
---|
483 | SetStatFloatValue(index, value); |
---|
484 | } |
---|
485 | |
---|
486 | void Player::UpdateAllCritPercentages() |
---|
487 | { |
---|
488 | float value = GetMeleeCritFromAgility(); |
---|
489 | |
---|
490 | SetBaseModValue(CRIT_PERCENTAGE, PCT_MOD, value); |
---|
491 | SetBaseModValue(OFFHAND_CRIT_PERCENTAGE, PCT_MOD, value); |
---|
492 | SetBaseModValue(RANGED_CRIT_PERCENTAGE, PCT_MOD, value); |
---|
493 | |
---|
494 | UpdateCritPercentage(BASE_ATTACK); |
---|
495 | UpdateCritPercentage(OFF_ATTACK); |
---|
496 | UpdateCritPercentage(RANGED_ATTACK); |
---|
497 | } |
---|
498 | |
---|
499 | void Player::UpdateParryPercentage() |
---|
500 | { |
---|
501 | // No parry |
---|
502 | float value = 0.0f; |
---|
503 | if (CanParry()) |
---|
504 | { |
---|
505 | // Base parry |
---|
506 | value = 5.0f; |
---|
507 | // Modify value from defense skill |
---|
508 | value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; |
---|
509 | // Parry from SPELL_AURA_MOD_PARRY_PERCENT aura |
---|
510 | value += GetTotalAuraModifier(SPELL_AURA_MOD_PARRY_PERCENT); |
---|
511 | // Parry from rating |
---|
512 | value += GetRatingBonusValue(CR_PARRY); |
---|
513 | value = value < 0.0f ? 0.0f : value; |
---|
514 | } |
---|
515 | SetStatFloatValue(PLAYER_PARRY_PERCENTAGE, value); |
---|
516 | } |
---|
517 | |
---|
518 | void Player::UpdateDodgePercentage() |
---|
519 | { |
---|
520 | // Dodge from agility |
---|
521 | float value = GetDodgeFromAgility(); |
---|
522 | // Modify value from defense skill |
---|
523 | value += (int32(GetDefenseSkillValue()) - int32(GetMaxSkillValueForLevel())) * 0.04f; |
---|
524 | // Dodge from SPELL_AURA_MOD_DODGE_PERCENT aura |
---|
525 | value += GetTotalAuraModifier(SPELL_AURA_MOD_DODGE_PERCENT); |
---|
526 | // Dodge from rating |
---|
527 | value += GetRatingBonusValue(CR_DODGE); |
---|
528 | value = value < 0.0f ? 0.0f : value; |
---|
529 | SetStatFloatValue(PLAYER_DODGE_PERCENTAGE, value); |
---|
530 | } |
---|
531 | |
---|
532 | void Player::UpdateSpellCritChance(uint32 school) |
---|
533 | { |
---|
534 | // For normal school set zero crit chance |
---|
535 | if(school == SPELL_SCHOOL_NORMAL) |
---|
536 | { |
---|
537 | SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1, 0.0f); |
---|
538 | return; |
---|
539 | } |
---|
540 | // For others recalculate it from: |
---|
541 | float crit = 0.0f; |
---|
542 | // Crit from Intellect |
---|
543 | crit += GetSpellCritFromIntellect(); |
---|
544 | // Increase crit from SPELL_AURA_MOD_SPELL_CRIT_CHANCE |
---|
545 | crit += GetTotalAuraModifier(SPELL_AURA_MOD_SPELL_CRIT_CHANCE); |
---|
546 | // Increase crit by school from SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL |
---|
547 | crit += GetTotalAuraModifierByMiscMask(SPELL_AURA_MOD_SPELL_CRIT_CHANCE_SCHOOL, 1<<school); |
---|
548 | // Increase crit from spell crit ratings |
---|
549 | crit += GetRatingBonusValue(CR_CRIT_SPELL); |
---|
550 | |
---|
551 | // Store crit value |
---|
552 | SetFloatValue(PLAYER_SPELL_CRIT_PERCENTAGE1 + school, crit); |
---|
553 | } |
---|
554 | |
---|
555 | void Player::UpdateAllSpellCritChances() |
---|
556 | { |
---|
557 | for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) |
---|
558 | UpdateSpellCritChance(i); |
---|
559 | } |
---|
560 | |
---|
561 | void Player::UpdateExpertise(WeaponAttackType attack) |
---|
562 | { |
---|
563 | if(attack==RANGED_ATTACK) |
---|
564 | return; |
---|
565 | |
---|
566 | int32 expertise = int32(GetRatingBonusValue(CR_EXPERTISE)); |
---|
567 | |
---|
568 | Item *weapon = GetWeaponForAttack(attack); |
---|
569 | |
---|
570 | AuraList const& expAuras = GetAurasByType(SPELL_AURA_MOD_EXPERTISE); |
---|
571 | for(AuraList::const_iterator itr = expAuras.begin(); itr != expAuras.end(); ++itr) |
---|
572 | { |
---|
573 | // item neutral spell |
---|
574 | if((*itr)->GetSpellProto()->EquippedItemClass == -1) |
---|
575 | expertise += (*itr)->GetModifier()->m_amount; |
---|
576 | // item dependent spell |
---|
577 | else if(weapon && weapon->IsFitToSpellRequirements((*itr)->GetSpellProto())) |
---|
578 | expertise += (*itr)->GetModifier()->m_amount; |
---|
579 | } |
---|
580 | |
---|
581 | if(expertise < 0) |
---|
582 | expertise = 0; |
---|
583 | |
---|
584 | switch(attack) |
---|
585 | { |
---|
586 | case BASE_ATTACK: SetUInt32Value(PLAYER_EXPERTISE, expertise); break; |
---|
587 | case OFF_ATTACK: SetUInt32Value(PLAYER_OFFHAND_EXPERTISE, expertise); break; |
---|
588 | default: break; |
---|
589 | } |
---|
590 | } |
---|
591 | |
---|
592 | void Player::UpdateManaRegen() |
---|
593 | { |
---|
594 | float Intellect = GetStat(STAT_INTELLECT); |
---|
595 | // Mana regen from spirit and intellect |
---|
596 | float power_regen = sqrt(Intellect) * OCTRegenMPPerSpirit(); |
---|
597 | // Apply PCT bonus from SPELL_AURA_MOD_POWER_REGEN_PERCENT aura on spirit base regen |
---|
598 | power_regen *= GetTotalAuraMultiplierByMiscValue(SPELL_AURA_MOD_POWER_REGEN_PERCENT, POWER_MANA); |
---|
599 | |
---|
600 | // Mana regen from SPELL_AURA_MOD_POWER_REGEN aura |
---|
601 | float power_regen_mp5 = GetTotalAuraModifierByMiscValue(SPELL_AURA_MOD_POWER_REGEN, POWER_MANA) / 5.0f; |
---|
602 | |
---|
603 | // Get bonus from SPELL_AURA_MOD_MANA_REGEN_FROM_STAT aura |
---|
604 | AuraList const& regenAura = GetAurasByType(SPELL_AURA_MOD_MANA_REGEN_FROM_STAT); |
---|
605 | for(AuraList::const_iterator i = regenAura.begin();i != regenAura.end(); ++i) |
---|
606 | { |
---|
607 | Modifier* mod = (*i)->GetModifier(); |
---|
608 | power_regen_mp5 += GetStat(Stats(mod->m_miscvalue)) * mod->m_amount / 500.0f; |
---|
609 | } |
---|
610 | |
---|
611 | // Bonus from some dummy auras |
---|
612 | AuraList const& mDummyAuras = GetAurasByType(SPELL_AURA_PERIODIC_DUMMY); |
---|
613 | for(AuraList::const_iterator i = mDummyAuras.begin();i != mDummyAuras.end(); ++i) |
---|
614 | if((*i)->GetId() == 34074) // Aspect of the Viper |
---|
615 | { |
---|
616 | power_regen_mp5 += (*i)->GetModifier()->m_amount * Intellect / 500.0f; |
---|
617 | // Add regen bonus from level in this dummy |
---|
618 | power_regen_mp5 += getLevel() * 35 / 100; |
---|
619 | } |
---|
620 | |
---|
621 | // Set regen rate in cast state apply only on spirit based regen |
---|
622 | int32 modManaRegenInterrupt = GetTotalAuraModifier(SPELL_AURA_MOD_MANA_REGEN_INTERRUPT); |
---|
623 | if (modManaRegenInterrupt > 100) |
---|
624 | modManaRegenInterrupt = 100; |
---|
625 | SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN_INTERRUPT, power_regen_mp5 + power_regen * modManaRegenInterrupt / 100.0f); |
---|
626 | |
---|
627 | SetStatFloatValue(PLAYER_FIELD_MOD_MANA_REGEN, power_regen_mp5 + power_regen); |
---|
628 | } |
---|
629 | |
---|
630 | void Player::_ApplyAllStatBonuses() |
---|
631 | { |
---|
632 | SetCanModifyStats(false); |
---|
633 | |
---|
634 | _ApplyAllAuraMods(); |
---|
635 | _ApplyAllItemMods(); |
---|
636 | |
---|
637 | SetCanModifyStats(true); |
---|
638 | |
---|
639 | UpdateAllStats(); |
---|
640 | } |
---|
641 | |
---|
642 | void Player::_RemoveAllStatBonuses() |
---|
643 | { |
---|
644 | SetCanModifyStats(false); |
---|
645 | |
---|
646 | _RemoveAllItemMods(); |
---|
647 | _RemoveAllAuraMods(); |
---|
648 | |
---|
649 | SetCanModifyStats(true); |
---|
650 | |
---|
651 | UpdateAllStats(); |
---|
652 | } |
---|
653 | |
---|
654 | /*####################################### |
---|
655 | ######## ######## |
---|
656 | ######## MOBS STAT SYSTEM ######## |
---|
657 | ######## ######## |
---|
658 | #######################################*/ |
---|
659 | |
---|
660 | bool Creature::UpdateStats(Stats /*stat*/) |
---|
661 | { |
---|
662 | return true; |
---|
663 | } |
---|
664 | |
---|
665 | bool Creature::UpdateAllStats() |
---|
666 | { |
---|
667 | UpdateMaxHealth(); |
---|
668 | UpdateAttackPowerAndDamage(); |
---|
669 | |
---|
670 | for(int i = POWER_MANA; i < MAX_POWERS; ++i) |
---|
671 | UpdateMaxPower(Powers(i)); |
---|
672 | |
---|
673 | for(int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; ++i) |
---|
674 | UpdateResistances(i); |
---|
675 | |
---|
676 | return true; |
---|
677 | } |
---|
678 | |
---|
679 | void Creature::UpdateResistances(uint32 school) |
---|
680 | { |
---|
681 | if(school > SPELL_SCHOOL_NORMAL) |
---|
682 | { |
---|
683 | float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); |
---|
684 | SetResistance(SpellSchools(school), int32(value)); |
---|
685 | } |
---|
686 | else |
---|
687 | UpdateArmor(); |
---|
688 | } |
---|
689 | |
---|
690 | void Creature::UpdateArmor() |
---|
691 | { |
---|
692 | float value = GetTotalAuraModValue(UNIT_MOD_ARMOR); |
---|
693 | SetArmor(int32(value)); |
---|
694 | } |
---|
695 | |
---|
696 | void Creature::UpdateMaxHealth() |
---|
697 | { |
---|
698 | float value = GetTotalAuraModValue(UNIT_MOD_HEALTH); |
---|
699 | SetMaxHealth((uint32)value); |
---|
700 | } |
---|
701 | |
---|
702 | void Creature::UpdateMaxPower(Powers power) |
---|
703 | { |
---|
704 | UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); |
---|
705 | |
---|
706 | float value = GetTotalAuraModValue(unitMod); |
---|
707 | SetMaxPower(power, uint32(value)); |
---|
708 | } |
---|
709 | |
---|
710 | void Creature::UpdateAttackPowerAndDamage(bool ranged) |
---|
711 | { |
---|
712 | if(ranged) |
---|
713 | return; |
---|
714 | |
---|
715 | //automatically update weapon damage after attack power modification |
---|
716 | UpdateDamagePhysical(BASE_ATTACK); |
---|
717 | } |
---|
718 | |
---|
719 | void Creature::UpdateDamagePhysical(WeaponAttackType attType) |
---|
720 | { |
---|
721 | if(attType > BASE_ATTACK) |
---|
722 | return; |
---|
723 | |
---|
724 | UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; |
---|
725 | |
---|
726 | float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; |
---|
727 | |
---|
728 | float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; |
---|
729 | float base_pct = GetModifierValue(unitMod, BASE_PCT); |
---|
730 | float total_value = GetModifierValue(unitMod, TOTAL_VALUE); |
---|
731 | float total_pct = GetModifierValue(unitMod, TOTAL_PCT); |
---|
732 | |
---|
733 | float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); |
---|
734 | float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); |
---|
735 | |
---|
736 | float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct ; |
---|
737 | float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct ; |
---|
738 | |
---|
739 | SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); |
---|
740 | SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); |
---|
741 | } |
---|
742 | |
---|
743 | /*####################################### |
---|
744 | ######## ######## |
---|
745 | ######## PETS STAT SYSTEM ######## |
---|
746 | ######## ######## |
---|
747 | #######################################*/ |
---|
748 | |
---|
749 | bool Pet::UpdateStats(Stats stat) |
---|
750 | { |
---|
751 | if(stat > STAT_SPIRIT) |
---|
752 | return false; |
---|
753 | |
---|
754 | // value = ((base_value * base_pct) + total_value) * total_pct |
---|
755 | float value = GetTotalStatValue(stat); |
---|
756 | |
---|
757 | Unit *owner = GetOwner(); |
---|
758 | if ( stat == STAT_STAMINA ) |
---|
759 | { |
---|
760 | if(owner) |
---|
761 | value += float(owner->GetStat(stat)) * 0.3f; |
---|
762 | } |
---|
763 | //warlock's and mage's pets gain 30% of owner's intellect |
---|
764 | else if ( stat == STAT_INTELLECT && getPetType() == SUMMON_PET ) |
---|
765 | { |
---|
766 | if(owner && (owner->getClass() == CLASS_WARLOCK || owner->getClass() == CLASS_MAGE) ) |
---|
767 | value += float(owner->GetStat(stat)) * 0.3f; |
---|
768 | } |
---|
769 | |
---|
770 | SetStat(stat, int32(value)); |
---|
771 | |
---|
772 | switch(stat) |
---|
773 | { |
---|
774 | case STAT_STRENGTH: UpdateAttackPowerAndDamage(); break; |
---|
775 | case STAT_AGILITY: UpdateArmor(); break; |
---|
776 | case STAT_STAMINA: UpdateMaxHealth(); break; |
---|
777 | case STAT_INTELLECT: UpdateMaxPower(POWER_MANA); break; |
---|
778 | case STAT_SPIRIT: |
---|
779 | default: |
---|
780 | break; |
---|
781 | } |
---|
782 | |
---|
783 | return true; |
---|
784 | } |
---|
785 | |
---|
786 | bool Pet::UpdateAllStats() |
---|
787 | { |
---|
788 | for (int i = STAT_STRENGTH; i < MAX_STATS; i++) |
---|
789 | UpdateStats(Stats(i)); |
---|
790 | |
---|
791 | for(int i = POWER_MANA; i < MAX_POWERS; i++) |
---|
792 | UpdateMaxPower(Powers(i)); |
---|
793 | |
---|
794 | for (int i = SPELL_SCHOOL_NORMAL; i < MAX_SPELL_SCHOOL; i++) |
---|
795 | UpdateResistances(i); |
---|
796 | |
---|
797 | return true; |
---|
798 | } |
---|
799 | |
---|
800 | void Pet::UpdateResistances(uint32 school) |
---|
801 | { |
---|
802 | if(school > SPELL_SCHOOL_NORMAL) |
---|
803 | { |
---|
804 | float value = GetTotalAuraModValue(UnitMods(UNIT_MOD_RESISTANCE_START + school)); |
---|
805 | |
---|
806 | Unit *owner = GetOwner(); |
---|
807 | // hunter and warlock pets gain 40% of owner's resistance |
---|
808 | if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) |
---|
809 | value += float(owner->GetResistance(SpellSchools(school))) * 0.4f; |
---|
810 | |
---|
811 | SetResistance(SpellSchools(school), int32(value)); |
---|
812 | } |
---|
813 | else |
---|
814 | UpdateArmor(); |
---|
815 | } |
---|
816 | |
---|
817 | void Pet::UpdateArmor() |
---|
818 | { |
---|
819 | float value = 0.0f; |
---|
820 | float bonus_armor = 0.0f; |
---|
821 | UnitMods unitMod = UNIT_MOD_ARMOR; |
---|
822 | |
---|
823 | Unit *owner = GetOwner(); |
---|
824 | // hunter and warlock pets gain 35% of owner's armor value |
---|
825 | if(owner && (getPetType() == HUNTER_PET || getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK)) |
---|
826 | bonus_armor = 0.35f * float(owner->GetArmor()); |
---|
827 | |
---|
828 | value = GetModifierValue(unitMod, BASE_VALUE); |
---|
829 | value *= GetModifierValue(unitMod, BASE_PCT); |
---|
830 | value += GetStat(STAT_AGILITY) * 2.0f; |
---|
831 | value += GetModifierValue(unitMod, TOTAL_VALUE) + bonus_armor; |
---|
832 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
833 | |
---|
834 | SetArmor(int32(value)); |
---|
835 | } |
---|
836 | |
---|
837 | void Pet::UpdateMaxHealth() |
---|
838 | { |
---|
839 | UnitMods unitMod = UNIT_MOD_HEALTH; |
---|
840 | float stamina = GetStat(STAT_STAMINA) - GetCreateStat(STAT_STAMINA); |
---|
841 | |
---|
842 | float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreateHealth(); |
---|
843 | value *= GetModifierValue(unitMod, BASE_PCT); |
---|
844 | value += GetModifierValue(unitMod, TOTAL_VALUE) + stamina * 10.0f; |
---|
845 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
846 | |
---|
847 | SetMaxHealth((uint32)value); |
---|
848 | } |
---|
849 | |
---|
850 | void Pet::UpdateMaxPower(Powers power) |
---|
851 | { |
---|
852 | UnitMods unitMod = UnitMods(UNIT_MOD_POWER_START + power); |
---|
853 | float addValue = (power == POWER_MANA) ? GetStat(STAT_INTELLECT) - GetCreateStat(STAT_INTELLECT) : 0.0f; |
---|
854 | |
---|
855 | float value = GetModifierValue(unitMod, BASE_VALUE) + GetCreatePowers(power); |
---|
856 | value *= GetModifierValue(unitMod, BASE_PCT); |
---|
857 | value += GetModifierValue(unitMod, TOTAL_VALUE) + addValue * 15.0f; |
---|
858 | value *= GetModifierValue(unitMod, TOTAL_PCT); |
---|
859 | |
---|
860 | SetMaxPower(power, uint32(value)); |
---|
861 | } |
---|
862 | |
---|
863 | void Pet::UpdateAttackPowerAndDamage(bool ranged) |
---|
864 | { |
---|
865 | if(ranged) |
---|
866 | return; |
---|
867 | |
---|
868 | float val = 0.0f; |
---|
869 | float bonusAP = 0.0f; |
---|
870 | UnitMods unitMod = UNIT_MOD_ATTACK_POWER; |
---|
871 | |
---|
872 | if(GetEntry() == 416) // imp's attack power |
---|
873 | val = GetStat(STAT_STRENGTH) - 10.0f; |
---|
874 | else |
---|
875 | val = 2 * GetStat(STAT_STRENGTH) - 20.0f; |
---|
876 | |
---|
877 | Unit* owner = GetOwner(); |
---|
878 | if( owner && owner->GetTypeId()==TYPEID_PLAYER) |
---|
879 | { |
---|
880 | if(getPetType() == HUNTER_PET) //hunter pets benefit from owner's attack power |
---|
881 | { |
---|
882 | bonusAP = owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.22f; |
---|
883 | SetBonusDamage( int32(owner->GetTotalAttackPowerValue(RANGED_ATTACK) * 0.125f)); |
---|
884 | } |
---|
885 | //demons benefit from warlocks shadow or fire damage |
---|
886 | else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_WARLOCK) |
---|
887 | { |
---|
888 | int32 fire = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FIRE)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FIRE); |
---|
889 | int32 shadow = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_SHADOW)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_SHADOW); |
---|
890 | int32 maximum = (fire > shadow) ? fire : shadow; |
---|
891 | if(maximum < 0) |
---|
892 | maximum = 0; |
---|
893 | SetBonusDamage( int32(maximum * 0.15f)); |
---|
894 | bonusAP = maximum * 0.57f; |
---|
895 | } |
---|
896 | //water elementals benefit from mage's frost damage |
---|
897 | else if(getPetType() == SUMMON_PET && owner->getClass() == CLASS_MAGE) |
---|
898 | { |
---|
899 | int32 frost = int32(owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_POS + SPELL_SCHOOL_FROST)) - owner->GetUInt32Value(PLAYER_FIELD_MOD_DAMAGE_DONE_NEG + SPELL_SCHOOL_FROST); |
---|
900 | if(frost < 0) |
---|
901 | frost = 0; |
---|
902 | SetBonusDamage( int32(frost * 0.4f)); |
---|
903 | } |
---|
904 | } |
---|
905 | |
---|
906 | SetModifierValue(UNIT_MOD_ATTACK_POWER, BASE_VALUE, val + bonusAP); |
---|
907 | |
---|
908 | //in BASE_VALUE of UNIT_MOD_ATTACK_POWER for creatures we store data of meleeattackpower field in DB |
---|
909 | float base_attPower = GetModifierValue(unitMod, BASE_VALUE) * GetModifierValue(unitMod, BASE_PCT); |
---|
910 | float attPowerMod = GetModifierValue(unitMod, TOTAL_VALUE); |
---|
911 | float attPowerMultiplier = GetModifierValue(unitMod, TOTAL_PCT) - 1.0f; |
---|
912 | |
---|
913 | //UNIT_FIELD_(RANGED)_ATTACK_POWER field |
---|
914 | SetUInt32Value(UNIT_FIELD_ATTACK_POWER, (uint32)base_attPower); |
---|
915 | //UNIT_FIELD_(RANGED)_ATTACK_POWER_MODS field |
---|
916 | SetUInt32Value(UNIT_FIELD_ATTACK_POWER_MODS, (uint32)attPowerMod); |
---|
917 | //UNIT_FIELD_(RANGED)_ATTACK_POWER_MULTIPLIER field |
---|
918 | SetFloatValue(UNIT_FIELD_ATTACK_POWER_MULTIPLIER, attPowerMultiplier); |
---|
919 | |
---|
920 | //automatically update weapon damage after attack power modification |
---|
921 | UpdateDamagePhysical(BASE_ATTACK); |
---|
922 | } |
---|
923 | |
---|
924 | void Pet::UpdateDamagePhysical(WeaponAttackType attType) |
---|
925 | { |
---|
926 | if(attType > BASE_ATTACK) |
---|
927 | return; |
---|
928 | |
---|
929 | UnitMods unitMod = UNIT_MOD_DAMAGE_MAINHAND; |
---|
930 | |
---|
931 | float att_speed = float(GetAttackTime(BASE_ATTACK))/1000.0f; |
---|
932 | |
---|
933 | float base_value = GetModifierValue(unitMod, BASE_VALUE) + GetTotalAttackPowerValue(attType)/ 14.0f * att_speed; |
---|
934 | float base_pct = GetModifierValue(unitMod, BASE_PCT); |
---|
935 | float total_value = GetModifierValue(unitMod, TOTAL_VALUE); |
---|
936 | float total_pct = GetModifierValue(unitMod, TOTAL_PCT); |
---|
937 | |
---|
938 | float weapon_mindamage = GetWeaponDamageRange(BASE_ATTACK, MINDAMAGE); |
---|
939 | float weapon_maxdamage = GetWeaponDamageRange(BASE_ATTACK, MAXDAMAGE); |
---|
940 | |
---|
941 | float mindamage = ((base_value + weapon_mindamage) * base_pct + total_value) * total_pct; |
---|
942 | float maxdamage = ((base_value + weapon_maxdamage) * base_pct + total_value) * total_pct; |
---|
943 | |
---|
944 | // Pet's base damage changes depending on happiness |
---|
945 | if (getPetType() == HUNTER_PET && attType == BASE_ATTACK) |
---|
946 | { |
---|
947 | switch(GetHappinessState()) |
---|
948 | { |
---|
949 | case HAPPY: |
---|
950 | // 125% of normal damage |
---|
951 | mindamage = mindamage * 1.25; |
---|
952 | maxdamage = maxdamage * 1.25; |
---|
953 | break; |
---|
954 | case CONTENT: |
---|
955 | // 100% of normal damage, nothing to modify |
---|
956 | break; |
---|
957 | case UNHAPPY: |
---|
958 | // 75% of normal damage |
---|
959 | mindamage = mindamage * 0.75; |
---|
960 | maxdamage = maxdamage * 0.75; |
---|
961 | break; |
---|
962 | } |
---|
963 | } |
---|
964 | |
---|
965 | SetStatFloatValue(UNIT_FIELD_MINDAMAGE, mindamage); |
---|
966 | SetStatFloatValue(UNIT_FIELD_MAXDAMAGE, maxdamage); |
---|
967 | } |
---|