diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/Pet.cpp | 2 | ||||
-rw-r--r-- | src/game/PetHandler.cpp | 10 | ||||
-rw-r--r-- | src/game/Player.cpp | 6 | ||||
-rw-r--r-- | src/game/SharedDefines.h | 7 | ||||
-rw-r--r-- | src/game/Spell.cpp | 348 | ||||
-rw-r--r-- | src/game/Spell.h | 22 | ||||
-rw-r--r-- | src/game/SpellEffects.cpp | 6 | ||||
-rw-r--r-- | src/game/SpellMgr.cpp | 28 | ||||
-rw-r--r-- | src/game/SpellMgr.h | 4 | ||||
-rw-r--r-- | src/game/Unit.cpp | 7 | ||||
-rw-r--r-- | src/game/Unit.h | 2 |
11 files changed, 216 insertions, 226 deletions
diff --git a/src/game/Pet.cpp b/src/game/Pet.cpp index 11f1ba5d236..32ffd80801b 100644 --- a/src/game/Pet.cpp +++ b/src/game/Pet.cpp @@ -304,7 +304,7 @@ bool Pet::LoadPetFromDB( Player* owner, uint32 petentry, uint32 petnumber, bool AIM_Initialize(); map->Add((Creature*)this); - // Spells should be loaded after pet is added to map, because in CanCast is check on it + // Spells should be loaded after pet is added to map, because in CheckCast is check on it _LoadSpells(); _LoadSpellCooldowns(); diff --git a/src/game/PetHandler.cpp b/src/game/PetHandler.cpp index 11caeb74a55..9f9cb3a33a3 100644 --- a/src/game/PetHandler.cpp +++ b/src/game/PetHandler.cpp @@ -207,7 +207,7 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) Spell *spell = new Spell(pet, spellInfo, false); - int16 result = spell->PetCanCast(unit_target); + SpellCastResult result = spell->CheckPetCast(unit_target); //auto turn to target unless possessed if(result == SPELL_FAILED_UNIT_NOT_INFRONT && !pet->isPossessed()) @@ -218,10 +218,10 @@ void WorldSession::HandlePetAction( WorldPacket & recv_data ) if(Unit* powner = pet->GetCharmerOrOwner()) if(powner->GetTypeId() == TYPEID_PLAYER) pet->SendUpdateToPlayer((Player*)powner); - result = -1; + result = SPELL_CAST_OK; } - if(result == -1) + if(result == SPELL_CAST_OK) { ((Creature*)pet)->AddCreatureSpellCooldown(spellid); if (((Creature*)pet)->isPet()) @@ -624,8 +624,8 @@ void WorldSession::HandlePetCastSpellOpcode( WorldPacket& recvPacket ) spell->m_cast_count = cast_count; // probably pending spell cast spell->m_targets = targets; - int16 result = spell->PetCanCast(NULL); - if(result == -1) + SpellCastResult result = spell->CheckPetCast(NULL); + if(result == SPELL_CAST_OK) { if(caster->GetTypeId() == TYPEID_UNIT) { diff --git a/src/game/Player.cpp b/src/game/Player.cpp index 2fdf78e4a11..badeca1fa0e 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -7178,7 +7178,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply if(apply) { // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)!=0) + if(GetErrorAtShapeshiftedCast(spellInfo, m_form) != SPELL_CAST_OK) return; if(form_change) // check aura active state from other form @@ -7212,7 +7212,7 @@ void Player::ApplyEquipSpell(SpellEntry const* spellInfo, Item* item, bool apply if(form_change) // check aura compatibility { // Cannot be used in this stance/form - if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==0) + if(GetErrorAtShapeshiftedCast(spellInfo, m_form)==SPELL_CAST_OK) return; // and remove only not compatible at form change } @@ -19894,7 +19894,7 @@ void Player::UpdateAreaDependentAuras( uint32 newArea ) for(AuraMap::iterator iter = m_Auras.begin(); iter != m_Auras.end();) { // use m_zoneUpdateId for speed: UpdateArea called from UpdateZone or instead UpdateZone in both cases m_zoneUpdateId up-to-date - if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this)!=0) + if(spellmgr.GetSpellAllowedInLocationError(iter->second->GetSpellProto(),GetMapId(),m_zoneUpdateId,newArea,this) != SPELL_CAST_OK) RemoveAura(iter); else ++iter; diff --git a/src/game/SharedDefines.h b/src/game/SharedDefines.h index ba165d3053a..f71f5655e25 100644 --- a/src/game/SharedDefines.h +++ b/src/game/SharedDefines.h @@ -695,8 +695,7 @@ enum SpellEffects enum SpellCastResult { - SPELL_CAST_OK = 0, //FIXME: used as success result currently - SPELL_FAILED_AFFECTING_COMBAT = 0, //FIXME: used as success result currently + SPELL_FAILED_AFFECTING_COMBAT = 0, SPELL_FAILED_ALREADY_AT_FULL_HEALTH = 1, SPELL_FAILED_ALREADY_AT_FULL_MANA = 2, SPELL_FAILED_ALREADY_AT_FULL_POWER = 3, @@ -877,7 +876,9 @@ enum SpellCastResult SPELL_FAILED_ITEM_AT_MAX_CHARGES = 178, SPELL_FAILED_NOT_IN_BARBERSHOP = 179, SPELL_FAILED_FISHING_TOO_LOW = 180, - SPELL_FAILED_UNKNOWN = 181 + SPELL_FAILED_UNKNOWN = 181, + + SPELL_CAST_OK = 255 //custom value, don't must be send to client }; // Spell aura states diff --git a/src/game/Spell.cpp b/src/game/Spell.cpp index bfc58631079..57bcebcef62 100644 --- a/src/game/Spell.cpp +++ b/src/game/Spell.cpp @@ -627,7 +627,7 @@ void Spell::FillTargetMap() for (std::list<Unit*>::iterator itr = tmpUnitMap.begin() ; itr != tmpUnitMap.end();) { - if(!CheckTarget(*itr, i, false )) + if(!CheckTarget(*itr, i)) { itr = tmpUnitMap.erase(itr); continue; @@ -2060,8 +2060,8 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura) // Fill cost data m_powerCost = CalculatePowerCost(); - uint8 result = CanCast(true); - if(result != 0 && !IsAutoRepeat()) //always cast autorepeat dummy for triggering + SpellCastResult result = CheckCast(true); + if(result != SPELL_CAST_OK && !IsAutoRepeat()) //always cast autorepeat dummy for triggering { if(triggeredByAura) { @@ -2076,7 +2076,7 @@ void Spell::prepare(SpellCastTargets const* targets, Aura* triggeredByAura) // Prepare data for triggers prepareDataForTriggerSystem(); - // calculate cast time (calculated after first CanCast check to prevent charge counting for first CanCast fail) + // calculate cast time (calculated after first CheckCast check to prevent charge counting for first CheckCast fail) m_casttime = GetSpellCastTime(m_spellInfo, this); // set timer base at cast time @@ -2157,8 +2157,6 @@ void Spell::cast(bool skipCheck) { SetExecutedCurrently(true); - uint8 castResult = 0; - // update pointers base at GUIDs to prevent access to non-existed already object UpdatePointers(); @@ -2175,8 +2173,8 @@ void Spell::cast(bool skipCheck) if(!m_IsTriggeredSpell) { - castResult = CheckPower(); - if(castResult != 0) + SpellCastResult castResult = CheckPower(); + if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); finish(false); @@ -2188,8 +2186,8 @@ void Spell::cast(bool skipCheck) // triggered cast called from Spell::prepare where it was already checked if(!skipCheck) { - castResult = CanCast(false); - if(castResult != 0) + SpellCastResult castResult = CheckCast(false); + if(castResult != SPELL_CAST_OK) { SendCastResult(castResult); finish(false); @@ -2634,65 +2632,65 @@ void Spell::finish(bool ok) m_caster->AttackStop(); } -void Spell::SendCastResult(uint8 result) +void Spell::SendCastResult(SpellCastResult result) { + if(result == SPELL_CAST_OK) + return; + if (m_caster->GetTypeId() != TYPEID_PLAYER) return; if(((Player*)m_caster)->GetSession()->PlayerLoading()) // don't send cast results at loading time return; - if(result != 0) + WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); + data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) + data << uint32(m_spellInfo->Id); + data << uint8(result); // problem + switch (result) { - WorldPacket data(SMSG_CAST_FAILED, (4+1+1)); - data << uint8(m_cast_count); // single cast or multi 2.3 (0/1) - data << uint32(m_spellInfo->Id); - data << uint8(result); // problem - switch (result) - { - case SPELL_FAILED_REQUIRES_SPELL_FOCUS: - data << uint32(m_spellInfo->RequiresSpellFocus); - break; - case SPELL_FAILED_REQUIRES_AREA: - // hardcode areas limitation case - switch(m_spellInfo->Id) - { - case 41617: // Cenarion Mana Salve - case 41619: // Cenarion Healing Salve - data << uint32(3905); - break; - case 41618: // Bottled Nethergon Energy - case 41620: // Bottled Nethergon Vapor - data << uint32(3842); - break; - case 45373: // Bloodberry Elixir - data << uint32(4075); - break; - default: // default case (don't must be) - data << uint32(0); - break; - } - break; - case SPELL_FAILED_TOTEMS: - if(m_spellInfo->Totem[0]) - data << uint32(m_spellInfo->Totem[0]); - if(m_spellInfo->Totem[1]) - data << uint32(m_spellInfo->Totem[1]); - break; - case SPELL_FAILED_TOTEM_CATEGORY: - if(m_spellInfo->TotemCategory[0]) - data << uint32(m_spellInfo->TotemCategory[0]); - if(m_spellInfo->TotemCategory[1]) - data << uint32(m_spellInfo->TotemCategory[1]); - break; - case SPELL_FAILED_EQUIPPED_ITEM_CLASS: - data << uint32(m_spellInfo->EquippedItemClass); - data << uint32(m_spellInfo->EquippedItemSubClassMask); - //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); - break; - } - ((Player*)m_caster)->GetSession()->SendPacket(&data); + case SPELL_FAILED_REQUIRES_SPELL_FOCUS: + data << uint32(m_spellInfo->RequiresSpellFocus); + break; + case SPELL_FAILED_REQUIRES_AREA: + // hardcode areas limitation case + switch(m_spellInfo->Id) + { + case 41617: // Cenarion Mana Salve + case 41619: // Cenarion Healing Salve + data << uint32(3905); + break; + case 41618: // Bottled Nethergon Energy + case 41620: // Bottled Nethergon Vapor + data << uint32(3842); + break; + case 45373: // Bloodberry Elixir + data << uint32(4075); + break; + default: // default case (don't must be) + data << uint32(0); + break; + } + break; + case SPELL_FAILED_TOTEMS: + if(m_spellInfo->Totem[0]) + data << uint32(m_spellInfo->Totem[0]); + if(m_spellInfo->Totem[1]) + data << uint32(m_spellInfo->Totem[1]); + break; + case SPELL_FAILED_TOTEM_CATEGORY: + if(m_spellInfo->TotemCategory[0]) + data << uint32(m_spellInfo->TotemCategory[0]); + if(m_spellInfo->TotemCategory[1]) + data << uint32(m_spellInfo->TotemCategory[1]); + break; + case SPELL_FAILED_EQUIPPED_ITEM_CLASS: + data << uint32(m_spellInfo->EquippedItemClass); + data << uint32(m_spellInfo->EquippedItemSubClassMask); + //data << uint32(m_spellInfo->EquippedItemInventoryTypeMask); + break; } + ((Player*)m_caster)->GetSession()->SendPacket(&data); } void Spell::SendSpellStart() @@ -3280,30 +3278,28 @@ void Spell::TakeAmmo() } } -uint8 Spell::CheckRuneCost(uint32 runeCostID) +SpellCastResult Spell::CheckRuneCost(uint32 runeCostID) { if(m_caster->GetTypeId() != TYPEID_PLAYER) - return 0; + return SPELL_CAST_OK; Player *plr = (Player*)m_caster; if(plr->getClass() != CLASS_DEATH_KNIGHT) - return 0; + return SPELL_CAST_OK; SpellRuneCostEntry const *src = sSpellRuneCostStore.LookupEntry(runeCostID); if(!src) - return 0; + return SPELL_CAST_OK; if(src->NoRuneCost()) - return 0; + return SPELL_CAST_OK; int32 runeCost[NUM_RUNE_TYPES]; // blood, frost, unholy, death for(uint32 i = 0; i < RUNE_DEATH; ++i) - { runeCost[i] = src->RuneCost[i]; - } runeCost[RUNE_DEATH] = MAX_RUNES; // calculated later @@ -3311,23 +3307,17 @@ uint8 Spell::CheckRuneCost(uint32 runeCostID) { uint8 rune = plr->GetCurrentRune(i); if((plr->GetRuneCooldown(i) == 0) && (runeCost[rune] > 0)) - { runeCost[rune]--; - } } for(uint32 i = 0; i < RUNE_DEATH; ++i) - { if(runeCost[i] > 0) - { runeCost[RUNE_DEATH] += runeCost[i]; - } - } if(runeCost[RUNE_DEATH] > MAX_RUNES) return SPELL_FAILED_NO_POWER; // not sure if result code is correct - return 0; + return SPELL_CAST_OK; } void Spell::TakeRunePower() @@ -3498,7 +3488,7 @@ void Spell::TriggerSpell() } } -uint8 Spell::CanCast(bool strict) +SpellCastResult Spell::CheckCast(bool strict) { // check cooldowns to prevent cheating if(m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->HasSpellCooldown(m_spellInfo->Id)) @@ -3535,7 +3525,8 @@ uint8 Spell::CanCast(bool strict) if (checkForm) { // Cannot be used in this stance/form - if(uint8 shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form)) + SpellCastResult shapeError = GetErrorAtShapeshiftedCast(m_spellInfo, m_caster->m_form); + if(shapeError != SPELL_CAST_OK) return shapeError; if ((m_spellInfo->Attributes & SPELL_ATTR_ONLY_STEALTHED) && !(m_caster->HasStealthAura())) @@ -3582,9 +3573,7 @@ uint8 Spell::CanCast(bool strict) return SPELL_FAILED_MOVING; } - Unit *target = m_targets.getUnitTarget(); - - if(target) + if(Unit *target = m_targets.getUnitTarget()) { if (reqAuraState) { @@ -3615,14 +3604,10 @@ uint8 Spell::CanCast(bool strict) // auto selection spell rank implemented in WorldSession::HandleCastSpellOpcode // this case can be triggered if rank not found (too low-level target for first rank) if(m_caster->GetTypeId() == TYPEID_PLAYER && !IsPassiveSpell(m_spellInfo->Id) && !m_CastItem) - { for(int i=0;i<3;i++) - { if(IsPositiveEffect(m_spellInfo->Id, i) && m_spellInfo->Effect[i] == SPELL_EFFECT_APPLY_AURA) if(target->getLevel() + 10 < m_spellInfo->spellLevel) return SPELL_FAILED_LOWLEVEL; - } - } } else if (m_caster->GetTypeId()==TYPEID_PLAYER) // Target - is player caster { @@ -3688,10 +3673,8 @@ uint8 Spell::CanCast(bool strict) } if(IsPositiveSpell(m_spellInfo->Id)) - { if(target->IsImmunedToSpell(m_spellInfo)) return SPELL_FAILED_TARGET_AURASTATE; - } //Must be behind the target. if( m_spellInfo->AttributesEx2 == 0x100000 && (m_spellInfo->AttributesEx & 0x200) == 0x200 && target->HasInArc(M_PI, m_caster) @@ -3713,10 +3696,9 @@ uint8 Spell::CanCast(bool strict) // check if target is in combat if (target != m_caster && (m_spellInfo->AttributesEx & SPELL_ATTR_EX_NOT_IN_COMBAT_TARGET) && target->isInCombat()) - { return SPELL_FAILED_TARGET_AFFECTING_COMBAT; - } } + // Spell casted only on battleground if((m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_BATTLEGROUND) && m_caster->GetTypeId()==TYPEID_PLAYER) if(!((Player*)m_caster)->InBattleGround()) @@ -3735,9 +3717,10 @@ uint8 Spell::CanCast(bool strict) uint32 zone, area; m_caster->GetZoneAndAreaId(zone,area); - if (uint8 res= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, - m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL)) - return res; + SpellCastResult locRes= spellmgr.GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),zone,area, + m_caster->GetTypeId()==TYPEID_PLAYER ? ((Player*)m_caster) : NULL); + if(locRes != SPELL_CAST_OK) + return locRes; // not let players cast spells at mount (and let do it to creatures) if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell && @@ -3751,11 +3734,14 @@ uint8 Spell::CanCast(bool strict) // always (except passive spells) check items (focus object can be required for any type casts) if(!IsPassiveSpell(m_spellInfo->Id)) - if(uint8 castResult = CheckItems()) + { + SpellCastResult castResult = CheckItems(); + if(castResult != SPELL_CAST_OK) return castResult; + } /*//ImpliciteTargetA-B = 38, If fact there is 0 Spell with ImpliciteTargetB=38 - if(m_UniqueTargetInfo.empty()) // skip second canCast apply (for delayed spells for example) + if(m_UniqueTargetInfo.empty()) // skip second CheckCast apply (for delayed spells for example) { for(uint8 j = 0; j < 3; j++) { @@ -3891,13 +3877,16 @@ uint8 Spell::CanCast(bool strict) if(!m_IsTriggeredSpell) { - if(uint8 castResult = CheckRange(strict)) + SpellCastResult castResult = CheckRange(strict); + if(castResult != SPELL_CAST_OK) return castResult; - if(uint8 castResult = CheckPower()) + castResult = CheckPower(); + if(castResult != SPELL_CAST_OK) return castResult; - if(uint8 castResult = CheckCasterAuras()) + castResult = CheckCasterAuras(); + if(castResult != SPELL_CAST_OK) return castResult; } @@ -3922,7 +3911,7 @@ uint8 Spell::CanCast(bool strict) { // spell different for friends and enemies // hart version required facing - if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, target )) + if(m_targets.getUnitTarget() && !m_caster->IsFriendlyTo(m_targets.getUnitTarget()) && !m_caster->HasInArc( M_PI, m_targets.getUnitTarget() )) return SPELL_FAILED_UNIT_NOT_INFRONT; } else if (m_spellInfo->Id == 19938) // Awaken Peon @@ -4332,10 +4321,10 @@ uint8 Spell::CanCast(bool strict) } // all ok - return 0; + return SPELL_CAST_OK; } -int16 Spell::PetCanCast(Unit* target) +SpellCastResult Spell::CheckPetCast(Unit* target) { if(!m_caster->isAlive()) return SPELL_FAILED_CASTER_DEAD; @@ -4383,20 +4372,16 @@ int16 Spell::PetCanCast(Unit* target) return SPELL_FAILED_NOT_READY; } - uint16 result = CanCast(true); - if(result != 0) - return result; - else - return -1; //this allows to check spell fail 0, in combat + return CheckCast(true); } -uint8 Spell::CheckCasterAuras() const +SpellCastResult Spell::CheckCasterAuras() const { // Flag drop spells totally immuned to caster auras // FIXME: find more nice check for all totally immuned spells // AttributesEx3 & 0x10000000? if(m_spellInfo->Id==23336 || m_spellInfo->Id==23334 || m_spellInfo->Id==34991) - return 0; + return SPELL_CAST_OK; uint8 school_immune = 0; uint32 mechanic_immune = 0; @@ -4421,7 +4406,7 @@ uint8 Spell::CheckCasterAuras() const } //Check whether the cast should be prevented by any state you might have. - uint8 prevented_reason = 0; + SpellCastResult prevented_reason = SPELL_CAST_OK; // Have to check if there is a stun aura. Otherwise will have problems with ghost aura apply while logging out uint32 unitflag = m_caster->GetUInt32Value(UNIT_FIELD_FLAGS); // Get unit state if(unitflag & UNIT_FLAG_STUNNED && !(m_spellInfo->AttributesEx5 & SPELL_ATTR_EX5_USABLE_WHILE_STUNNED)) @@ -4485,7 +4470,7 @@ uint8 Spell::CheckCasterAuras() const else return prevented_reason; } - return 0; // all ok + return SPELL_CAST_OK; } bool Spell::CanAutoCast(Unit* target) @@ -4514,9 +4499,9 @@ bool Spell::CanAutoCast(Unit* target) } } - int16 result = PetCanCast(target); + SpellCastResult result = CheckPetCast(target); - if(result == -1 || result == SPELL_FAILED_UNIT_NOT_INFRONT) + if(result == SPELL_CAST_OK || result == SPELL_FAILED_UNIT_NOT_INFRONT) { FillTargetMap(); //check if among target units, our WANTED target is as well (->only self cast spells return false) @@ -4527,12 +4512,13 @@ bool Spell::CanAutoCast(Unit* target) return false; //target invalid } -uint8 Spell::CheckRange(bool strict) +SpellCastResult Spell::CheckRange(bool strict) { //float range_mod; // self cast doesn't need range checking -- also for Starshards fix - if (m_spellInfo->rangeIndex == 1) return 0; + if (m_spellInfo->rangeIndex == 1) + return SPELL_CAST_OK; // i do not know why we need this /*if (strict) //add radius of caster @@ -4583,7 +4569,7 @@ uint8 Spell::CheckRange(bool strict) return SPELL_FAILED_TOO_CLOSE; } - return 0; // ok + return SPELL_CAST_OK; } int32 Spell::CalculatePowerCost() @@ -4654,18 +4640,18 @@ int32 Spell::CalculatePowerCost() return powerCost; } -uint8 Spell::CheckPower() +SpellCastResult Spell::CheckPower() { // item cast not used power if(m_CastItem) - return 0; + return SPELL_CAST_OK; // health as power used - need check health amount if(m_spellInfo->powerType == POWER_HEALTH) { if(m_caster->GetHealth() <= m_powerCost) return SPELL_FAILED_CASTER_AURASTATE; - return 0; + return SPELL_CAST_OK; } // Check valid power type if( m_spellInfo->powerType >= MAX_POWERS ) @@ -4674,8 +4660,8 @@ uint8 Spell::CheckPower() return SPELL_FAILED_UNKNOWN; } - uint8 failReason = CheckRuneCost(m_spellInfo->runeCostID); - if(failReason) + SpellCastResult failReason = CheckRuneCost(m_spellInfo->runeCostID); + if(failReason != SPELL_CAST_OK) return failReason; // Check power amount @@ -4683,15 +4669,14 @@ uint8 Spell::CheckPower() if(m_caster->GetPower(powerType) < m_powerCost) return SPELL_FAILED_NO_POWER; else - return 0; + return SPELL_CAST_OK; } -uint8 Spell::CheckItems() +SpellCastResult Spell::CheckItems() { if (m_caster->GetTypeId() != TYPEID_PLAYER) - return 0; + return SPELL_CAST_OK; - uint32 itemid, itemcount; Player* p_caster = (Player*)m_caster; if(!m_CastItem) @@ -4701,77 +4686,72 @@ uint8 Spell::CheckItems() } else { - itemid = m_CastItem->GetEntry(); + uint32 itemid = m_CastItem->GetEntry(); if( !p_caster->HasItemCount(itemid,1) ) return SPELL_FAILED_ITEM_NOT_READY; - else - { - ItemPrototype const *proto = m_CastItem->GetProto(); - if(!proto) - return SPELL_FAILED_ITEM_NOT_READY; - for (int i = 0; i<5; i++) + ItemPrototype const *proto = m_CastItem->GetProto(); + if(!proto) + return SPELL_FAILED_ITEM_NOT_READY; + + for (int i = 0; i<5; i++) + if (proto->Spells[i].SpellCharges) + if(m_CastItem->GetSpellCharges(i)==0) + return SPELL_FAILED_NO_CHARGES_REMAIN; + + // consumable cast item checks + if (proto->Class == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) + { + // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example + SpellCastResult failReason = SPELL_CAST_OK; + for (int i = 0; i < 3; i++) { - if (proto->Spells[i].SpellCharges) + // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster + if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + continue; + + if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) { - if(m_CastItem->GetSpellCharges(i)==0) - return SPELL_FAILED_NO_CHARGES_REMAIN; + if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) + { + failReason = SPELL_FAILED_ALREADY_AT_FULL_HEALTH; + continue; + } + else + { + failReason = SPELL_CAST_OK; + break; + } } - } - uint32 ItemClass = proto->Class; - if (ItemClass == ITEM_CLASS_CONSUMABLE && m_targets.getUnitTarget()) - { - // such items should only fail if there is no suitable effect at all - see Rejuvenation Potions for example - uint8 failReason = 0; - for (int i = 0; i < 3; i++) + // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... + if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) { - // skip check, pet not required like checks, and for TARGET_PET m_targets.getUnitTarget() is not the real target but the caster - if (m_spellInfo->EffectImplicitTargetA[i] == TARGET_PET) + if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) + { + failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; continue; + } - if (m_spellInfo->Effect[i] == SPELL_EFFECT_HEAL) + Powers power = Powers(m_spellInfo->EffectMiscValue[i]); + if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) { - if (m_targets.getUnitTarget()->GetHealth() == m_targets.getUnitTarget()->GetMaxHealth()) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_HEALTH; - continue; - } - else - { - failReason = 0; - break; - } + failReason = SPELL_FAILED_ALREADY_AT_FULL_POWER; + continue; } - - // Mana Potion, Rage Potion, Thistle Tea(Rogue), ... - if (m_spellInfo->Effect[i] == SPELL_EFFECT_ENERGIZE) + else { - if(m_spellInfo->EffectMiscValue[i] < 0 || m_spellInfo->EffectMiscValue[i] >= MAX_POWERS) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - continue; - } - - Powers power = Powers(m_spellInfo->EffectMiscValue[i]); - if (m_targets.getUnitTarget()->GetPower(power) == m_targets.getUnitTarget()->GetMaxPower(power)) - { - failReason = (uint8)SPELL_FAILED_ALREADY_AT_FULL_POWER; - continue; - } - else - { - failReason = 0; - break; - } + failReason = SPELL_CAST_OK; + break; } } - if (failReason) - return failReason; } + if (failReason != SPELL_CAST_OK) + return failReason; } } + // check target item if(m_targets.getItemTargetGUID()) { if(m_caster->GetTypeId() != TYPEID_PLAYER) @@ -4790,6 +4770,7 @@ uint8 Spell::CheckItems() return SPELL_FAILED_EQUIPPED_ITEM_CLASS; } + // check spell focus object if(m_spellInfo->RequiresSpellFocus) { CellPair p(Trinity::ComputeCellPair(m_caster->GetPositionX(), m_caster->GetPositionY())); @@ -4805,11 +4786,12 @@ uint8 Spell::CheckItems() cell_lock->Visit(cell_lock, object_checker, *MapManager::Instance().GetMap(m_caster->GetMapId(), m_caster)); if(!ok) - return (uint8)SPELL_FAILED_REQUIRES_SPELL_FOCUS; + return SPELL_FAILED_REQUIRES_SPELL_FOCUS; focusObject = ok; // game object found in range } + // check reagents if (!p_caster->CanNoReagentCast(m_spellInfo)) { for(uint32 i=0;i<8;i++) @@ -4817,8 +4799,8 @@ uint8 Spell::CheckItems() if(m_spellInfo->Reagent[i] <= 0) continue; - itemid = m_spellInfo->Reagent[i]; - itemcount = m_spellInfo->ReagentCount[i]; + uint32 itemid = m_spellInfo->Reagent[i]; + uint32 itemcount = m_spellInfo->ReagentCount[i]; // if CastItem is also spell reagent if( m_CastItem && m_CastItem->GetEntry() == itemid ) @@ -4838,10 +4820,11 @@ uint8 Spell::CheckItems() } } if( !p_caster->HasItemCount(itemid,itemcount) ) - return (uint8)SPELL_FAILED_ITEM_NOT_READY; //0x54 + return SPELL_FAILED_ITEM_NOT_READY; //0x54 } } + // check totem-item requirements (items presence in inventory) uint32 totems = 2; for(int i=0;i<2;++i) { @@ -4856,9 +4839,9 @@ uint8 Spell::CheckItems() totems -= 1; } if(totems != 0) - return (uint8)SPELL_FAILED_TOTEMS; //0x7C + return SPELL_FAILED_TOTEMS; //0x7C - //Check items for TotemCategory + // Check items for TotemCategory (items presence in inventory) uint32 TotemCategory = 2; for(int i=0;i<2;++i) { @@ -4874,8 +4857,9 @@ uint8 Spell::CheckItems() TotemCategory -= 1; } if(TotemCategory != 0) - return (uint8)SPELL_FAILED_TOTEM_CATEGORY; //0x7B + return SPELL_FAILED_TOTEM_CATEGORY; //0x7B + // special checks for spell effects for(int i = 0; i < 3; i++) { switch (m_spellInfo->Effect[i]) @@ -5077,7 +5061,7 @@ uint8 Spell::CheckItems() } } - return uint8(0); + return SPELL_CAST_OK; } void Spell::Delayed() // only called in DealDamage() @@ -5236,7 +5220,7 @@ CurrentSpellTypes Spell::GetCurrentContainer() return(CURRENT_GENERIC_SPELL); } -bool Spell::CheckTarget( Unit* target, uint32 eff, bool hitPhase ) +bool Spell::CheckTarget( Unit* target, uint32 eff ) { // Check targets for creature type mask and remove not appropriate (skip explicit self target case, maybe need other explicit targets) if(m_spellInfo->EffectImplicitTargetA[eff]!=TARGET_SELF) diff --git a/src/game/Spell.h b/src/game/Spell.h index 0e87a0a01e3..66b98e7d566 100644 --- a/src/game/Spell.h +++ b/src/game/Spell.h @@ -365,14 +365,14 @@ class Spell void finish(bool ok = true); void TakePower(); void TakeAmmo(); - uint8 CheckRuneCost(uint32 runeCostID); + void TakeRunePower(); void TakeReagents(); void TakeCastItem(); void TriggerSpell(); - uint8 CanCast(bool strict); - int16 PetCanCast(Unit* target); - bool CanAutoCast(Unit* target); + + SpellCastResult CheckCast(bool strict); + SpellCastResult CheckPetCast(Unit* target); // handlers void handle_immediate(); @@ -381,10 +381,11 @@ class Spell void _handle_immediate_phase(); void _handle_finish_phase(); - uint8 CheckItems(); - uint8 CheckRange(bool strict); - uint8 CheckPower(); - uint8 CheckCasterAuras() const; + SpellCastResult CheckItems(); + SpellCastResult CheckRange(bool strict); + SpellCastResult CheckPower(); + SpellCastResult CheckRuneCost(uint32 runeCostID); + SpellCastResult CheckCasterAuras() const; int32 CalculateDamage(uint8 i, Unit* target) { return m_caster->CalculateSpellDamage(m_spellInfo,i,m_currentBasePoints[i],target); } int32 CalculatePowerCost(); @@ -403,9 +404,10 @@ class Spell void SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap); Unit* SelectMagnetTarget(); - bool CheckTarget( Unit* target, uint32 eff, bool hitPhase ); + bool CheckTarget( Unit* target, uint32 eff ); + bool CanAutoCast(Unit* target); - void SendCastResult(uint8 result); + void SendCastResult(SpellCastResult result); void SendSpellStart(); void SendSpellGo(); void SendSpellCooldown(); diff --git a/src/game/SpellEffects.cpp b/src/game/SpellEffects.cpp index 5cfb00588c5..309cf6e5816 100644 --- a/src/game/SpellEffects.cpp +++ b/src/game/SpellEffects.cpp @@ -3104,7 +3104,7 @@ void Spell::EffectOpenLock(uint32 effIndex) if( goInfo->type == GAMEOBJECT_TYPE_BUTTON && goInfo->button.noDamageImmune || goInfo->type == GAMEOBJECT_TYPE_GOOBER && goInfo->goober.losOK ) { - //CanUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CheckCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -3116,7 +3116,7 @@ void Spell::EffectOpenLock(uint32 effIndex) } else if (goInfo->type == GAMEOBJECT_TYPE_FLAGSTAND) { - //CanUseBattleGroundObject() already called in CanCast() + //CanUseBattleGroundObject() already called in CheckCast() // in battleground check if(BattleGround *bg = player->GetBattleGround()) { @@ -3156,7 +3156,7 @@ void Spell::EffectOpenLock(uint32 effIndex) SendLoot(guid, LOOT_SKINNING); - // not allow use skill grou at item base open + // not allow use skill grow at item base open if(!m_CastItem && skillId != SKILL_NONE) { // update skill if really known diff --git a/src/game/SpellMgr.cpp b/src/game/SpellMgr.cpp index 109c846710a..5e21c4700c3 100644 --- a/src/game/SpellMgr.cpp +++ b/src/game/SpellMgr.cpp @@ -780,13 +780,13 @@ bool IsAuraAddedBySpell(uint32 auraType, uint32 spellId) return false; } -uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) +SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) { // talents that learn spells can have stance requirements that need ignore // (this requirement only for client-side stance show in talent description) if( GetTalentSpellCost(spellInfo->Id) > 0 && (spellInfo->Effect[0]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[1]==SPELL_EFFECT_LEARN_SPELL || spellInfo->Effect[2]==SPELL_EFFECT_LEARN_SPELL) ) - return 0; + return SPELL_CAST_OK; uint32 stanceMask = (form ? 1 << (form - 1) : 0); @@ -794,7 +794,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) return SPELL_FAILED_NOT_SHAPESHIFT; if (stanceMask & spellInfo->Stances) // can explicitly be casted in this stance - return 0; + return SPELL_CAST_OK; bool actAsShifted = false; if (form > 0) @@ -803,7 +803,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) if (!shapeInfo) { sLog.outError("GetErrorAtShapeshiftedCast: unknown shapeshift %u", form); - return 0; + return SPELL_CAST_OK; } actAsShifted = !(shapeInfo->flags1 & 1); // shapeshift acts as normal form for spells } @@ -822,7 +822,7 @@ uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form) return SPELL_FAILED_ONLY_SHAPESHIFT; } - return 0; + return SPELL_CAST_OK; } void SpellMgr::LoadSpellTargetPositions() @@ -2759,7 +2759,7 @@ void SpellMgr::LoadSpellAreas() sLog.outString( ">> Loaded %u spell area requirements", count ); } -uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) +SpellCastResult SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player) { // normal case if( spellInfo->AreaGroupId > 0) @@ -2785,7 +2785,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint for(SpellAreaMap::const_iterator itr = saBounds.first; itr != saBounds.second; ++itr) { if(itr->second.IsFitToRequirements(player,zone_id,area_id)) - return 0; + return SPELL_CAST_OK; } return SPELL_FAILED_INCORRECT_AREA; } @@ -2795,9 +2795,9 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint { case 23333: // Warsong Flag case 23335: // Silverwing Flag - return map_id == 489 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 489 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 34976: // Netherstorm Flag - return map_id == 566 && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return map_id == 566 && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; case 2584: // Waiting to Resurrect case 22011: // Spirit Heal Channel case 22012: // Spirit Heal @@ -2810,7 +2810,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleGround() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleGround() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 44521: // Preparation { @@ -2825,7 +2825,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint return SPELL_FAILED_REQUIRES_AREA; BattleGround* bg = player->GetBattleGround(); - return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; + return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32724: // Gold Team (Alliance) case 32725: // Green Team (Alliance) @@ -2836,7 +2836,7 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint if(!mapEntry) return SPELL_FAILED_INCORRECT_AREA; - return mapEntry->IsBattleArena() && player && player->InBattleGround() ? 0 : SPELL_FAILED_REQUIRES_AREA; + return mapEntry->IsBattleArena() && player && player->InBattleGround() ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } case 32727: // Arena Preparation { @@ -2851,11 +2851,11 @@ uint8 SpellMgr::GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint return SPELL_FAILED_REQUIRES_AREA; BattleGround* bg = player->GetBattleGround(); - return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? 0 : SPELL_FAILED_REQUIRES_AREA; + return bg && bg->GetStatus()==STATUS_WAIT_JOIN ? SPELL_CAST_OK : SPELL_FAILED_REQUIRES_AREA; } } - return 0; + return SPELL_CAST_OK; } void SpellMgr::LoadSkillLineAbilityMap() diff --git a/src/game/SpellMgr.h b/src/game/SpellMgr.h index 8c2b5ccef93..9c671391bd5 100644 --- a/src/game/SpellMgr.h +++ b/src/game/SpellMgr.h @@ -285,7 +285,7 @@ inline bool IsAutoRepeatRangedSpell(SpellEntry const* spellInfo) return (spellInfo->Attributes & SPELL_ATTR_RANGED) && (spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG); } -uint8 GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form); +SpellCastResult GetErrorAtShapeshiftedCast (SpellEntry const *spellInfo, uint32 form); inline bool IsChanneledSpell(SpellEntry const* spellInfo) { @@ -915,7 +915,7 @@ class SpellMgr return NULL; } - uint8 GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL); + SpellCastResult GetSpellAllowedInLocationError(SpellEntry const *spellInfo, uint32 map_id, uint32 zone_id, uint32 area_id, Player const* player = NULL); SpellAreaMapBounds GetSpellAreaMapBounds(uint32 spell_id) const { diff --git a/src/game/Unit.cpp b/src/game/Unit.cpp index edd099b63b7..d957988cc05 100644 --- a/src/game/Unit.cpp +++ b/src/game/Unit.cpp @@ -3385,7 +3385,7 @@ void Unit::_UpdateAutoRepeatSpell() if (isAttackReady(RANGED_ATTACK)) { // Check if able to cast - if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CanCast(true)) + if(m_currentSpells[CURRENT_AUTOREPEAT_SPELL]->CheckCast(true) != SPELL_CAST_OK) { InterruptSpell(CURRENT_AUTOREPEAT_SPELL); return; @@ -11955,8 +11955,11 @@ Player* Unit::GetSpellModOwner() const } ///----------Pet responses methods----------------- -void Unit::SendPetCastFail(uint32 spellid, uint8 msg) +void Unit::SendPetCastFail(uint32 spellid, SpellCastResult msg) { + if(msg == SPELL_CAST_OK) + return; + Unit *owner = GetCharmerOrOwner(); if(!owner || owner->GetTypeId() != TYPEID_PLAYER) return; diff --git a/src/game/Unit.h b/src/game/Unit.h index c3b786f2715..c977a1f1b0e 100644 --- a/src/game/Unit.h +++ b/src/game/Unit.h @@ -1516,7 +1516,7 @@ class TRINITY_DLL_SPEC Unit : public WorldObject void ClearComboPointHolders(); ///----------Pet responses methods----------------- - void SendPetCastFail(uint32 spellid, uint8 msg); + void SendPetCastFail(uint32 spellid, SpellCastResult msg); void SendPetActionFeedback (uint8 msg); void SendPetTalk (uint32 pettalk); void SendPetSpellCooldown (uint32 spellid, time_t cooltime); |