[10701] Correct check percent spell costs in AI::CanCast

Also use uint32 for spell cost fields/results

Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
kid 10 2010-11-08 22:04:50 +03:00 committed by VladimirMangos
parent a72930acc9
commit b435aa350f
5 changed files with 41 additions and 39 deletions

View file

@ -19,6 +19,7 @@
#include "CreatureAI.h" #include "CreatureAI.h"
#include "Creature.h" #include "Creature.h"
#include "DBCStores.h" #include "DBCStores.h"
#include "Spell.h"
CreatureAI::~CreatureAI() CreatureAI::~CreatureAI()
{ {
@ -46,7 +47,7 @@ CanCastResult CreatureAI::CanCastSpell(Unit* pTarget, const SpellEntry *pSpell,
return CAST_FAIL_STATE; return CAST_FAIL_STATE;
// Check for power (also done by Spell::CheckCast()) // Check for power (also done by Spell::CheckCast())
if (m_creature->GetPower((Powers)pSpell->powerType) < pSpell->manaCost) if (m_creature->GetPower((Powers)pSpell->powerType) < Spell::CalculatePowerCost(pSpell, m_creature))
return CAST_FAIL_POWER; return CAST_FAIL_POWER;
} }

View file

@ -1390,7 +1390,7 @@ bool CreatureEventAI::CanCast(Unit* Target, SpellEntry const *Spell, bool Trigge
return false; return false;
//Check for power //Check for power
if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell->manaCost) if (!Triggered && m_creature->GetPower((Powers)Spell->powerType) < Spell::CalculatePowerCost(Spell, m_creature))
return false; return false;
SpellRangeEntry const *TempRange = NULL; SpellRangeEntry const *TempRange = NULL;

View file

@ -2633,7 +2633,7 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura)
} }
// Fill cost data // Fill cost data
m_powerCost = CalculatePowerCost(); m_powerCost = CalculatePowerCost(m_spellInfo, m_caster, this, m_CastItem);
SpellCastResult result = CheckCast(true); SpellCastResult result = CheckCast(true);
if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering
@ -5616,69 +5616,70 @@ SpellCastResult Spell::CheckRange(bool strict)
return SPELL_CAST_OK; return SPELL_CAST_OK;
} }
int32 Spell::CalculatePowerCost() uint32 Spell::CalculatePowerCost(SpellEntry const* spellInfo, Unit* caster, Spell const* spell, Item* castItem)
{ {
// item cast not used power // item cast not used power
if (m_CastItem) if (castItem)
return 0; return 0;
// Spell drain all exist power on cast (Only paladin lay of Hands) // Spell drain all exist power on cast (Only paladin lay of Hands)
if (m_spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER) if (spellInfo->AttributesEx & SPELL_ATTR_EX_DRAIN_ALL_POWER)
{ {
// If power type - health drain all // If power type - health drain all
if (m_spellInfo->powerType == POWER_HEALTH) if (spellInfo->powerType == POWER_HEALTH)
return m_caster->GetHealth(); return caster->GetHealth();
// Else drain all power // Else drain all power
if (m_spellInfo->powerType < MAX_POWERS) if (spellInfo->powerType < MAX_POWERS)
return m_caster->GetPower(Powers(m_spellInfo->powerType)); return caster->GetPower(Powers(spellInfo->powerType));
sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id);
return 0; return 0;
} }
// Base powerCost // Base powerCost
int32 powerCost = m_spellInfo->manaCost; int32 powerCost = spellInfo->manaCost;
// PCT cost from total amount // PCT cost from total amount
if (m_spellInfo->ManaCostPercentage) if (spellInfo->ManaCostPercentage)
{ {
switch (m_spellInfo->powerType) switch (spellInfo->powerType)
{ {
// health as power used // health as power used
case POWER_HEALTH: case POWER_HEALTH:
powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateHealth() / 100; powerCost += spellInfo->ManaCostPercentage * caster->GetCreateHealth() / 100;
break; break;
case POWER_MANA: case POWER_MANA:
powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetCreateMana() / 100; powerCost += spellInfo->ManaCostPercentage * caster->GetCreateMana() / 100;
break; break;
case POWER_RAGE: case POWER_RAGE:
case POWER_FOCUS: case POWER_FOCUS:
case POWER_ENERGY: case POWER_ENERGY:
case POWER_HAPPINESS: case POWER_HAPPINESS:
powerCost += m_spellInfo->ManaCostPercentage * m_caster->GetMaxPower(Powers(m_spellInfo->powerType)) / 100; powerCost += spellInfo->ManaCostPercentage * caster->GetMaxPower(Powers(spellInfo->powerType)) / 100;
break; break;
case POWER_RUNE: case POWER_RUNE:
case POWER_RUNIC_POWER: case POWER_RUNIC_POWER:
DEBUG_LOG("Spell::CalculateManaCost: Not implemented yet!"); DEBUG_LOG("Spell::CalculateManaCost: Not implemented yet!");
break; break;
default: default:
sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", m_spellInfo->powerType, m_spellInfo->Id); sLog.outError("Spell::CalculateManaCost: Unknown power type '%d' in spell %d", spellInfo->powerType, spellInfo->Id);
return 0; return 0;
} }
} }
SpellSchools school = GetFirstSchoolInMask(m_spellSchoolMask); SpellSchools school = GetFirstSchoolInMask(spell ? spell->m_spellSchoolMask : GetSpellSchoolMask(spellInfo));
// Flat mod from caster auras by spell school // Flat mod from caster auras by spell school
powerCost += m_caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school); powerCost += caster->GetInt32Value(UNIT_FIELD_POWER_COST_MODIFIER + school);
// Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost) // Shiv - costs 20 + weaponSpeed*10 energy (apply only to non-triggered spell with energy cost)
if ( m_spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST ) if (spellInfo->AttributesEx4 & SPELL_ATTR_EX4_SPELL_VS_EXTEND_COST)
powerCost += m_caster->GetAttackTime(OFF_ATTACK) / 100; powerCost += caster->GetAttackTime(OFF_ATTACK) / 100;
// Apply cost mod by spell // Apply cost mod by spell
if(Player* modOwner = m_caster->GetSpellModOwner()) if (spell)
modOwner->ApplySpellMod(m_spellInfo->Id, SPELLMOD_COST, powerCost, this); if (Player* modOwner = caster->GetSpellModOwner())
modOwner->ApplySpellMod(spellInfo->Id, SPELLMOD_COST, powerCost, spell);
if(m_spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION) if (spellInfo->Attributes & SPELL_ATTR_LEVEL_DAMAGE_CALCULATION)
powerCost = int32(powerCost/ (1.117f * m_spellInfo->spellLevel / m_caster->getLevel() -0.1327f)); powerCost = int32(powerCost/ (1.117f * spellInfo->spellLevel / caster->getLevel() -0.1327f));
// PCT mod from user auras by school // PCT mod from user auras by school
powerCost = int32(powerCost * (1.0f + m_caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school))); powerCost = int32(powerCost * (1.0f + caster->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER + school)));
if (powerCost < 0) if (powerCost < 0)
powerCost = 0; powerCost = 0;
return powerCost; return powerCost;
@ -5700,33 +5701,33 @@ SpellCastResult Spell::CheckPower()
} }
// health as power used - need check health amount // health as power used - need check health amount
if(m_spellInfo->powerType == POWER_HEALTH) if (m_spellInfo->powerType == POWER_HEALTH)
{ {
if((int32)m_caster->GetHealth() <= m_powerCost) if (m_caster->GetHealth() <= m_powerCost)
return SPELL_FAILED_CASTER_AURASTATE; return SPELL_FAILED_CASTER_AURASTATE;
return SPELL_CAST_OK; return SPELL_CAST_OK;
} }
// Check valid power type // Check valid power type
if( m_spellInfo->powerType >= MAX_POWERS ) if (m_spellInfo->powerType >= MAX_POWERS)
{ {
sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType); sLog.outError("Spell::CheckMana: Unknown power type '%d'", m_spellInfo->powerType);
return SPELL_FAILED_UNKNOWN; return SPELL_FAILED_UNKNOWN;
} }
//check rune cost only if a spell has PowerType == POWER_RUNE //check rune cost only if a spell has PowerType == POWER_RUNE
if(m_spellInfo->powerType == POWER_RUNE) if (m_spellInfo->powerType == POWER_RUNE)
{ {
SpellCastResult failReason = CheckOrTakeRunePower(false); SpellCastResult failReason = CheckOrTakeRunePower(false);
if(failReason != SPELL_CAST_OK) if (failReason != SPELL_CAST_OK)
return failReason; return failReason;
} }
// Check power amount // Check power amount
Powers powerType = Powers(m_spellInfo->powerType); Powers powerType = Powers(m_spellInfo->powerType);
if((int32)m_caster->GetPower(powerType) < m_powerCost) if (m_caster->GetPower(powerType) < m_powerCost)
return SPELL_FAILED_NO_POWER; return SPELL_FAILED_NO_POWER;
else
return SPELL_CAST_OK; return SPELL_CAST_OK;
} }
bool Spell::IgnoreItemRequirements() const bool Spell::IgnoreItemRequirements() const

