void AuraInterface::MassDispel(Unit* caster, uint32 index, SpellEntry* Dispelling, uint32 MaxDispel, uint8 start, uint8 end) { WorldPacket data(SMSG_SPELLDISPELLOG, 16); Aura* aur = NULL; for(uint32 x = start; x < end; x++) { if(m_auras.find(x) != m_auras.end()) { aur = m_auras.at(x); //Nothing can dispel resurrection sickness; if(aur != NULL && !aur->IsPassive() && !(aur->GetSpellProto()->Attributes & ATTRIBUTES_IGNORE_INVULNERABILITY)) { int32 resistchance = 0; Unit* caster = aur->GetUnitCaster(); if( caster ) SM_FIValue(caster->SM[SMT_RESIST_DISPEL][0], &resistchance, aur->GetSpellProto()->SpellGroupType); if( !Rand(resistchance) ) { if(Dispelling->DispelType == DISPEL_ALL) { m_Unit->HandleProc( PROC_ON_DISPEL_AURA_VICTIM, NULL, caster, Dispelling, aur->GetSpellId() ); data.clear(); data << caster->GetNewGUID(); data << m_Unit->GetNewGUID(); data << (uint32)1;//probably dispel type data << aur->GetSpellId(); caster->SendMessageToSet(&data,true); aur->AttemptDispel( caster ); if(!--MaxDispel) return; } else if(aur->GetSpellProto()->DispelType == Dispelling->EffectMiscValue[index]) { if( (aur->GetSpellProto()->NameHash != SPELL_HASH_ICE_BARRIER && aur->GetSpellProto()->NameHash != SPELL_HASH_DIVINE_SHIELD) || Dispelling->NameHash == SPELL_HASH_MASS_DISPEL ) { m_Unit->HandleProc( PROC_ON_DISPEL_AURA_VICTIM, NULL, caster, Dispelling, aur->GetSpellId() ); data.clear(); data << caster->GetNewGUID(); data << m_Unit->GetNewGUID(); data << (uint32)1; data << aur->GetSpellId(); caster->SendMessageToSet(&data,true); aur->AttemptDispel( caster ); if(!--MaxDispel) return; } } } else if( !--MaxDispel ) return; } } } }
bool AIInterface::CanCastFuckingSpell(Unit* Target, AI_Spell* toCast, uint32 currentTime) { if(toCast->cooldown) { if((toCast->lastcast+toCast->cooldown) > currentTime) return false; } if(toCast->minHPPercentReq) if(Target->GetHealthPct() > toCast->minHPPercentReq) return false; if(toCast->ProcLimit) { if(toCast->ProcResetDelay) { if(toCast->ProcResetTimer <= currentTime) { toCast->procCounter = 0; toCast->ProcResetTimer = currentTime+toCast->ProcResetDelay; } } if(toCast->procCounter >= toCast->ProcLimit) return false; } float dist = fabs(m_Unit->CalcDistance(Target)); if(dist < toCast->mindist2cast) return false; if(toCast->maxdist2cast) if(dist > toCast->maxdist2cast) return false; if(toCast->info->powerType == POWER_TYPE_MANA) { int32 currentPower = m_Unit->GetPower(POWER_TYPE_MANA); int32 cost; if( toCast->info->ManaCostPercentage)//Percentage spells cost % of !!!BASE!!! mana cost = (m_Unit->GetUInt32Value(UNIT_FIELD_BASE_MANA)*toCast->info->ManaCostPercentage)/100; else cost = toCast->info->manaCost; cost += m_Unit->PowerCostMod[toCast->info->School];//this is not percent! cost += float2int32(cost*m_Unit->GetFloatValue(UNIT_FIELD_POWER_COST_MULTIPLIER+toCast->info->School)); //apply modifiers if( toCast->info->SpellGroupType ) { SM_FIValue(m_Unit->SM[SMT_COST][0], &cost, toCast->info->SpellGroupType); SM_PIValue(m_Unit->SM[SMT_COST][1], &cost, toCast->info->SpellGroupType); } if(cost > currentPower) return false; } return true; }
uint32 Spell::GetTargetType(uint32 implicittarget, uint32 i) { uint32 type = implicitTargetFlags[implicittarget]; //CHAIN SPELLS ALWAYS CHAIN! uint32 jumps = m_spellInfo->EffectChainTarget[i]; if(u_caster != NULL) SM_FIValue(u_caster->SM[SMT_JUMP_REDUCE][0], (int32*)&jumps, m_spellInfo->SpellGroupType); if(jumps != 0) type |= SPELL_TARGET_AREA_CHAIN; return type; }
bool DoEffect(Unit* victim, SpellEntry* CastingSpell, uint32 flag, uint32 dmg, uint32 abs, int* dmg_overwrite, uint32 weapon_damage_type) { Aura* aura = mTarget->FindAuraByNameHash(SPELL_HASH_SLICE_AND_DICE); if(aura) { // Duration of 5 combo maximum int32 dur = 21 * MSTIME_SECOND; SM_FIValue(mTarget->SM_FDur, &dur, aura->GetSpellProto()->SpellGroupType); SM_PIValue(mTarget->SM_PDur, &dur, aura->GetSpellProto()->SpellGroupType); // Set new aura's duration, reset event timer and set client visual aura aura->SetDuration(dur); sEventMgr.ModifyEventTimeLeft(aura, EVENT_AURA_REMOVE, aura->GetDuration()); mTarget->ModVisualAuraStackCount(aura, 0); } return true; }
uint32 CalculateDamage( Unit* pAttacker, Unit* pVictim, uint32 weapon_damage_type, uint64 spellgroup, SpellEntry* ability ) // spellid is used only for 2-3 spells, that have AP bonus { //TODO: Some awesome formula to determine how much damage to deal //consider this is melee damage // weapon_damage_type: 0 = melee, 1 = offhand(dualwield), 2 = ranged // Attack Power increases your base damage-per-second (DPS) by 1 for every 14 attack power. // (c) wowwiki //type of this UNIT_FIELD_ATTACK_POWER_MODS is unknown, not even uint32 disabled for now. uint32 offset; Item *it = NULL; if(pAttacker->disarmed && pAttacker->IsPlayer()) { offset=UNIT_FIELD_MINDAMAGE; it = static_cast< Player* >(pAttacker)->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND); } else if( weapon_damage_type == MELEE ) offset = UNIT_FIELD_MINDAMAGE; else if( weapon_damage_type == OFFHAND ) offset = UNIT_FIELD_MINOFFHANDDAMAGE; else // weapon_damage_type == RANGED offset = UNIT_FIELD_MINRANGEDDAMAGE; float min_damage = pAttacker->GetFloatValue(offset); float max_damage = pAttacker->GetFloatValue(offset+1); if(it) { min_damage -= it->GetProto()->Damage[0].Min; max_damage -= it->GetProto()->Damage[0].Max; } float ap = 0; float bonus; float wspeed; if(offset == UNIT_FIELD_MINRANGEDDAMAGE) { //starting from base attack power then we apply mods on it //ap += pAttacker->GetRAP(); ap += pVictim->RAPvModifier; if(!pVictim->IsPlayer() && ((Creature*)pVictim)->GetCreatureInfo()) { uint32 creatType = ((Creature*)pVictim)->GetCreatureInfo()->Type; ap += (float)pAttacker->CreatureRangedAttackPowerMod[creatType]; if(pAttacker->IsPlayer()) { min_damage = (min_damage + static_cast< Player* >(pAttacker)->IncreaseDamageByType[creatType]) * (1 + static_cast< Player* >(pAttacker)->IncreaseDamageByTypePCT[creatType]); max_damage = (max_damage + static_cast< Player* >(pAttacker)->IncreaseDamageByType[creatType]) * (1 + static_cast< Player* >(pAttacker)->IncreaseDamageByTypePCT[creatType]); } } if(pAttacker->IsPlayer()) { if(!pAttacker->disarmed) { Item *it = static_cast< Player* >(pAttacker)->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_RANGED); if(it) wspeed = (float)it->GetProto()->Delay; else wspeed = 2000; } else wspeed = (float)pAttacker->GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME); } else { wspeed = (float)pAttacker->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME); } //ranged weapon normalization. if(pAttacker->IsPlayer() && ability) { if(ability->Effect[0] == SPELL_EFFECT_DUMMYMELEE || ability->Effect[1] == SPELL_EFFECT_DUMMYMELEE || ability->Effect[2] == SPELL_EFFECT_DUMMYMELEE) { wspeed = 2800; } } //Weapon speed constant in feral forms if(pAttacker->IsPlayer()) { if(static_cast< Player* >(pAttacker)->IsInFeralForm()) { uint8 ss = static_cast< Player* >(pAttacker)->GetShapeShift(); if(ss == FORM_CAT) wspeed = 1000.0; else if(ss == FORM_DIREBEAR || ss == FORM_BEAR) wspeed = 2500.0; } } bonus = (wspeed-pAttacker->GetUInt32Value(UNIT_FIELD_RANGEDATTACKTIME))/14000.0f*ap; min_damage += bonus; max_damage += bonus; } else { //MinD = AP(28AS-(WS/7))-MaxD //starting from base attack power then we apply mods on it //ap += pAttacker->GetAP(); ap += pVictim->APvModifier; if(!pVictim->IsPlayer() && ((Creature*)pVictim)->GetCreatureInfo()) { uint32 creatType = ((Creature*)pVictim)->GetCreatureInfo()->Type; ap += (float)pAttacker->CreatureAttackPowerMod[creatType]; if(pAttacker->IsPlayer()) { min_damage = (min_damage + static_cast< Player* >(pAttacker)->IncreaseDamageByType[creatType]) * (1 + static_cast< Player* >(pAttacker)->IncreaseDamageByTypePCT[creatType]); max_damage = (max_damage + static_cast< Player* >(pAttacker)->IncreaseDamageByType[creatType]) * (1 + static_cast< Player* >(pAttacker)->IncreaseDamageByTypePCT[creatType]); } } if(pAttacker->IsPlayer()) { if(!pAttacker->disarmed) { Item *it = static_cast< Player* >(pAttacker)->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND); if(it) wspeed = (float)it->GetProto()->Delay; else wspeed = 2000; } else wspeed = (float)pAttacker->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME); if(spellgroup) { int32 apall = pAttacker->GetAP(); int32 apb=0; SM_FIValue(pAttacker->SM_PAPBonus,&apb,spellgroup); if(apb) ap += apall*((float)apb/100); else ap = float(apall); } } else { wspeed = (float)pAttacker->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME); } //Normalized weapon damage checks. if(pAttacker->IsPlayer() && ability) { if(ability->Effect[0] == SPELL_EFFECT_DUMMYMELEE || ability->Effect[1] == SPELL_EFFECT_DUMMYMELEE || ability->Effect[2] == SPELL_EFFECT_DUMMYMELEE) { it = static_cast< Player* >(pAttacker)->GetItemInterface()->GetInventoryItem(EQUIPMENT_SLOT_MAINHAND); if(it) { if(it->GetProto()->Class == 2) //weapon { if(it->GetProto()->InventoryType == INVTYPE_2HWEAPON) wspeed = 3300; else if(it->GetProto()->SubClass == 15) wspeed = 1700; else wspeed = 2400; } } } } //Weapon speed constant in feral forms if(pAttacker->IsPlayer()) { if(static_cast< Player* >(pAttacker)->IsInFeralForm()) { uint8 ss = static_cast< Player* >(pAttacker)->GetShapeShift(); if(ss == FORM_CAT) wspeed = 1000.0; else if(ss == FORM_DIREBEAR || ss == FORM_BEAR) wspeed = 2500.0; } } if (offset == UNIT_FIELD_MINDAMAGE) bonus = (wspeed-pAttacker->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME))/14000.0f*ap; else bonus = (wspeed-pAttacker->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME_01))/14000.0f*ap; min_damage += bonus; max_damage += bonus; } float diff = fabs(max_damage - min_damage); float result = min_damage; if(diff >= 1) result += float(RandomDouble(diff)); if(result >= 0) { if( pAttacker->IsPlayer() && ((Player*)pAttacker)->m_outStealthDamageBonusTimer ) { if( (uint32)UNIXTIME >= ((Player*)pAttacker)->m_outStealthDamageBonusTimer ) ((Player*)pAttacker)->m_outStealthDamageBonusTimer = 0; else result *= ((float(((Player*)pAttacker)->m_outStealthDamageBonusPct) / 100.0f) + 1.0f); } return FL2UINT(result); } return 0; }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; TargetsList* tmpMap=&m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == static_cast< Player* >( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM_FAdditionalTargets,(int32*)&jumps,m_spellInfo->SpellGroupType); } SafeAddTarget(tmpMap,firstTarget->GetGUID()); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); ++itr) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer==u_caster || !(*itr)->m_loggedInPlayer->isAlive() ) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->m_loggedInPlayer->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->m_loggedInPlayer->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->m_loggedInPlayer->GetPositionNC())) continue; } if( IsInrange(u_caster,(*itr)->m_loggedInPlayer, range) ) { SafeAddTarget(tmpMap,(*itr)->m_loggedInPlayer->GetGUID()); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { std::set<Object*>::iterator itr; firstTarget->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++ ) { if( !(*itr)->IsUnit() || !((Unit*)(*itr))->isAlive()) continue; //we target stuff that has no full health. No idea if we must fill target list or not :( if( (*itr)->GetUInt32Value( UNIT_FIELD_HEALTH ) == (*itr)->GetUInt32Value( UNIT_FIELD_MAXHEALTH ) ) continue; if (sWorld.Collision) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(firstTarget,*itr, range)) { if(!isAttackable(u_caster,(Unit*)(*itr))) { SafeAddTarget(tmpMap,(*itr)->GetGUID()); if(!--jumps) { firstTarget->ReleaseInrangeLock(); return; } } } } firstTarget->ReleaseInrangeLock(); } }
/// Spell Target Handling for type 6 and 77: Single Target Enemy (grep thinks 77 fits in 6) void Spell::SpellTargetSingleTargetEnemy(uint32 i, uint32 j) { if(!m_caster->IsInWorld()) return; Unit * pTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!pTarget) return; if(p_caster && p_caster == pTarget) // spell bug: target is supposed to be a single enemy, not self { if(GetProto()) sLog.outDebug("Spell %lu has target single enemy, but is targeting the caster.", GetProto()->Id); } TargetsList* tmpMap=&m_targetUnits[i]; if(m_spellInfo->TargetCreatureType && pTarget->GetTypeId()==TYPEID_UNIT) { Creature* cr = static_cast< Creature* >( pTarget ); if( cr == NULL ) return; if( cr->GetCreatureInfo() ) if(!(1<<(cr->GetCreatureInfo()->Type-1) & m_spellInfo->TargetCreatureType)) return; } if(p_caster && pTarget != p_caster) { // this is mostly used for things like duels if(pTarget->IsPlayer() && !isAttackable(p_caster, pTarget, false)) { cancastresult = SPELL_FAILED_BAD_TARGETS; return; } /* HACK FIX */ /* Please replace if found correct way */ /* SPELL_AURA_SPELL_MAGNET */ int x; for( x = 0; x < 3; ++x ) if( m_spellInfo->EffectApplyAuraName[x] == SPELL_AURA_MOD_POSSESS || m_spellInfo->is_melee_spell ) break; if( pTarget && x == 3 && pTarget->m_magnetcaster != 0) { Unit *MagnetTarget = pTarget->GetMapMgr()->GetUnit(pTarget->m_magnetcaster); if ( MagnetTarget && m_spellInfo->School ) { m_magnetTarget = pTarget->m_magnetcaster; pTarget = MagnetTarget; // Redirected } } } uint8 did_hit_result = DidHit(i,pTarget); if(did_hit_result != SPELL_DID_HIT_SUCCESS) SafeAddModeratedTarget(pTarget->GetGUID(), did_hit_result); else SafeAddTarget(tmpMap, pTarget->GetGUID()); if( m_spellInfo->EffectChainTarget[i] ) { //number of additional targets uint32 jumps = m_spellInfo->EffectChainTarget[i] - 1; // extra targets by auras if( u_caster ) SM_FIValue( u_caster->SM_FAdditionalTargets,(int32*)&jumps, m_spellInfo->SpellGroupType ); float range = GetMaxRange( dbcSpellRange.LookupEntry( m_spellInfo->rangeIndex ) );//this is probably wrong range *= range; std::set<Object*>::iterator itr,itr2; m_caster->AquireInrangeLock(); //make sure to release lock before exit function ! for( itr2 = m_caster->GetInRangeSetBegin(); itr2 != m_caster->GetInRangeSetEnd(); ) { itr = itr2; itr2++; if((*itr)->GetGUID()==m_targets.m_unitTarget) continue; if( !((*itr)->IsUnit()) || !((Unit*)(*itr))->isAlive() || ((*itr)->IsCreature() && ((Creature*)(*itr))->IsTotem())) continue; if( sWorld.Collision && u_caster != NULL ) { if (u_caster->GetMapId() == (*itr)->GetMapId() && !CollideInterface.CheckLOS(u_caster->GetMapId(),u_caster->GetPositionNC(),(*itr)->GetPositionNC())) continue; } if(IsInrange(m_caster->GetPositionX(),m_caster->GetPositionY(),m_caster->GetPositionZ(),(*itr),range)) { if(isAttackable(u_caster,(Unit*)(*itr))) { did_hit_result = DidHit(i,((Unit*)*itr)); if(did_hit_result==SPELL_DID_HIT_SUCCESS) SafeAddTarget(tmpMap, (*itr)->GetGUID()); else SafeAddModeratedTarget((*itr)->GetGUID(), did_hit_result); if(!--jumps) { m_caster->ReleaseInrangeLock(); return; } } } } m_caster->ReleaseInrangeLock(); } }
/// Spell Target Handling for type 45: Chain,!!only for healing!! for chain lightning =6 void Spell::SpellTargetChainTargeting(uint32 i, uint32 j) { if( !m_caster->IsInWorld() ) return; //if selected target is party member, then jumps on party Unit* firstTarget; bool PartyOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; firstTarget = m_caster->GetMapMgr()->GetPlayer((uint32)m_targets.m_unitTarget); if( firstTarget && p_caster != NULL ) { if( p_caster->InGroup() ) if( p_caster->GetSubGroup() == TO_PLAYER( firstTarget )->GetSubGroup() ) PartyOnly=true; } else { firstTarget = m_caster->GetMapMgr()->GetUnit(m_targets.m_unitTarget); if(!firstTarget) return; } uint32 jumps=m_spellInfo->EffectChainTarget[i]; if(m_spellInfo->SpellGroupType && u_caster) { SM_FIValue(u_caster->SM[SMT_ADDITIONAL_TARGET][0],(int32*)&jumps,m_spellInfo->SpellGroupType); } _AddTargetForced(firstTarget->GetGUID(), i); if(!jumps) return; jumps--; if(PartyOnly) { GroupMembersSet::iterator itr; SubGroup * pGroup = p_caster->GetGroup() ? p_caster->GetGroup()->GetSubGroup(p_caster->GetSubGroup()) : 0; if(pGroup) { p_caster->GetGroup()->Lock(); for(itr = pGroup->GetGroupMembersBegin(); itr != pGroup->GetGroupMembersEnd(); itr++) { if(!(*itr)->m_loggedInPlayer || (*itr)->m_loggedInPlayer == u_caster || (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_HEALTH) == (*itr)->m_loggedInPlayer->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) continue; if(IsInrange(u_caster->GetPositionX(),u_caster->GetPositionY(),u_caster->GetPositionZ(),(*itr)->m_loggedInPlayer, range)) { _AddTargetForced((*itr)->m_loggedInPlayer->GetGUID(), i); if(!--jumps) { p_caster->GetGroup()->Unlock(); return; } } } p_caster->GetGroup()->Unlock(); } }//find nearby friendly target else { unordered_set<Object*>::iterator itr; for( itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); ++itr ) { if( !(*itr)->IsUnit() || !TO_UNIT(*itr)->isAlive()) continue; if(IsInrange(firstTarget->GetPositionX(),firstTarget->GetPositionY(),firstTarget->GetPositionZ(),*itr, range)) { if(!isAttackable(u_caster,TO_UNIT(*itr)) && (*itr)->GetUInt32Value(UNIT_FIELD_HEALTH) != (*itr)->GetUInt32Value(UNIT_FIELD_MAXHEALTH)) { _AddTargetForced((*itr)->GetGUID(), i); if(!--jumps) return; } } } } }
void Spell::AddChainTargets(uint32 i, uint32 TargetType, float r, uint32 maxtargets) { if(!m_caster->IsInWorld()) return; Object* targ = m_caster->GetMapMgr()->_GetObject(m_targets.m_unitTarget); if(targ == NULL) return; TargetsList* list = &m_targetUnits[i]; //if selected target is party member, then jumps on party Unit* firstTarget = NULL; if(targ->IsUnit()) firstTarget = TO_UNIT(targ); else firstTarget = u_caster; bool RaidOnly = false; float range = GetMaxRange(dbcSpellRange.LookupEntry(m_spellInfo->rangeIndex));//this is probably wrong, //this is cast distance, not searching distance range *= range; //is this party only? Player* casterFrom = TO< Player* >(u_caster->GetPlayerOwner()); Player* pfirstTargetFrom = TO< Player* >(firstTarget->GetPlayerOwner()); if(casterFrom != NULL && pfirstTargetFrom != NULL && casterFrom->GetGroup() == pfirstTargetFrom->GetGroup()) RaidOnly = true; uint32 jumps = m_spellInfo->EffectChainTarget[i]; //range range /= jumps; //hacky, needs better implementation! if(m_spellInfo->SpellGroupType && u_caster != NULL) SM_FIValue(u_caster->SM_FAdditionalTargets, (int32*)&jumps, m_spellInfo->SpellGroupType); AddTarget(i, TargetType, firstTarget); if(jumps <= 1 || list->size() == 0) //1 because we've added the first target, 0 size if spell is resisted return; ObjectSet::iterator itr; for(itr = firstTarget->GetInRangeSetBegin(); itr != firstTarget->GetInRangeSetEnd(); itr++) { if(!(*itr)->IsUnit() || !TO_UNIT((*itr))->isAlive()) continue; if(RaidOnly && !pfirstTargetFrom->InRaid(TO_UNIT(*itr))) continue; //healing spell, full health target = NONO if(IsHealingSpell(m_spellInfo) && TO_UNIT(*itr)->GetHealthPct() == 100) continue; size_t oldsize; if(IsInrange(firstTarget->GetPositionX(), firstTarget->GetPositionY(), firstTarget->GetPositionZ(), (*itr), range)) { oldsize = list->size(); AddTarget(i, TargetType, (*itr)); if(list->size() == oldsize || list->size() >= jumps) //either out of jumps or a resist return; } } }