예제 #1
0
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;
			}
		}
	}
}
예제 #2
0
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;
}
예제 #3
0
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;
}
예제 #4
0
		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;
		}
예제 #5
0
파일: Stats.cpp 프로젝트: zurr/abcwow
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;
}
예제 #6
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();
	}
}
예제 #7
0
/// 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();
	}
}
예제 #8
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;

	//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;
				}
			}
		}
	}
}
예제 #9
0
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;
		}
	}
}