View file

@ -374,7 +374,7 @@ class Spell
SpellCastResult CheckCasterAuras() const; SpellCastResult CheckCasterAuras() const;
int32 CalculateDamage(SpellEffectIndex i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_currentBasePoints[i]); } int32 CalculateDamage(SpellEffectIndex i, Unit* target) { return m_caster->CalculateSpellDamage(target, m_spellInfo, i, &m_currentBasePoints[i]); }
int32 CalculatePowerCost(); static uint32 CalculatePowerCost(SpellEntry const* spellInfo, Unit* caster, Spell const* spell = NULL, Item* castItem = NULL);
bool HaveTargetsForEffect(SpellEffectIndex effect) const; bool HaveTargetsForEffect(SpellEffectIndex effect) const;
void Delayed(); void Delayed();
@ -469,7 +469,7 @@ class Spell
// m_originalCasterGUID can store GO guid, and in this case this is visual caster // m_originalCasterGUID can store GO guid, and in this case this is visual caster
WorldObject* GetCastingObject() const; WorldObject* GetCastingObject() const;
int32 GetPowerCost() const { return m_powerCost; } uint32 GetPowerCost() const { return m_powerCost; }
void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc) void UpdatePointers(); // must be used at call Spell code after time delay (non triggered spell cast/update spell call/etc)
@ -506,7 +506,7 @@ class Spell
//Spell data //Spell data
SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example) SpellSchoolMask m_spellSchoolMask; // Spell school (can be overwrite for some spells (wand shoot for example)
WeaponAttackType m_attackType; // For weapon based attack WeaponAttackType m_attackType; // For weapon based attack
int32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare uint32 m_powerCost; // Calculated spell cost initialized only in Spell::prepare
int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare int32 m_casttime; // Calculated spell cast time initialized only in Spell::prepare
bool m_canReflect; // can reflect this spell? bool m_canReflect; // can reflect this spell?
bool m_autoRepeat; bool m_autoRepeat;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "10700" #define REVISION_NR "10701"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__