Merge branch 'master' into 308

This commit is contained in:
tomrus88 2009-01-13 20:08:41 +03:00
commit 77f11162dc
464 changed files with 12368 additions and 5663 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2008 MaNGOS <http://getmangos.com/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -298,7 +298,7 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
break;
default:
// Wands
if (m_spellInfo->AttributesEx3 & SPELL_ATTR_EX3_REQ_WAND)
if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)
m_attackType = RANGED_ATTACK;
else
m_attackType = BASE_ATTACK;
@ -351,11 +351,8 @@ Spell::Spell( Unit* Caster, SpellEntry const *info, bool triggered, uint64 origi
m_glyphIndex = 0;
m_triggeredByAuraSpell = NULL;
//Auto Shot & Shoot
if( m_spellInfo->AttributesEx2 == 0x000020 && !triggered )
m_autoRepeat = true;
else
m_autoRepeat = false;
//Auto Shot & Shoot (wand)
m_autoRepeat = IsAutoRepeatRangedSpell(m_spellInfo);
m_runesState = 0;
m_powerCost = 0; // setup to correct value in Spell::prepare, don't must be used before.
@ -424,7 +421,7 @@ void Spell::FillTargetMap()
case TARGET_ALL_AROUND_CASTER:
if( m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_PARTY ||
m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_FRIENDLY_UNITS_AROUND_CASTER ||
m_spellInfo->EffectImplicitTargetB[i]==TARGET_RANDOM_RAID_MEMBER )
m_spellInfo->EffectImplicitTargetB[i]==TARGET_ALL_RAID_AROUND_CASTER )
{
SetTargetMap(i,m_spellInfo->EffectImplicitTargetB[i],tmpUnitMap);
}
@ -584,14 +581,12 @@ void Spell::FillTargetMap()
tmpUnitMap.push_back(m_caster);
break;
case SPELL_EFFECT_SUMMON_CHANGE_ITEM:
case SPELL_EFFECT_SUMMON_WILD:
case SPELL_EFFECT_SUMMON_GUARDIAN:
case SPELL_EFFECT_TRANS_DOOR:
case SPELL_EFFECT_ADD_FARSIGHT:
case SPELL_EFFECT_APPLY_GLYPH:
case SPELL_EFFECT_STUCK:
case SPELL_EFFECT_FEED_PET:
case SPELL_EFFECT_DESTROY_ALL_TOTEMS:
case SPELL_EFFECT_SUMMON_DEMON:
case SPELL_EFFECT_SKILL:
tmpUnitMap.push_back(m_caster);
break;
@ -602,7 +597,6 @@ void Spell::FillTargetMap()
case SPELL_EFFECT_ENCHANT_ITEM:
case SPELL_EFFECT_ENCHANT_ITEM_TEMPORARY:
case SPELL_EFFECT_DISENCHANT:
case SPELL_EFFECT_FEED_PET:
case SPELL_EFFECT_PROSPECTING:
case SPELL_EFFECT_MILLING:
if(m_targets.getItemTarget())
@ -705,6 +699,9 @@ void Spell::prepareDataForTriggerSystem()
case SPELLFAMILY_WARLOCK: // For Hellfire Effect / Rain of Fire / Seed of Corruption triggers need do it
if (m_spellInfo->SpellFamilyFlags & 0x0000800000000060LL) m_canTrigger = true;
break;
case SPELLFAMILY_PRIEST: // For Penance heal/damage triggers need do it
if (m_spellInfo->SpellFamilyFlags & 0x0001800000000000LL) m_canTrigger = true;
break;
case SPELLFAMILY_HUNTER: // Hunter Explosive Trap Effect/Immolation Trap Effect/Frost Trap Aura/Snake Trap Effect
if (m_spellInfo->SpellFamilyFlags & 0x0000200000000014LL) m_canTrigger = true;
break;
@ -725,21 +722,30 @@ void Spell::prepareDataForTriggerSystem()
m_procVictim = PROC_FLAG_TAKEN_MELEE_SPELL_HIT;
break;
case SPELL_DAMAGE_CLASS_RANGED:
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
break;
default:
if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
// Auto attack
if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG)
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
}
else if (m_spellInfo->Id == 5019) // Wands
else // Ranged spell attack
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_SPELL_HIT;
}
else
break;
default:
if (IsPositiveSpell(m_spellInfo->Id)) // Check for positive spell
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_POSITIVE_SPELL;
m_procVictim = PROC_FLAG_TAKEN_POSITIVE_SPELL;
}
else if (m_spellInfo->AttributesEx2 & SPELL_ATTR_EX2_AUTOREPEAT_FLAG) // Wands auto attack
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_RANGED_HIT;
m_procVictim = PROC_FLAG_TAKEN_RANGED_HIT;
}
else // Negative spell
{
m_procAttacker = PROC_FLAG_SUCCESSFUL_NEGATIVE_SPELL_HIT;
m_procVictim = PROC_FLAG_TAKEN_NEGATIVE_SPELL_HIT;
@ -1000,21 +1006,8 @@ void Spell::DoAllEffectOnTarget(TargetInfo *target)
caster->DealSpellDamage(&damageInfo, true);
// Shadow Word: Death - deals damage equal to damage done to caster if victim is not killed
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PRIEST && m_spellInfo->SpellFamilyFlags&0x0000000200000000LL &&
caster != unitTarget && unitTarget->isAlive())
{
// Redirect damage to caster if victim Alive
damageInfo.target = caster;
damageInfo.absorb = 0;
damageInfo.resist = 0;
damageInfo.blocked = 0;
// Send log damage message to client
caster->SendSpellNonMeleeDamageLog(&damageInfo);
caster->DealSpellDamage(&damageInfo, true);
}
// Judgement of Blood
else if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153)
if (m_spellInfo->SpellFamilyName == SPELLFAMILY_PALADIN && m_spellInfo->SpellFamilyFlags & 0x0000000800000000LL && m_spellInfo->SpellIconID==153)
{
int32 damagePoint = damageInfo.damage * 33 / 100;
m_caster->CastCustomSpell(m_caster, 32220, &damagePoint, NULL, NULL, true);
@ -1070,8 +1063,8 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
// Recheck immune (only for delayed spells)
if( m_spellInfo->speed && (
unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo),true) ||
unit->IsImmunedToSpell(m_spellInfo,true) ))
unit->IsImmunedToDamage(GetSpellSchoolMask(m_spellInfo)) ||
unit->IsImmunedToSpell(m_spellInfo)))
{
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_IMMUNE);
return;
@ -1090,6 +1083,15 @@ void Spell::DoSpellHitOnUnit(Unit *unit, const uint32 effectMask)
if( m_caster != unit )
{
// Recheck UNIT_FLAG_NON_ATTACKABLE for delayed spells
if (m_spellInfo->speed > 0.0f &&
unit->HasFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE) &&
unit->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
{
m_caster->SendSpellMiss(unit, m_spellInfo->Id, SPELL_MISS_EVADE);
return;
}
if( !m_caster->IsFriendlyTo(unit) )
{
// for delayed spells ignore not visible explicit target
@ -1521,6 +1523,7 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
case TARGET_ALL_PARTY_AROUND_CASTER:
case TARGET_ALL_PARTY_AROUND_CASTER_2:
case TARGET_ALL_PARTY:
case TARGET_ALL_RAID_AROUND_CASTER:
{
Player *pTarget = m_caster->GetCharmerOrOwnerPlayerOrPlayerItself();
Group *pGroup = pTarget ? pTarget->GetGroup() : NULL;
@ -1534,7 +1537,9 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
Player* Target = itr->getSource();
// IsHostileTo check duel and controlled by enemy
if( Target && Target->GetSubGroup()==subgroup && !m_caster->IsHostileTo(Target) )
if( Target &&
(cur==TARGET_ALL_RAID_AROUND_CASTER || Target->GetSubGroup()==subgroup) &&
!m_caster->IsHostileTo(Target) )
{
if( m_caster->IsWithinDistInMap(Target, radius) )
TagUnitMap.push_back(Target);
@ -1555,12 +1560,6 @@ void Spell::SetTargetMap(uint32 i,uint32 cur,std::list<Unit*> &TagUnitMap)
TagUnitMap.push_back(pet);
}
}break;
case TARGET_RANDOM_RAID_MEMBER:
{
if (m_caster->GetTypeId() == TYPEID_PLAYER)
if(Player* target = ((Player*)m_caster)->GetNextRandomRaidMember(radius))
TagUnitMap.push_back(target);
}break;
case TARGET_SINGLE_FRIEND:
case TARGET_SINGLE_FRIEND_2:
{
@ -2066,7 +2065,7 @@ void Spell::prepare(SpellCastTargets * targets, Aura* triggeredByAura)
m_caster->m_Events.AddEvent(Event, m_caster->m_Events.CalculateTime(1));
//Prevent casting at cast another spell (ServerSide check)
if(m_caster->IsNonMeleeSpellCasted(false, true) && m_cast_count)
if(m_caster->IsNonMeleeSpellCasted(false, true, true) && m_cast_count)
{
SendCastResult(SPELL_FAILED_SPELL_IN_PROGRESS);
finish(false);
@ -2272,8 +2271,12 @@ void Spell::handle_immediate()
// start channeling if applicable
if(IsChanneledSpell(m_spellInfo))
{
m_spellState = SPELL_STATE_CASTING;
SendChannelStart(GetSpellDuration(m_spellInfo));
int32 duration = GetSpellDuration(m_spellInfo);
if (duration)
{
m_spellState = SPELL_STATE_CASTING;
SendChannelStart(duration);
}
}
// process immediate effects (items, ground, etc.) also initialize some variables
@ -2455,7 +2458,7 @@ void Spell::SendSpellCooldown()
// shoot spells used equipped item cooldown values already assigned in GetAttackTime(RANGED_ATTACK)
// prevent 0 cooldowns set by another way
if (rec <= 0 && catrec <= 0 && (cat == 76 || cat == 351))
if (rec <= 0 && catrec <= 0 && (cat == 76 || IsAutoRepeatRangedSpell(m_spellInfo) && m_spellInfo->Id != SPELL_ID_AUTOSHOT))
rec = _player->GetAttackTime(RANGED_ATTACK);
// Now we have cooldown data (if found any), time to apply mods
@ -2493,7 +2496,7 @@ void Spell::SendSpellCooldown()
if(*i_scset == m_spellInfo->Id) // skip main spell, already handled above
continue;
_player->AddSpellCooldown(m_spellInfo->Id, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);
_player->AddSpellCooldown(*i_scset, m_CastItem ? m_CastItem->GetEntry() : 0, catrecTime);
}
}
}
@ -2689,6 +2692,68 @@ void Spell::finish(bool ok)
((Player*)m_caster)->ClearComboPoints();
}
// Post effects apply on spell targets in some spells
if(!m_UniqueTargetInfo.empty())
{
uint32 spellId = 0;
switch(m_spellInfo->SpellFamilyName)
{
case SPELLFAMILY_GENERIC:
{
if (m_spellInfo->Mechanic == MECHANIC_BANDAGE) // Bandages
spellId = 11196; // Recently Bandaged
else if(m_spellInfo->SpellIconID == 1662 && m_spellInfo->AttributesEx & 0x20) // Blood Fury (Racial)
spellId = 23230; // Blood Fury - Healing Reduction
break;
}
case SPELLFAMILY_MAGE:
{
if (m_spellInfo->SpellFamilyFlags&0x0000008000000000LL) // Ice Block
spellId = 41425; // Hypothermia
break;
}
case SPELLFAMILY_PRIEST:
{
if (m_spellInfo->Mechanic == MECHANIC_SHIELD &&
m_spellInfo->SpellIconID == 566) // Power Word: Shield
spellId = 6788; // Weakened Soul
break;
}
case SPELLFAMILY_PALADIN:
{
if (m_spellInfo->SpellFamilyFlags&0x0000000000400080LL) // Divine Shield, Divine Protection or Hand of Protection
spellId = 25771; // Forbearance
break;
}
case SPELLFAMILY_SHAMAN:
{
if (m_spellInfo->Id == 2825) // Bloodlust
spellId = 57724; // Sated
else if (m_spellInfo->Id == 32182) // Heroism
spellId = 57723; // Exhaustion
break;
}
default:
break;
}
if (spellId)
{
for(std::list<TargetInfo>::iterator ihit= m_UniqueTargetInfo.begin();ihit != m_UniqueTargetInfo.end();++ihit)
{
Unit* unit = m_caster->GetGUID()==ihit->targetGUID ? m_caster : ObjectAccessor::GetUnit(*m_caster, ihit->targetGUID);
if (unit)
{
// TODO: fix me use cast spell (now post spell can immune by this spell)
// m_caster->CastSpell(unit, spellId, true, m_CastItem);
SpellEntry const *AdditionalSpellInfo = sSpellStore.LookupEntry(spellId);
if (!AdditionalSpellInfo)
continue;
Aura* AdditionalAura = CreateAura(AdditionalSpellInfo, 0, &m_currentBasePoints[0], unit, m_caster, m_CastItem);
unit->AddAura(AdditionalAura);
}
}
}
}
// call triggered spell only at successful cast (after clear combo points -> for add some if need)
if(!m_TriggerSpells.empty())
TriggerSpell();
@ -2732,8 +2797,8 @@ void Spell::SendCastResult(uint8 result)
case 45373: // Bloodberry Elixir
data << uint32(4075);
break;
default: // default case
data << uint32(m_spellInfo->AreaId);
default: // default case (don't must be)
data << uint32(0);
break;
}
break;
@ -3208,7 +3273,7 @@ void Spell::TakeCastItem()
if (charges)
{
(charges > 0) ? --charges : ++charges; // abs(charges) less at 1 after use
if (proto->Stackable < 2)
if (proto->Stackable == 1)
m_CastItem->SetSpellCharges(i, charges);
m_CastItem->SetState(ITEM_CHANGED, (Player*)m_caster);
}
@ -3535,6 +3600,12 @@ uint8 Spell::CanCast(bool strict)
if(m_spellInfo->CasterAuraStateNot && m_caster->HasAuraState(AuraState(m_spellInfo->CasterAuraStateNot)))
return SPELL_FAILED_CASTER_AURASTATE;
// Caster aura req check if need
if(m_spellInfo->casterAuraSpell && !m_caster->HasAura(m_spellInfo->casterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
if(m_spellInfo->excludeCasterAuraSpell && m_caster->HasAura(m_spellInfo->excludeCasterAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
// cancel autorepeat spells if cast start when moving
// (not wand currently autorepeat cast delayed to moving stop anyway in spell update code)
if( m_caster->GetTypeId()==TYPEID_PLAYER && ((Player*)m_caster)->isMoving() )
@ -3553,6 +3624,12 @@ uint8 Spell::CanCast(bool strict)
if(m_spellInfo->TargetAuraStateNot && target->HasAuraState(AuraState(m_spellInfo->TargetAuraStateNot)))
return SPELL_FAILED_TARGET_AURASTATE;
// Target aura req check if need
if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
if(m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell))
return SPELL_FAILED_CASTER_AURASTATE;
if(target != m_caster)
{
// target state requirements (apply to non-self only), to allow cast affects to self like Dirty Deeds
@ -3628,7 +3705,7 @@ uint8 Spell::CanCast(bool strict)
if(IsPositiveSpell(m_spellInfo->Id))
{
if(target->IsImmunedToSpell(m_spellInfo,false))
if(target->IsImmunedToSpell(m_spellInfo))
return SPELL_FAILED_TARGET_AURASTATE;
}
@ -3671,8 +3748,8 @@ uint8 Spell::CanCast(bool strict)
return SPELL_FAILED_NOT_IN_ARENA;
// zone check
if(!IsSpellAllowedInLocation(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId()))
return SPELL_FAILED_REQUIRES_AREA;
if(uint8 res= GetSpellAllowedInLocationError(m_spellInfo,m_caster->GetMapId(),m_caster->GetZoneId(),m_caster->GetAreaId()))
return res;
// not let players cast spells at mount (and let do it to creatures)
if( m_caster->IsMounted() && m_caster->GetTypeId()==TYPEID_PLAYER && !m_IsTriggeredSpell &&
@ -3824,7 +3901,7 @@ uint8 Spell::CanCast(bool strict)
}
}
if(!m_triggeredByAuraSpell)
if(!m_IsTriggeredSpell)
if(uint8 castResult = CheckRange(strict))
return castResult;
@ -3833,7 +3910,7 @@ uint8 Spell::CanCast(bool strict)
return castResult;
}
if(!m_triggeredByAuraSpell) // triggered spell not affected by stun/etc
if(!m_IsTriggeredSpell) // triggered spell not affected by stun/etc
if(uint8 castResult = CheckCasterAuras())
return castResult;
@ -3935,7 +4012,11 @@ uint8 Spell::CanCast(bool strict)
}
case SPELL_EFFECT_FEED_PET:
{
if (m_caster->GetTypeId() != TYPEID_PLAYER || !m_targets.getItemTarget() )
if (m_caster->GetTypeId() != TYPEID_PLAYER)
return SPELL_FAILED_BAD_TARGETS;
Item* foodItem = m_targets.getItemTarget();
if(!foodItem)
return SPELL_FAILED_BAD_TARGETS;
Pet* pet = m_caster->GetPet();
@ -3943,10 +4024,10 @@ uint8 Spell::CanCast(bool strict)
if(!pet)
return SPELL_FAILED_NO_PET;
if(!pet->HaveInDiet(m_targets.getItemTarget()->GetProto()))
if(!pet->HaveInDiet(foodItem->GetProto()))
return SPELL_FAILED_WRONG_PET_FOOD;
if(!pet->GetCurrentFoodBenefitLevel(m_targets.getItemTarget()->GetProto()->ItemLevel))
if(!pet->GetCurrentFoodBenefitLevel(foodItem->GetProto()->ItemLevel))
return SPELL_FAILED_FOOD_LOWLEVEL;
if(m_caster->isInCombat() || pet->isInCombat())
@ -4149,9 +4230,7 @@ uint8 Spell::CanCast(bool strict)
break;
}
// This is generic summon effect now and don't make this check for summon types similar
// SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
// These won't show up in m_caster->GetPetGUID()
// This is generic summon effect
case SPELL_EFFECT_SUMMON:
{
switch(m_spellInfo->EffectMiscValueB[i])
@ -4171,10 +4250,8 @@ uint8 Spell::CanCast(bool strict)
}
break;
}
// Don't make this check for SPELL_EFFECT_SUMMON_CRITTER, SPELL_EFFECT_SUMMON_WILD or SPELL_EFFECT_SUMMON_GUARDIAN.
// These won't show up in m_caster->GetPetGUID()
// Not used for summon?
case SPELL_EFFECT_SUMMON_PHANTASM:
case SPELL_EFFECT_SUMMON_DEMON:
{
if(m_caster->GetPetGUID())
return SPELL_FAILED_ALREADY_HAVE_SUMMON;
@ -4298,10 +4375,7 @@ uint8 Spell::CanCast(bool strict)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
// Ignore map check if spell have AreaId. AreaId already checked and this prevent special mount spells
if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaId)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
if (m_caster->GetAreaId()==35)
if (m_caster->GetTypeId()==TYPEID_PLAYER && !sMapStore.LookupEntry(m_caster->GetMapId())->IsMountAllowed() && !m_IsTriggeredSpell && !m_spellInfo->AreaGroupId)
return SPELL_FAILED_NO_MOUNTS_ALLOWED;
ShapeshiftForm form = m_caster->m_form;
@ -5254,6 +5328,12 @@ bool Spell::CheckTarget( Unit* target, uint32 eff )
return false;
}
// Check Aura spell req (need for AoE spells)
if(m_spellInfo->targetAuraSpell && !target->HasAura(m_spellInfo->targetAuraSpell))
return false;
if (m_spellInfo->excludeTargetAuraSpell && target->HasAura(m_spellInfo->excludeTargetAuraSpell))
return false;
// Check targets for not_selectable unit flag and remove
// A player can cast spells on his pet (or other controlled unit) though in any state
if (target != m_caster && target->GetCharmerOrOwnerGUID() != m_caster->GetGUID())
@ -5344,7 +5424,7 @@ Unit* Spell::SelectMagnetTarget()
bool Spell::IsNeedSendToClient() const
{
return m_spellInfo->SpellVisual!=0 || IsChanneledSpell(m_spellInfo) ||
return m_spellInfo->SpellVisual[0] || m_spellInfo->SpellVisual[1] || IsChanneledSpell(m_spellInfo) ||
m_spellInfo->speed > 0.0f || !m_triggeredByAuraSpell && !m_IsTriggeredSpell;
}