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