コード例 #1
0
ファイル: waypoints.cpp プロジェクト: UnityEQ/UnityEQServer
void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
	if(IsNPC()) {
		entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z + 0.1);
	}

	m_Position.x = new_x;
	m_Position.y = new_y;
	m_Position.z = new_z + 0.1;

	//fix up pathing Z, this shouldent be needed IF our waypoints
	//are corrected instead

	if(zone->HasMap() && RuleB(Map, FixPathingZOnSendTo))
	{
		if(!RuleB(Watermap, CheckForWaterOnSendTo) || !zone->HasWaterMap() ||
			(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
		{
			glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);

			float newz = zone->zonemap->FindBestZ(dest, nullptr);

			Log.Out(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,m_Position.x,m_Position.y,m_Position.z);

			if( (newz > -2000) && std::abs(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaSendTo)) // Sanity check.
				m_Position.z = newz + 1;
		}
	}
}
コード例 #2
0
ファイル: waypoints.cpp プロジェクト: Leere/Server
void Mob::SendToFixZ(float new_x, float new_y, float new_z) {
	if(IsNPC()) {
		entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z + 0.1);
	}

	x_pos = new_x;
	y_pos = new_y;
	z_pos = new_z + 0.1;

	//fix up pathing Z, this shouldent be needed IF our waypoints
	//are corrected instead

	if(zone->HasMap() && RuleB(Map, FixPathingZOnSendTo))
	{
		if(!RuleB(Watermap, CheckForWaterOnSendTo) || !zone->HasWaterMap() ||
			(zone->HasWaterMap() && !zone->watermap->InWater(x_pos, y_pos, z_pos)))
		{
			Map::Vertex dest(x_pos, y_pos, z_pos);

			float newz = zone->zonemap->FindBestZ(dest, nullptr);

			mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);

			if( (newz > -2000) && ABS(newz-dest.z) < RuleR(Map, FixPathingZMaxDeltaSendTo)) // Sanity check.
				z_pos = newz + 1;
		}
	}
}
コード例 #3
0
ファイル: waypoints.cpp プロジェクト: UnityEQ/UnityEQServer
void NPC::StopWandering()
{	// stops a mob from wandering, takes him off grid and sends him back to spawn point
	roamer=false;
	CastToNPC()->SetGrid(0);
	SendPosition();
	Log.Out(Logs::Detail, Logs::Pathing, "Stop Wandering requested.");
	return;
}
コード例 #4
0
ファイル: waypoints.cpp プロジェクト: Leere/Server
void NPC::StopWandering()
{	// stops a mob from wandering, takes him off grid and sends him back to spawn point
	roamer=false;
	CastToNPC()->SetGrid(0);
	SendPosition();
	mlog(QUESTS__PATHING, "Stop Wandering requested.");
	return;
}
コード例 #5
0
ファイル: aggro.cpp プロジェクト: AthrogatePEQ/Server
Mob* EntityList::AICheckCloseAggro(Mob* sender, float iAggroRange, float iAssistRange) {
	if (!sender || !sender->IsNPC())
		return(nullptr);

#ifdef REVERSE_AGGRO
	//with reverse aggro, npc->client is checked elsewhere, no need to check again
	auto it = npc_list.begin();
	while (it != npc_list.end()) {
#else
	auto it = mob_list.begin();
	while (it != mob_list.end()) {
#endif
		Mob *mob = it->second;

		if (sender->CheckWillAggro(mob))
			return mob;
		++it;
	}
	//LogFile->write(EQEMuLog::Debug, "Check aggro for %s no target.", sender->GetName());
	return nullptr;
}

int EntityList::GetHatedCount(Mob *attacker, Mob *exclude)
{
	// Return a list of how many non-feared, non-mezzed, non-green mobs, within aggro range, hate *attacker
	if (!attacker)
		return 0;

	int Count = 0;

	for (auto it = npc_list.begin(); it != npc_list.end(); ++it) {
		NPC *mob = it->second;
		if (!mob || (mob == exclude))
			continue;

		if (!mob->IsEngaged())
			continue;

		if (mob->IsFeared() || mob->IsMezzed())
			continue;

		if (attacker->GetLevelCon(mob->GetLevel()) == CON_GREEN)
			continue;

		if (!mob->CheckAggro(attacker))
			continue;

		float AggroRange = mob->GetAggroRange();

		// Square it because we will be using DistNoRoot

		AggroRange *= AggroRange;

		if (DistanceSquared(mob->GetPosition(), attacker->GetPosition()) > AggroRange)
			continue;

		Count++;
	}

	return Count;

}

void EntityList::AIYellForHelp(Mob* sender, Mob* attacker) {
	if(!sender || !attacker)
		return;
	if (sender->GetPrimaryFaction() == 0 )
		return; // well, if we dont have a faction set, we're gonna be indiff to everybody

	if (sender->HasAssistAggro())
		return;

	for (auto it = npc_list.begin(); it != npc_list.end(); ++it) {
		NPC *mob = it->second;
		if (!mob)
			continue;

		if (mob->CheckAggro(attacker))
			continue;

		if (sender->NPCAssistCap() >= RuleI(Combat, NPCAssistCap))
			break;

		float r = mob->GetAssistRange();
		r = r * r;

		if (
			mob != sender
			&& mob != attacker
//			&& !mob->IsCorpse()
//			&& mob->IsAIControlled()
			&& mob->GetPrimaryFaction() != 0
			&& DistanceSquared(mob->GetPosition(), sender->GetPosition()) <= r
			&& !mob->IsEngaged()
			&& ((!mob->IsPet()) || (mob->IsPet() && mob->GetOwner() && !mob->GetOwner()->IsClient()))
				// If we're a pet we don't react to any calls for help if our owner is a client
			)
		{
			//if they are in range, make sure we are not green...
			//then jump in if they are our friend
			if(attacker->GetLevelCon(mob->GetLevel()) != CON_GREEN)
			{
				bool useprimfaction = false;
				if(mob->GetPrimaryFaction() == sender->CastToNPC()->GetPrimaryFaction())
				{
					const NPCFactionList *cf = database.GetNPCFactionEntry(mob->GetNPCFactionID());
					if(cf){
						if(cf->assistprimaryfaction != 0)
							useprimfaction = true;
					}
				}

				if(useprimfaction || sender->GetReverseFactionCon(mob) <= FACTION_AMIABLE )
				{
					//attacking someone on same faction, or a friend
					//Father Nitwit: make sure we can see them.
					if(mob->CheckLosFN(sender)) {
#if (EQDEBUG>=5)
						Log.Out(Logs::General, Logs::None, "AIYellForHelp(\"%s\",\"%s\") %s attacking %s Dist %f Z %f",
							sender->GetName(), attacker->GetName(), mob->GetName(),
							attacker->GetName(), DistanceSquared(mob->GetPosition(),
							sender->GetPosition()), fabs(sender->GetZ()+mob->GetZ()));
#endif
						mob->AddToHateList(attacker, 25, 0, false);
						sender->AddAssistCap();
					}
				}
			}
		}
	}
}

/*
returns false if attack should not be allowed
I try to list every type of conflict that's possible here, so it's easy
to see how the decision is made. Yea, it could be condensed and made
faster, but I'm doing it this way to make it readable and easy to modify
*/

bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
{

	Mob *mob1, *mob2, *tempmob;
	Client *c1, *c2, *becomenpc;
//	NPC *npc1, *npc2;
	int reverse;

	if(!zone->CanDoCombat())
		return false;

	// some special cases
	if(!target)
		return false;

	if(this == target)	// you can attack yourself
		return true;

	if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){
		return false;
	}

	// can't damage own pet (applies to everthing)
	Mob *target_owner = target->GetOwner();
	Mob *our_owner = GetOwner();
	if(target_owner && target_owner == this)
		return false;
	else if(our_owner && our_owner == target)
		return false;

	// invalidate for swarm pets for later on if their owner is a corpse
	if (IsNPC() && CastToNPC()->GetSwarmInfo() && our_owner &&
			our_owner->IsCorpse() && !our_owner->IsPlayerCorpse())
		our_owner = nullptr;
	if (target->IsNPC() && target->CastToNPC()->GetSwarmInfo() && target_owner &&
			target_owner->IsCorpse() && !target_owner->IsPlayerCorpse())
		target_owner = nullptr;

	//cannot hurt untargetable mobs
	bodyType bt = target->GetBodyType();

	if(bt == BT_NoTarget || bt == BT_NoTarget2) {
		if (RuleB(Pets, UnTargetableSwarmPet)) {
			if (target->IsNPC()) {
				if (!target->CastToNPC()->GetSwarmOwner()) {
					return(false);
				}
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}

	if(!isSpellAttack)
	{
		if(GetClass() == LDON_TREASURE)
		{
			return false;
		}
	}

	// the format here is a matrix of mob type vs mob type.
	// redundant ones are omitted and the reverse is tried if it falls through.

	// first figure out if we're pets. we always look at the master's flags.
	// no need to compare pets to anything
	mob1 = our_owner ? our_owner : this;
	mob2 = target_owner ? target_owner : target;

	reverse = 0;
	do
	{
		if(_CLIENT(mob1))
		{
			if(_CLIENT(mob2))					// client vs client
			{
				c1 = mob1->CastToClient();
				c2 = mob2->CastToClient();

				if	// if both are pvp they can fight
				(
					c1->GetPVP() &&
					c2->GetPVP()
				)
					return true;
				else if	// if they're dueling they can go at it
				(
					c1->IsDueling() &&
					c2->IsDueling() &&
					c1->GetDuelTarget() == c2->GetID() &&
					c2->GetDuelTarget() == c1->GetID()
				)
					return true;
				else
					return false;
			}
			else if(_NPC(mob2))				// client vs npc
			{
				return true;
			}
			else if(_BECOMENPC(mob2))	// client vs becomenpc
			{
				c1 = mob1->CastToClient();
				becomenpc = mob2->CastToClient();

				if(c1->GetLevel() > becomenpc->GetBecomeNPCLevel())
					return false;
				else
					return true;
			}
			else if(_CLIENTCORPSE(mob2))	// client vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// client vs npc corpse
			{
				return false;
			}
		}
		else if(_NPC(mob1))
		{
			if(_NPC(mob2))						// npc vs npc
			{
/*
this says that an NPC can NEVER attack a faction ally...
this is stupid... somebody else should check this rule if they want to
enforce it, this just says 'can they possibly fight based on their
type', in which case, the answer is yes.
*/
/*				npc1 = mob1->CastToNPC();
				npc2 = mob2->CastToNPC();
				if
				(
					npc1->GetPrimaryFaction() != 0 &&
					npc2->GetPrimaryFaction() != 0 &&
					(
						npc1->GetPrimaryFaction() == npc2->GetPrimaryFaction() ||
						npc1->IsFactionListAlly(npc2->GetPrimaryFaction())
					)
				)
					return false;
				else
*/
					return true;
			}
			else if(_BECOMENPC(mob2))	// npc vs becomenpc
			{
				return true;
			}
			else if(_CLIENTCORPSE(mob2))	// npc vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// npc vs npc corpse
			{
				return false;
			}
		}
		else if(_BECOMENPC(mob1))
		{
			if(_BECOMENPC(mob2))			// becomenpc vs becomenpc
			{
				return true;
			}
			else if(_CLIENTCORPSE(mob2))	// becomenpc vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// becomenpc vs npc corpse
			{
				return false;
			}
		}
		else if(_CLIENTCORPSE(mob1))
		{
			if(_CLIENTCORPSE(mob2))		// client corpse vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// client corpse vs npc corpse
			{
				return false;
			}
		}
		else if(_NPCCORPSE(mob1))
		{
			if(_NPCCORPSE(mob2))			// npc corpse vs npc corpse
			{
				return false;
			}
		}

#ifdef BOTS
		bool HasRuleDefined = false;
		bool IsBotAttackAllowed = false;
		IsBotAttackAllowed = Bot::IsBotAttackAllowed(mob1, mob2, HasRuleDefined);
		if(HasRuleDefined)
			return IsBotAttackAllowed;
#endif //BOTS

		// we fell through, now we swap the 2 mobs and run through again once more
		tempmob = mob1;
		mob1 = mob2;
		mob2 = tempmob;
	}
	while( reverse++ == 0 );

	Log.Out(Logs::General, Logs::None, "Mob::IsAttackAllowed: don't have a rule for this - %s vs %s\n", this->GetName(), target->GetName());
	return false;
}
コード例 #6
0
ファイル: effects.cpp プロジェクト: gpanula/Server
int32 Mob::GetActSpellDamage(uint16 spell_id, int32 value, Mob* target) {

	if (spells[spell_id].targettype == ST_Self)
		return value;

	if (IsNPC())
		value += value*CastToNPC()->GetSpellFocusDMG()/100;

	bool Critical = false;
	int32 value_BaseEffect = 0;
	int chance = 0;

	value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

	// Need to scale HT damage differently after level 40! It no longer scales by the constant value in the spell file. It scales differently, instead of 10 more damage per level, it does 30 more damage per level. So we multiply the level minus 40 times 20 if they are over level 40.
	if ((spell_id == SPELL_HARM_TOUCH || spell_id == SPELL_HARM_TOUCH2 || spell_id == SPELL_IMP_HARM_TOUCH ) && GetLevel() > 40)
		value -= (GetLevel() - 40) * 20;

	//This adds the extra damage from the AA Unholy Touch, 450 per level to the AA Improved Harm TOuch.
	if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient()) //Improved Harm Touch
		value -= GetAA(aaUnholyTouch) * 450; //Unholy Touch

		chance = RuleI(Spells, BaseCritChance); //Wizard base critical chance is 2% (Does not scale with level)
		chance += itembonuses.CriticalSpellChance + spellbonuses.CriticalSpellChance + aabonuses.CriticalSpellChance;
		chance += itembonuses.FrenziedDevastation + spellbonuses.FrenziedDevastation + aabonuses.FrenziedDevastation;

	//Crtical Hit Calculation pathway
	if (chance > 0 || (IsClient() && GetClass() == WIZARD && GetLevel() >= RuleI(Spells, WizCritLevel))) {

		 int32 ratio = RuleI(Spells, BaseCritRatio); //Critical modifier is applied from spell effects only. Keep at 100 for live like criticals.

		//Improved Harm Touch is a guaranteed crit if you have at least one level of SCF.
		if (spell_id == SPELL_IMP_HARM_TOUCH && IsClient() && (GetAA(aaSpellCastingFury) > 0) && (GetAA(aaUnholyTouch) > 0))
			 chance = 100;

		if (zone->random.Roll(chance)) {
			Critical = true;
			ratio += itembonuses.SpellCritDmgIncrease + spellbonuses.SpellCritDmgIncrease + aabonuses.SpellCritDmgIncrease;
			ratio += itembonuses.SpellCritDmgIncNoStack + spellbonuses.SpellCritDmgIncNoStack + aabonuses.SpellCritDmgIncNoStack;
		}

		else if ((IsClient() && GetClass() == WIZARD) || (IsMerc() && GetClass() == CASTERDPS)) {
			if ((GetLevel() >= RuleI(Spells, WizCritLevel)) && zone->random.Roll(RuleI(Spells, WizCritChance))){
				//Wizard innate critical chance is calculated seperately from spell effect and is not a set ratio. (20-70 is parse confirmed)
				ratio += zone->random.Int(20,70);
				Critical = true;
			}
		}

		if (IsClient() && GetClass() == WIZARD)
			ratio += RuleI(Spells, WizCritRatio); //Default is zero

		if (Critical){

			value = value_BaseEffect*ratio/100;

			value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;

			value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;

			if (target) {
				value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
				value -= target->GetFcDamageAmtIncoming(this, spell_id);
			}

			value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100;

			value -= GetFocusEffect(focusFcDamageAmt, spell_id);

			if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
				value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value)*ratio/100;

			else if (IsNPC() && CastToNPC()->GetSpellScale())
				value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

			entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
					OTHER_CRIT_BLAST, GetName(), itoa(-value));

			if (IsClient())
				Message_StringID(MT_SpellCrits, YOU_CRIT_BLAST, itoa(-value));

			return value;
		}
	}
	//Non Crtical Hit Calculation pathway
	value = value_BaseEffect;

	value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;

	value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;

	if (target) {
		value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
		value -= target->GetFcDamageAmtIncoming(this, spell_id);
	}

	value -= GetFocusEffect(focusFcDamageAmtCrit, spell_id);

	value -= GetFocusEffect(focusFcDamageAmt, spell_id);

	if(itembonuses.SpellDmg && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
		 value -= GetExtraSpellAmt(spell_id, itembonuses.SpellDmg, value);

	if (IsNPC() && CastToNPC()->GetSpellScale())
		value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

	return value;
}
コード例 #7
0
ファイル: effects.cpp プロジェクト: gpanula/Server
int32 Mob::GetActSpellHealing(uint16 spell_id, int32 value, Mob* target) {

	if (target == nullptr)
		target = this;

	if (IsNPC())
		value += value*CastToNPC()->GetSpellFocusHeal()/100;

	int32 value_BaseEffect = 0;
	int16 chance = 0;
	int8 modifier = 1;
	bool Critical = false;

	value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

	value = value_BaseEffect;

	value += int(value_BaseEffect*GetFocusEffect(focusImprovedHeal, spell_id)/100);

	// Instant Heals
	if(spells[spell_id].buffduration < 1) {

		chance += itembonuses.CriticalHealChance + spellbonuses.CriticalHealChance + aabonuses.CriticalHealChance;

		chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);

		if (spellbonuses.CriticalHealDecay)
			chance += GetDecayEffectValue(spell_id, SE_CriticalHealDecay);

		if(chance && (zone->random.Roll(chance))) {
			Critical = true;
			modifier = 2; //At present time no critical heal amount modifier SPA exists.
		}

		value *= modifier;
		value += GetFocusEffect(focusFcHealAmtCrit, spell_id) * modifier;
		value += GetFocusEffect(focusFcHealAmt, spell_id);
		value += target->GetFocusIncoming(focusFcHealAmtIncoming, SE_FcHealAmtIncoming, this, spell_id);

		if(itembonuses.HealAmt && spells[spell_id].classes[(GetClass()%16) - 1] >= GetLevel() - 5)
			value += GetExtraSpellAmt(spell_id, itembonuses.HealAmt, value) * modifier;

		value += value*target->GetHealRate(spell_id, this)/100;

		if (IsNPC() && CastToNPC()->GetHealScale())
			value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);

		if (Critical) {
			entity_list.MessageClose_StringID(this, true, 100, MT_SpellCrits,
					OTHER_CRIT_HEAL, GetName(), itoa(value));

			if (IsClient())
				Message_StringID(MT_SpellCrits, YOU_CRIT_HEAL, itoa(value));
		}

		return value;
	}

	//Heal over time spells. [Heal Rate and Additional Healing effects do not increase this value]
	else {

		chance = itembonuses.CriticalHealOverTime + spellbonuses.CriticalHealOverTime + aabonuses.CriticalHealOverTime;

		chance += target->GetFocusIncoming(focusFcHealPctCritIncoming, SE_FcHealPctCritIncoming, this, spell_id);

		if (spellbonuses.CriticalRegenDecay)
			chance += GetDecayEffectValue(spell_id, SE_CriticalRegenDecay);

		if(chance && zone->random.Roll(chance))
			value *= 2;
	}

	if (IsNPC() && CastToNPC()->GetHealScale())
		value = int(static_cast<float>(value) * CastToNPC()->GetHealScale() / 100.0f);

	return value;
}
コード例 #8
0
ファイル: effects.cpp プロジェクト: gpanula/Server
int32 Mob::GetActDoTDamage(uint16 spell_id, int32 value, Mob* target) {

	if (target == nullptr)
		return value;

	if (IsNPC())
		value += value*CastToNPC()->GetSpellFocusDMG()/100;

	int32 value_BaseEffect = 0;
	int32 extra_dmg = 0;
	int16 chance = 0;
	chance += itembonuses.CriticalDoTChance + spellbonuses.CriticalDoTChance + aabonuses.CriticalDoTChance;

	if (spellbonuses.CriticalDotDecay)
			chance += GetDecayEffectValue(spell_id, SE_CriticalDotDecay);

	value_BaseEffect = value + (value*GetFocusEffect(focusFcBaseEffects, spell_id)/100);

	if (chance > 0 && (zone->random.Roll(chance))) {
		int32 ratio = 200;
		ratio += itembonuses.DotCritDmgIncrease + spellbonuses.DotCritDmgIncrease + aabonuses.DotCritDmgIncrease;
		value = value_BaseEffect*ratio/100;
		value += int(value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100)*ratio/100;
		value += int(value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100)*ratio/100;
		value += int(value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100)*ratio/100;
		extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
					int(GetFocusEffect(focusFcDamageAmtCrit, spell_id)*ratio/100) +
					GetFocusEffect(focusFcDamageAmt, spell_id);

		if (extra_dmg) {
			int duration = CalcBuffDuration(this, this, spell_id);
			if (duration > 0)
				extra_dmg /= duration;
		}

		value -= extra_dmg;
	}
	else {

		value = value_BaseEffect;
		value += value_BaseEffect*GetFocusEffect(focusImprovedDamage, spell_id)/100;
		value += value_BaseEffect*GetFocusEffect(focusFcDamagePctCrit, spell_id)/100;
		value += value_BaseEffect*target->GetVulnerability(this, spell_id, 0)/100;
		extra_dmg = target->GetFcDamageAmtIncoming(this, spell_id) +
					GetFocusEffect(focusFcDamageAmtCrit, spell_id) +
					GetFocusEffect(focusFcDamageAmt, spell_id);

		if (extra_dmg) {
			int duration = CalcBuffDuration(this, this, spell_id);
			if (duration > 0)
				extra_dmg /= duration;
		}

		value -= extra_dmg;
	}

	if (IsNPC() && CastToNPC()->GetSpellScale())
		value = int(static_cast<float>(value) * CastToNPC()->GetSpellScale() / 100.0f);

	return value;
}
コード例 #9
0
ファイル: waypoints.cpp プロジェクト: UnityEQ/UnityEQServer
bool Mob::CalculateNewPosition(float x, float y, float z, int speed, bool checkZ, bool calcHeading) {
	if(GetID()==0)
		return true;

	float nx = m_Position.x;
	float ny = m_Position.y;
	float nz = m_Position.z;

	// if NPC is rooted
	if (speed == 0) {
		SetHeading(CalculateHeadingToTarget(x, y));
		if(moved){
			SetCurrentSpeed(0);
			moved=false;
		}
		Log.Out(Logs::Detail, Logs::AI, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z);
		return true;
	}

	float old_test_vector=test_vector;
	m_TargetV.x = x - nx;
	m_TargetV.y = y - ny;
	m_TargetV.z = z - nz;

	if (m_TargetV.x == 0 && m_TargetV.y == 0)
		return false;
	SetCurrentSpeed((int8)(speed)); //*NPC_RUNANIM_RATIO);
	//speed *= NPC_SPEED_MULTIPLIER;

	Log.Out(Logs::Detail, Logs::AI, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed);

	// --------------------------------------------------------------------------
	// 2: get unit vector
	// --------------------------------------------------------------------------
	test_vector=sqrtf (x*x + y*y + z*z);
	tar_vector = speed / sqrtf (m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z);
	m_Position.w = CalculateHeadingToTarget(x, y);

	if (tar_vector >= 1.0) {
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), x, y, z);
		}

		m_Position.x = x;
		m_Position.y = y;
		m_Position.z = z;
		Log.Out(Logs::Detail, Logs::AI, "Close enough, jumping to waypoint");
	}
	else {
		float new_x = m_Position.x + m_TargetV.x*tar_vector;
		float new_y = m_Position.y + m_TargetV.y*tar_vector;
		float new_z = m_Position.z + m_TargetV.z*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		m_Position.x = new_x;
		m_Position.y = new_y;
		m_Position.z = new_z;
		Log.Out(Logs::Detail, Logs::AI, "Next position (%.3f, %.3f, %.3f)", m_Position.x, m_Position.y, m_Position.z);
	}

	uint8 NPCFlyMode = 0;

	if(IsNPC()) {
		if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
			NPCFlyMode = 1;
	}

	//fix up pathing Z
	if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
	{
		if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
			(zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
		{
			glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);

			float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;

			Log.Out(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,m_Position.x,m_Position.y,m_Position.z);

			if ((newz > -2000) &&
			    std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
			{
				if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) {
					if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving))
						m_Position.z = z;
					else
						m_Position.z = newz + 1;
				}
				else
					m_Position.z = newz+1;
			}
		}
	}

	//OP_MobUpdate
	if((old_test_vector!=test_vector) || tar_ndx>20){ //send update
		tar_ndx=0;
		this->SetMoving(true);
		moved=true;
		m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);
		SendPosUpdate();
	}
	tar_ndx++;

	// now get new heading
	SetAppearance(eaStanding, false); // make sure they're standing
	pLastChange = Timer::GetCurrentTime();
	return true;
}
コード例 #10
0
ファイル: waypoints.cpp プロジェクト: UnityEQ/UnityEQServer
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, int speed, bool checkZ) {
	if(GetID()==0)
		return true;

	if(speed <= 0)
	{
		SetCurrentSpeed(0);
		return true;
	}

	if ((m_Position.x-x == 0) && (m_Position.y-y == 0)) {//spawn is at target coords
		if(m_Position.z-z != 0) {
			m_Position.z = z;
			Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z);
			return true;
		}
		Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater);
		return false;
	} else if ((std::abs(m_Position.x - x) < 0.1) && (std::abs(m_Position.y - y) < 0.1)) {
		Log.Out(Logs::Detail, Logs::AI, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z);

		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), x, y, z);
		}

		m_Position.x = x;
		m_Position.y = y;
		m_Position.z = z;
		return true;
	}

	bool send_update = false;
	int compare_steps = 20;
	if(tar_ndx < compare_steps && m_TargetLocation.x==x && m_TargetLocation.y==y) {

		float new_x = m_Position.x + m_TargetV.x*tar_vector;
		float new_y = m_Position.y + m_TargetV.y*tar_vector;
		float new_z = m_Position.z + m_TargetV.z*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		m_Position.x = new_x;
		m_Position.y = new_y;
		m_Position.z = new_z;

		Log.Out(Logs::Detail, Logs::AI, "Calculating new position2 to (%.3f, %.3f, %.3f), old vector (%.3f, %.3f, %.3f)", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z);

		uint8 NPCFlyMode = 0;

		if(IsNPC()) {
			if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
				NPCFlyMode = 1;
		}

		//fix up pathing Z
		if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
		{
			if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
			   (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
			{
				glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);

				float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;

				Log.Out(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,m_Position.x,m_Position.y,m_Position.z);

				if ((newz > -2000) &&
				    std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
				{
					if ((std::abs(x - m_Position.x) < 0.5) &&
					    (std::abs(y - m_Position.y) < 0.5)) {
						if (std::abs(z - m_Position.z) <=
						    RuleR(Map, FixPathingZMaxDeltaMoving))
							m_Position.z = z;
						else
							m_Position.z = newz + 1;
					}
					else
						m_Position.z = newz + 1;
				}
			}
		}

		tar_ndx++;
		return true;
	}


	if (tar_ndx>50) {
		tar_ndx--;
	} else {
		tar_ndx=0;
	}
	m_TargetLocation = glm::vec3(x, y, z);

	float nx = this->m_Position.x;
	float ny = this->m_Position.y;
	float nz = this->m_Position.z;
//	float nh = this->heading;

	m_TargetV.x = x - nx;
	m_TargetV.y = y - ny;
	m_TargetV.z = z - nz;
	SetCurrentSpeed((int8)speed);
	pRunAnimSpeed = speed;
	if(IsClient())
	{
		animation = speed / 2;
	}
	//pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
	//speed *= NPC_SPEED_MULTIPLIER;

	Log.Out(Logs::Detail, Logs::AI, "Calculating new position2 to (%.3f, %.3f, %.3f), new vector (%.3f, %.3f, %.3f) rate %.3f, RAS %d", x, y, z, m_TargetV.x, m_TargetV.y, m_TargetV.z, speed, pRunAnimSpeed);

	// --------------------------------------------------------------------------
	// 2: get unit vector
	// --------------------------------------------------------------------------
	float mag = sqrtf (m_TargetV.x*m_TargetV.x + m_TargetV.y*m_TargetV.y + m_TargetV.z*m_TargetV.z);
	tar_vector = (float)speed / mag;

// mob move fix
	int numsteps = (int) ( mag * 16.0f / (float)speed + 0.5f);


// mob move fix

	if (numsteps<20)
	{
		if (numsteps>1)
		{
			tar_vector=1.0f	;
			m_TargetV.x = m_TargetV.x/(float)numsteps;
			m_TargetV.y = m_TargetV.y/(float)numsteps;
			m_TargetV.z = m_TargetV.z/(float)numsteps;

			float new_x = m_Position.x + m_TargetV.x;
			float new_y = m_Position.y + m_TargetV.y;
			float new_z = m_Position.z + m_TargetV.z;
			if(IsNPC()) {
				entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
			}

			m_Position.x = new_x;
			m_Position.y = new_y;
			m_Position.z = new_z;
			m_Position.w = CalculateHeadingToTarget(x, y);
			tar_ndx = 20 - numsteps;
			Log.Out(Logs::Detail, Logs::AI, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", m_Position.x, m_Position.y, m_Position.z, numsteps);
		}
		else
		{
			if(IsNPC()) {
				entity_list.ProcessMove(CastToNPC(), x, y, z);
			}

			m_Position.x = x;
			m_Position.y = y;
			m_Position.z = z;

			Log.Out(Logs::Detail, Logs::AI, "Only a single step to get there... jumping.");

		}
	}

	else {
		tar_vector/=16.0f;
		float dur = Timer::GetCurrentTime() - pLastChange;
		if(dur < 1.0f) {
			dur = 1.0f;
		}
		tar_vector = (tar_vector * AImovement_duration) / 100.0f;

		float new_x = m_Position.x + m_TargetV.x*tar_vector;
		float new_y = m_Position.y + m_TargetV.y*tar_vector;
		float new_z = m_Position.z + m_TargetV.z*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		m_Position.x = new_x;
		m_Position.y = new_y;
		m_Position.z = new_z;
		m_Position.w = CalculateHeadingToTarget(x, y);
		Log.Out(Logs::Detail, Logs::AI, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", m_Position.x, m_Position.y, m_Position.z, numsteps);
	}

	uint8 NPCFlyMode = 0;

	if(IsNPC()) {
		if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
			NPCFlyMode = 1;
	}

	//fix up pathing Z
	if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) {

		if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
		   (zone->HasWaterMap() && !zone->watermap->InWater(glm::vec3(m_Position))))
		{
			glm::vec3 dest(m_Position.x, m_Position.y, m_Position.z);

			float newz = zone->zonemap->FindBestZ(dest, nullptr);

			Log.Out(Logs::Detail, Logs::AI, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,m_Position.x, m_Position.y, m_Position.z);

			if ((newz > -2000) &&
			    std::abs(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
			{
				if (std::abs(x - m_Position.x) < 0.5 && std::abs(y - m_Position.y) < 0.5) {
					if (std::abs(z - m_Position.z) <= RuleR(Map, FixPathingZMaxDeltaMoving))
						m_Position.z = z;
					else
						m_Position.z = newz + 1;
				}
				else
					m_Position.z = newz+1;
				}
		}
	}

	SetMoving(true);
	moved=true;

	m_Delta = glm::vec4(m_Position.x - nx, m_Position.y - ny, m_Position.z - nz, 0.0f);

	if (IsClient())
	{
		SendPosUpdate(1);
		CastToClient()->ResetPositionTimer();
	}
	else
	{
		SendPosUpdate();
		SetAppearance(eaStanding, false);
	}

	pLastChange = Timer::GetCurrentTime();
	return true;
}
コード例 #11
0
ファイル: SpellEffects.cpp プロジェクト: cavedude00/eqmacemu
//o--------------------------------------------------------------
//| BuffFadeBySlot; Yeahlight, Nov 16, 2008
//o--------------------------------------------------------------
//| Adapted from EQEMU 7.0: Removes the buff in the supplied
//| buff slot 'slot'
//o--------------------------------------------------------------
void Mob::BuffFadeBySlot(int slot, bool iRecalcBonuses)
{
	bool debugFlag = true;

	if(slot < 0 || slot > BUFF_COUNT)
		return;

	if(!buffs[slot].spell || !buffs[slot].spell->IsValidSpell())
		return;

	if(IsClient())
		CastToClient()->MakeBuffFadePacket(buffs[slot].spell, slot);


	if(debugFlag && this->IsClient() && this->CastToClient()->GetDebugMe())
		this->Message(LIGHTEN_BLUE, "Debug: Fading buff %d from slot %d", buffs[slot].spell->GetSpellID(), slot);

	for(int i = 0; i < EFFECT_COUNT; i++)
	{
		if(buffs[slot].spell->IsBlankSpellEffect(i))
			continue;
		switch(buffs[slot].spell->GetSpellEffectID(i))
		{
			case SE_WeaponProc:
			{
				SetBonusProcSpell(0);
				break;
			}
			case SE_Illusion: case SE_IllusionCopy:
			{
				SendIllusionPacket(GetBaseRace(), GetBaseGender(), GetTexture(), GetHelmTexture());
				SendAppearancePacket(this->GetID(), SAT_Size, GetDefaultSize(), true);
				break;
			}
			case SE_Levitate:
			{
				SendAppearancePacket(this->GetID(), SAT_Levitate, 0, true);
				break;
			}
			case SE_Invisibility:
			{
				SetInvisible(false);
				break;
			}
			case SE_InvisVsUndead:
			{
				SetInvisibleUndead(false);
				break;
			}
			case SE_InvisVsAnimals:
			{
				SetInvisibleAnimal(false);
				break;
			}
			case SE_Silence:
			{
				break;
			}
			case SE_DivineAura:
			{
				SetInvulnerable(false);
				break;
			}
			case SE_Rune:
			{
				break;
			}
			case SE_AbsorbMagicAtt:
			{
				break;
			}
			case SE_Mez:
			{
				//Yeahlight: Unfreeze the PC's UI
				if(IsClient())
					SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Sitting_To_Standing, true);
				this->mesmerized = false;
				break;
			}
			case SE_Charm:
			{
				Mob* charmer = entity_list.GetMob(this->GetOwnerID());
				if(charmer && charmer->IsClient())
				{
					char npcNameSuffix[] = "_CHARM00";
					char npcNamePrefix[100] = "";
					strcpy(npcNamePrefix, charmer->GetName());
					strcat(npcNamePrefix, npcNameSuffix);
					Mob* charmPH = entity_list.GetMob(npcNamePrefix);
					if(charmPH && charmPH->IsNPC())
					{
						charmPH->Depop();
					}
					//Yeahlight: Check for _CHARM01 NPC, too
					npcNamePrefix[strlen(npcNamePrefix) - 1] = '1';
					charmPH = entity_list.GetMob(npcNamePrefix);
					if(charmPH && charmPH->IsNPC())
					{
						charmPH->Depop();
					}
					//Yeahlight: Generate hate for towards the charmer if the charmer is not FD'ed
					if(this->IsNPC() && charmer->IsClient() && !charmer->CastToClient()->GetFeigned())
					{
						CastToNPC()->AddToHateList(charmer, 0, GetSpellHate(SE_Charm, this->GetLevel(), false));
					}
				}
				//Yeahlight: Unfreeze the PC's UI
				if(IsClient())
				{
					SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Sitting_To_Standing, true);
					CastToClient()->SetCharmed(false);
					CastToClient()->charmPositionUpdate_timer->Disable();
				}
				//Yeahlight: Deflag the NPC as charmed
				else if(IsNPC())
				{
					CastToNPC()->SetCharmed(false);
				}
				this->SetOwnerID(0, false);
				break;
			}
			case SE_Root:
			{
				break;
			}
			case SE_Fear:
			{
				//Yeahlight: Unfreeze the PC's UI
				if(IsClient())
				{
					CastToClient()->SetFeared(false);
					SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Sitting_To_Standing, true);
				}
				else if(IsNPC())
				{
					CastToNPC()->SetFeared(false);
					CastToNPC()->SetOnFearPath(false);
				}
				break;
			}
			case SE_SpinTarget:
			{
				//Yeahlight: Unfreeze the PC's UI
				if(IsClient())
					SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Sitting_To_Standing, true);
				break;
			}
			case SE_EyeOfZomm:
			{
				//Yeahlight: Clear the eye of zomm pointer and depop the eye
				if(IsClient() && CastToClient()->myEyeOfZomm)
				{
					CastToClient()->myEyeOfZomm->Depop();
					CastToClient()->myEyeOfZomm = NULL;
				}
				break;
			}
			case SE_DeathSave:
			{
				//Yeahlight: Clear the death save chance
				if(IsClient())
					CastToClient()->SetDeathSave(0);
				break;
			}
			case SE_VoiceGraft:
			{
				//Yeahlight: Drop the voice grafting flag from the client
				if(GetOwner() && GetOwner()->IsClient())
				{
					GetOwner()->CastToClient()->SetVoiceGrafting(false);
				}
				break;
			}
			case SE_SeeInvis:
			{
				//Yeahlight: Mob may no longer see through invis
				SetCanSeeThroughInvis(false);
				break;
			}
		}
	}

	buffs[slot].spell = NULL;

	if(iRecalcBonuses)
		CalcBonuses(true, true);
}
コード例 #12
0
ファイル: SpellEffects.cpp プロジェクト: cavedude00/eqmacemu
///////////////////////////////////////////////////
// Quagmire - that case above getting to long and spells are gonna have a lot of cases of their own
// Cofruben - Reorganised this a little.
void Mob::SpellEffect(Mob* caster, Spell* spell, int8 caster_level, bool partialResist)
{
	//Spells not loaded!
	if(!spells_handler.SpellsLoaded())
		return;
	//Spell not loaded!
	if(!spell)
		return;
	//Yeahlight: Caster was not supplied
	if(!caster)
		return;

	int i = 0;
	const int16	spell_id		= spell->GetSpellID();
	const char*	teleport_zone	= spell->GetSpellTeleportZone();
	
	// 1. Is it a buff? If so, handle its time based effects.
	if (spell->IsBuffSpell())
		spells_handler.HandleBuffSpellEffects(caster, this, spell);
	
	// 2. Handle its single-time effect.
	for (i = 0; i < EFFECT_COUNT; i++)
	{
		TSpellEffect effect_id = spell->GetSpellEffectID(i);
		if(effect_id == SE_Blank || effect_id == 0xFF)
			continue;
		int8   formula = spell->GetSpellFormula(i);
		sint16 base    = spell->GetSpellBase(i);
		sint16 max     = spell->GetSpellMax(i);	
		sint32 amount  = spells_handler.CalcSpellValue(spell, i, caster_level);
		//Yeahlight: This is an NPC and had a detremental spell casted upon it
		if(this->IsNPC() && (spell->IsDetrimentalSpell() || spell->IsUtilitySpell()))
		{
			CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): aggroing %s because of the spell effect!", spell->GetSpellName(), this->GetName());
			//Yeahlight: Generate hate based on the spells's effect type
			sint16 tempHate = GetSpellHate(effect_id, spell->GetMinLevel(), false, amount);
			if(tempHate)
			{
				this->CastToNPC()->AddToHateList(caster, 0, tempHate);
			}
		}
		switch(effect_id)
		{
			case SE_CurrentHP:
			case SE_CurrentHPOnce:
			{
				sint32 OldHP = this->GetHP();
				sint32 damage = amount;
				//Yeahlight: Partial resist calculations
				if(partialResist)
				{
					damage = damage / 2;
					damage = damage * (float)((float)(rand()%90 + 10) / 100.00f);
					if(caster->IsClient() && caster->CastToClient()->GetDebugMe())
						caster->Message(YELLOW, "Debug: Your direct damage spell resist has been upgrade to a partial resist.");
				}
				this->ChangeHP(caster, damage, spell_id);
				sint32 NewHP = this->GetHP();
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You changed %s's hp by %+i.", spell->GetSpellName(), this->GetName(), damage);
				break;
			}
			case SE_MovementSpeed:
			{
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Movement Speed spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_AttackSpeed:
			{
				//Yeahlight: There should not be any work to be done here
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Attack Speed spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Invisibility: 
			{
				this->SetInvisible(true);
				//Yeahlight: Castee has a pet; remove it
				if(GetPet())
				{
					Mob* myPet = GetPet();
					//Yeahlight: Castee's pet is an NPC
					if(myPet->IsNPC())
					{
						//Yeahlight: Castee's pet is a charmed NPC
						if(myPet->CastToNPC()->IsCharmed())
						{
							myPet->CastToNPC()->BuffFadeByEffect(SE_Charm);
						}
						//Yeahlight: Castee's pet is a summoned NPC
						else
						{
							myPet->Depop();
						}
					}
					//Yeahlight: Castee's pet is a charmed PC
					else if(myPet->IsClient() && myPet->CastToClient()->IsCharmed())
					{
						myPet->CastToClient()->BuffFadeByEffect(SE_Charm);
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an invisibility spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_CurrentMana:
			{
				SetMana(GetMana() + amount);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a mana recovery spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_AddFaction:
			{
				//Yeahlight: Only continue if the target is an NPC and the caster is a PC
				if(this->IsNPC() && caster->IsClient())
				{
					caster->CastToClient()->SetCharacterFactionLevelModifier(this->CastToNPC()->GetPrimaryFactionID(), amount);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an add faction spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Stun:
			{
				if (IsClient())
				{
					CastToClient()->Stun(base);
				}
				else if(IsNPC())
				{
					//Yeahlight: NPC is immune to stun effects
					if(CastToNPC()->GetCannotBeStunned())
					{
						if(caster->IsClient())
						{
							caster->Message(RED, "Your target is immune to the stun portion of this effect");
						}
					}
					else
					{
						CastToNPC()->Stun(base);
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a stun spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_Charm:
			{
				//Yeahlight: Can only charm a non-pet and the caster may only have one pet
				if(this->GetOwner() == NULL && caster->GetPet() == NULL && caster != this)
				{
					//Yeahlight: Flag the NPC as a pet
					if(this->IsNPC())
					{
						caster->SetPet(this);
						this->SetOwnerID(caster->GetID());
						this->CastToNPC()->SetCharmed(true);
						this->SetPetOrder(SPO_Follow);
						if(caster->IsClient())
							caster->CastToClient()->SendCharmPermissions();
						this->CastToNPC()->WhipeHateList();
						this->CastToNPC()->StartTaunting();
					}
					else if(this->IsClient())
					{
						if(caster->IsNPC())
						{
							caster->SetPet(this);
							this->SetOwnerID(caster->GetID());
							Mob* myTarget = caster->CastToNPC()->GetHateTop();
							if(!myTarget)
								myTarget = caster->CastToMob();
							this->SetTarget(myTarget);
							this->animation = 0;
							this->delta_heading = 0;
							this->delta_x = 0;
							this->delta_y = 0;
							this->delta_z = 0;
							this->SendPosUpdate(true, PC_UPDATE_RANGE, false);
							this->CastToClient()->charmPositionUpdate_timer->Start(200);
							this->CastToClient()->SetCharmed(true);
							this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false);
							this->SetPetOrder(SPO_Follow);
						}
						else if(caster->IsClient())
						{
							caster->SetPet(this);
							this->SetOwnerID(caster->GetID());
							this->SetTarget(caster);
							this->animation = 0;
							this->delta_heading = 0;
							this->delta_x = 0;
							this->delta_y = 0;
							this->delta_z = 0;
							this->SendPosUpdate(true, PC_UPDATE_RANGE, false);
							this->CastToClient()->charmPositionUpdate_timer->Start(200);
							this->CastToClient()->SetCharmed(true);
							this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false);
							this->SetPetOrder(SPO_Follow);
							caster->CastToClient()->SendCharmPermissions();
						}
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a charm spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Fear:
			{
				//Yeahlight: Victim is a PC
				if(this->IsClient())
				{
					this->CastToClient()->SetFeared(true);
					this->SendAppearancePacket(this->GetID(), SAT_Position_Update, SAPP_Lose_Control, false);
					this->CastToClient()->GetFearDestination(GetX(), GetY(), GetZ());
				}
				//Yeahlight: Victim is an NPC
				else if(this->IsNPC())
				{
					this->CastToNPC()->SetFeared(true);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a fear spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Stamina:
			{
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a stamina spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_BindAffinity:
			{
				//Yeahlight: Target of the bind affinity spell is a client
				if(this->IsClient())
				{
					this->CastToClient()->SetBindPoint();
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Bind Affinity spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Gate:
			{
				if(IsClient())
					CastToClient()->GoToBind();
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a gate spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_CancelMagic:
			{
				for(int i = 0; i < 15; i++)
				{
					//Yeahlight: Buff must exist and the buff may not have any poison or disease counters
					if(buffs[i].spell && buffs[i].spell->IsValidSpell() && buffs[i].casterlevel <= (caster_level + base) && buffs[i].spell->GetDiseaseCounters() == 0 && buffs[i].spell->GetPoisonCounters() == 0)
					{	
						this->BuffFadeBySlot(i, true);
						break;
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a cancel magic spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_InvisVsUndead:
			{
				this->SetInvisibleUndead(true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an Invis VS Undead spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_InvisVsAnimals:
			{
				this->SetInvisibleAnimal(true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an Invis VS Animal spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Mez:
			{
				// Pinedepain // When a mezz spell is casted, we mesmerize this mob
				Mesmerize();
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a mesmerize spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_SummonItem:
			{
				if(this->IsClient())
				{
					if(amount == 0)
						this->CastToClient()->SummonItem(base, 1);
					else
						this->CastToClient()->SummonItem(base, (amount > 20) ? 20 : amount);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a summon item spell: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_NecPet:
			case SE_SummonPet:
			{
				if (this->GetPetID() != 0) {
					Message(RED, "You\'ve already got a pet.");
					break;
				}
				this->MakePet(teleport_zone);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Summon pet / nec pet spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_DivineAura:
			{
				this->SetInvulnerable(true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Divine Aura, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_ShadowStep:
			{
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Shadow Step spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Rune:
			{
				//Yeahlight: Flag entity with rune for damage calculations
				hasRuneOn = true;
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Rune spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Levitate:
			{
				this->SendAppearancePacket(0, SAT_Levitate, 2, true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a levitate spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_SummonCorpse:
			{
				bool permit = false;
				Mob* corpseOwner = target;
				//Yeahlight: The target of this spell is not a PC or the caster is targeting themself
				if(!target || (target && !target->IsClient()) || target == this)
				{
					corpseOwner = this;
					permit = true;
				}
				//Yeahlight: Can only summon a PC's corpse
				if(corpseOwner && corpseOwner->IsClient())
				{
					//Yeahlight: PCs must be grouped to summon a corpse
					if(!permit)
					{
						Group* targetGroup = entity_list.GetGroupByClient(corpseOwner->CastToClient());
						Group* myGroup = NULL;
						if(this->IsClient())
							myGroup = entity_list.GetGroupByClient(this->CastToClient());
						//Yeahlight: Caster is in a group and they share the same group as the target
						if(myGroup != NULL && myGroup == targetGroup)
							permit = true;
					}
					//Yeahlight: Caster may proceed with the summon
					if(permit)
					{
						Corpse *corpse = entity_list.GetCorpseByOwner(corpseOwner->CastToClient());
						//Yeahlight: Corpse has been located
						if(corpse)
						{
							corpse->Summon(corpseOwner->CastToClient(), caster->CastToClient(), true);
							CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a summon corpse spell: %s.", spell->GetSpellName(), this->GetName());
						}
						//Yeahlight: There is no corpse available
						else
						{
							//Yeahlight: Caster failed to locate his/her corpse
							if(caster == corpseOwner)
							{
								caster->Message(RED, "You do not have a corpse in this zone.");
							}
							//Yeahlight: Caster failed to locate their target's corpse
							else
							{
								caster->Message(RED, "Your target does not have a corpse in this zone.");
							}
							CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): Summon corpse: you can't sense the corpse: %i.", spell->GetSpellName());
						}
					}
					else
					{
						//Yeahlight: TODO: This is not the correct message
						Message(RED, "You and your target must be in the same group to perform this action.");
					}
				}
				break;
			}
			case SE_Illusion:
			{
				SendIllusionPacket(base, GetDefaultGender(base, GetBaseGender()), GetTexture(), GetHelmTexture());
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an illusion spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Identify:
			{
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an identify spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_WipeHateList:
			{
				//Yeahlight: NOTE: Do NOT wipe the rampage list here; that never goes away until the mob resets
				if(this->IsNPC())
				{
					//Yeahlight: TODO: I don't remember this message, look into this
					entity_list.MessageClose(this, true, DEFAULT_MESSAGE_RANGE, DARK_BLUE, "My mind fogs. Who are my friends? Who are my enemies?... it was all so clear a moment ago...");
					this->CastToNPC()->WhipeHateList();
					CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a whipe hate list spell, amount: %i.", spell->GetSpellName(), amount);
				}
				break;
			}
			case SE_SpinTarget:
			{
				Spin(caster, spell);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a spin target spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_EyeOfZomm:
			{
				//Yeahlignt: Only produce eyes of zomm for PCs
				if(this->IsClient())
				{
					if(this->CastToClient()->myEyeOfZomm == 0)
						MakeEyeOfZomm(this);
					else
						Message(RED, "You may only have one eye of zomm out at a time!");
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a Eye Of Zomm spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_ReclaimPet:
			{
				//Yeahlight: Target of the spell is an uncharmed NPC, has an owner and the owner is the caster of the spell
				if(IsNPC() && CastToNPC()->IsCharmed() == false && GetOwnerID() && caster->GetID() == GetOwnerID())
				{
					//Yeahlight: TODO: Research this formula
					caster->SetMana(caster->GetMana()+(GetLevel()*4));
					if(caster->IsClient())
					{
						caster->CastToClient()->SetPet(0);
					}
					SetOwnerID(0);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a reclaim pet spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_FeignDeath:
			{
				if(this->IsClient())
					this->CastToClient()->FeignDeath(this->CastToClient()->GetSkill(ABJURATION));
				break;
			}
			case SE_VoiceGraft:
			{
				//Yeahlight: Only allow voice graft to be casted on NPCs (we don't want PCs griefing other charmed PCs with /say)
				if(IsNPC() && caster->IsClient() && CastToNPC()->GetOwner() == caster)
				{
					caster->CastToClient()->SetVoiceGrafting(true);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a voice graft spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Revive:
			{
				//Yeahlight: Handled in client_process.cpp
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a revive spell, amount: %i, corpse: %s.", spell->GetSpellName(), amount, this->GetName());
				break;
			}
			case SE_Teleport:
			{
				char teleport_zone_char[64];
				if(this->IsClient())
					strcpy(teleport_zone_char, teleport_zone);
					this->CastToClient()->MovePC(teleport_zone_char, spell->GetSpellBase(1), spell->GetSpellBase(0), spell->GetSpellBase(2), false, false);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a teleport spell to %s (%f, %f, %f).", spell->GetSpellName(), teleport_zone, spell->GetSpellBase(1), spell->GetSpellBase(0), spell->GetSpellBase(2));
				break;
			}
			case SE_Translocate:
			{
				bool permit = false;
				Mob* translocatee = CastToMob();

				//Enraged: The target of this spell is an NPC.
				//if(translocatee && !translocatee->IsClient())
				//{
				//	//Enraged: TODO: This is not the correct message?
				//	Message(RED, "You cannot cast that spell on your current target.");
				//	break;
				//}

				//Enraged: The target of this spell is the caster.
				//TODO: Can players target themselves with translocate spells?
				if(translocatee && (translocatee == this))
					permit = true;

				//Enraged: Check if the targetted client is in the casters group.
				//TODO: Translocate only worked on group players, right?
				if(!permit && translocatee)
				{
					Group* translocateeGroup = entity_list.GetGroupByClient(translocatee->CastToClient());
					Group* casterGroup = NULL;
					if(this->IsClient())
						casterGroup = entity_list.GetGroupByClient(this->CastToClient());
					//Enraged: The translocatee is in a group and they share the same group as the target
					if(casterGroup != NULL && casterGroup == translocateeGroup)
						permit = true;
				}

				//Enraged: Target is clear to be translocated.
				if(permit)
				{
					CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a translocation spell on %s.", spell->GetSpellName(), translocatee->GetName());
					//TODO: Translocate code here
					translocatee->CastToClient()->SendTranslocateConfirmation(caster, spell);
				}
				else
				{
					//The translocatee was not in the casters group.
					//Enraged: TODO: This is not the correct message
					Message(RED, "You can only cast that spell on players in your group.");
				}
				break;
			}
			case SE_InfraVision:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an infravision spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_UltraVision:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an ultravision spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_BindSight:
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a bind sight spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_SeeInvis:
				SetCanSeeThroughInvis(true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a see invis spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_WaterBreathing:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted an water breathing spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_SenseDead:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense dead spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_SenseSummoned:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense summoned spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_TrueNorth: 
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a true north spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_SenseAnimals:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sense animals spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_DamageShield:
				//Yeahlight: There should not be any work to be done here
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a damage shield spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_Sentinel:
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a sentinel spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_LocateCorpse:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a locate corpse spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_ModelSize:
			{
				//Yeahlight: Grow/Shrink
				float newSize = (GetSize() * (float)base) / 100.00f;
				//Yeahlight: Size of a gnome (minimum)
				if(newSize < 3)
					newSize = 3;
				//Yeahlight: Size of an ogre (maximum)
				else if(newSize > 9)
					newSize = 9;
				this->size = newSize;
				this->SendAppearancePacket(GetID(), SAT_Size, GetSize(), true);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a model size spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Root:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a root spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_Blind:
				//Yeahlight: Handled client side
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a blind spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			case SE_DiseaseCounter:
			{
				//Yeahlight: Spell is a cure disease spell
				if(amount < 0)
				{
					//Yeahlight: Iterate through all the debuffs on the target and check for the chance to cure it
					for(int i = 0; i < 15; i++)
					{
						if(buffs[i].spell && buffs[i].diseasecounters)
						{
							buffs[i].diseasecounters = buffs[i].diseasecounters + amount;
							if(buffs[i].diseasecounters <= 0)
								BuffFadeBySlot(i, true);
							break;
						}
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a disease counter spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_PoisonCounter:
			{
				//Yeahlight: Spell is a cure poison spell
				if(amount < 0)
				{
					//Yeahlight: Iterate through all the debuffs on the target and check for the chance to cure it
					for(int i = 0; i < 15; i++)
					{
						if(buffs[i].spell && buffs[i].poisoncounters)
						{
							buffs[i].poisoncounters = buffs[i].poisoncounters + amount;
							if(buffs[i].poisoncounters <= 0)
								BuffFadeBySlot(i, true);
							break;
						}
					}
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a poison counter spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_Calm:
			{
				//Yeahlight: Only add/remove hate from NPCs
				if(this->IsNPC())
				{
					this->CastToNPC()->AddToHateList(caster, 0, amount);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): You casted a calm hate spell, amount: %i.", spell->GetSpellName(), amount);
				break;
			}
			case SE_WeaponProc:
			{
				Spell* spell = spells_handler.GetSpellPtr(base);
				//Yeahlight: Legit spell proc bonus found
				if(spell)
					SetBonusProcSpell(spell);
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell name = %s): Weapon proc bonus of spell ID %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_StopRain:
			{
				zone->zone_weather = 0;
				zone->weatherSend();
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a stop rain spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_CallOfHero:
			{
				//Yeahlight: Call of the Hero may only be used on PCs
				int32 zoneid = 0;
				if(this->IsClient())
					this->CastToClient()->MovePC(zoneid, caster->GetX(), caster->GetY(), caster->GetZ(), false, true);
				else
					caster->Message(RED, "This spell may only be cast on players.");
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a call of the hero spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_CallPet:
			{
				//Yeahlight: This spell line may only be used on NPC pets
				if(GetPet() && GetPet()->IsNPC())
				{
					GetPet()->CastToNPC()->GMMove(GetX(), GetY(), GetZ(), GetHeading());
					GetPet()->pStandingPetOrder = SPO_Follow;
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a call pet spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_DeathSave:
			{
				//Yeahlight: Only apply divine intervention to players
				if(this->IsClient())
				{
					sint16 successChance = 0;
					float baseChance = 0.00f;
					switch(base)
					{
						//Yeahlight: Death Pact (CLR: 51)
						case 1:
						{
							baseChance = 0.10f;
							break;
						}
						//Yeahlight: Divine Intervention (CLR: 60)
						case 2:
						{
							baseChance = 0.30f;
							break;
						}
						default:
						{
							baseChance = 0.10f;
						}
					}
					//Yeahlight: The target's CHA is calculated into the bonus save chance
					successChance = (((float)CastToClient()->GetCHA() * 0.0005f) + baseChance) * 100;
					//Yeahlight: The worst possible save chance is the spell's base chance
					if(successChance < baseChance)
						successChance = baseChance;
					else if(successChance > 100)
						successChance = 100;
					this->CastToClient()->SetDeathSave(successChance);
				}
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a death save spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case SE_Succor:
			{
				//Yeahlight: There should be nothing to do here
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::ApplySpellsBonuses(spell name = %s): You casted a succor spell, amount: %i.", spell->GetSpellName(), base);
				break;
			}
			case 0xFE:
			case 0xFF:
			case SE_Harmony:
			case SE_ChangeFrenzyRad:
			case SE_Lull:
			case SE_TotalHP:
			case SE_ArmorClass:
			case SE_MagnifyVision:
			case SE_ATK:
			case SE_STR:
			case SE_DEX:
			case SE_AGI:
			case SE_STA:
			case SE_INT:
			case SE_WIS:
			case SE_CHA:
			case SE_ResistFire:
			case SE_ResistCold:
			case SE_ResistPoison:
			case SE_ResistDisease:
			case SE_ResistMagic:
			{
				// Buffs are handeled elsewhere
				break;
			}
			default:
			{
				CAST_CLIENT_DEBUG_PTR(caster)->Log(CP_SPELL, "Mob::SpellEffect(spell_name = %s): unknown effect (%i) for amount: %i.", spell->GetSpellName(), effect_id, amount);
				break;
			}
		}
	}
	if(this->IsClient())
		this->CastToClient()->Save();
}
コード例 #13
0
ファイル: waypoints.cpp プロジェクト: Leere/Server
bool Mob::CalculateNewPosition(float x, float y, float z, float speed, bool checkZ) {
	if(GetID()==0)
		return true;

	float nx = x_pos;
	float ny = y_pos;
	float nz = z_pos;

	// if NPC is rooted
	if (speed == 0.0) {
		SetHeading(CalculateHeadingToTarget(x, y));
		if(moved){
			SendPosition();
			SetMoving(false);
			moved=false;
		}
		SetRunAnimSpeed(0);
		mlog(AI__WAYPOINTS, "Rooted while calculating new position to (%.3f, %.3f, %.3f)", x, y, z);
		return true;
	}

	float old_test_vector=test_vector;
	tar_vx = x - nx;
	tar_vy = y - ny;
	tar_vz = z - nz;

	if (tar_vx == 0 && tar_vy == 0)
		return false;
	pRunAnimSpeed = (uint8)(speed*NPC_RUNANIM_RATIO);
	speed *= NPC_SPEED_MULTIPLIER;

	mlog(AI__WAYPOINTS, "Calculating new position to (%.3f, %.3f, %.3f) vector (%.3f, %.3f, %.3f) rate %.3f RAS %d", x, y, z, tar_vx, tar_vy, tar_vz, speed, pRunAnimSpeed);

	// --------------------------------------------------------------------------
	// 2: get unit vector
	// --------------------------------------------------------------------------
	test_vector=sqrtf (x*x + y*y + z*z);
	tar_vector = speed / sqrtf (tar_vx*tar_vx + tar_vy*tar_vy + tar_vz*tar_vz);
	heading = CalculateHeadingToTarget(x, y);

	if (tar_vector >= 1.0) {
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), x, y, z);
		}

		x_pos = x;
		y_pos = y;
		z_pos = z;
		mlog(AI__WAYPOINTS, "Close enough, jumping to waypoint");
	}
	else {
		float new_x = x_pos + tar_vx*tar_vector;
		float new_y = y_pos + tar_vy*tar_vector;
		float new_z = z_pos + tar_vz*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		x_pos = new_x;
		y_pos = new_y;
		z_pos = new_z;
		mlog(AI__WAYPOINTS, "Next position (%.3f, %.3f, %.3f)", x_pos, y_pos, z_pos);
	}

	uint8 NPCFlyMode = 0;

	if(IsNPC()) {
		if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
			NPCFlyMode = 1;
	}

	//fix up pathing Z
	if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
	{
		if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
			(zone->HasWaterMap() && !zone->watermap->InWater(x_pos, y_pos, z_pos)))
		{
			Map::Vertex dest(x_pos, y_pos, z_pos);

			float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;

			mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);

			if( (newz > -2000) && ABS(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
			{
				if(ABS(x - x_pos) < 0.5 && ABS(y - y_pos) < 0.5)
				{
					if(ABS(z - z_pos) <= RuleR(Map, FixPathingZMaxDeltaMoving))
						z_pos = z;
					else
						z_pos = newz + 1;
				}
				else
					z_pos = newz+1;
			}
		}
	}

	//OP_MobUpdate
	if((old_test_vector!=test_vector) || tar_ndx>20){ //send update
		tar_ndx=0;
		this->SetMoving(true);
		moved=true;
		delta_x=(x_pos-nx);
		delta_y=(y_pos-ny);
		delta_z=(z_pos-nz);
		delta_heading=0;//(heading-nh)*8;
		SendPosUpdate();
	}
	tar_ndx++;

	// now get new heading
	SetAppearance(eaStanding, false); // make sure they're standing
	pLastChange = Timer::GetCurrentTime();
	return true;
}
コード例 #14
0
ファイル: waypoints.cpp プロジェクト: Leere/Server
bool Mob::MakeNewPositionAndSendUpdate(float x, float y, float z, float speed, bool checkZ) {
	if(GetID()==0)
		return true;

	if ((x_pos-x == 0) && (y_pos-y == 0)) {//spawn is at target coords
		if(z_pos-z != 0) {
			z_pos = z;
			mlog(AI__WAYPOINTS, "Calc Position2 (%.3f, %.3f, %.3f): Jumping pure Z.", x, y, z);
			return true;
		}
		mlog(AI__WAYPOINTS, "Calc Position2 (%.3f, %.3f, %.3f) inWater=%d: We are there.", x, y, z, inWater);
		return false;
	}
	else if ((ABS(x_pos - x) < 0.1) && (ABS(y_pos - y) < 0.1))
	{
		mlog(AI__WAYPOINTS, "Calc Position2 (%.3f, %.3f, %.3f): X/Y difference <0.1, Jumping to target.", x, y, z);

		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), x, y, z);
		}

		x_pos = x;
		y_pos = y;
		z_pos = z;
		return true;
	}

	int compare_steps = IsBoat() ? 1 : 20;
	if(tar_ndx < compare_steps && tarx==x && tary==y) {

		float new_x = x_pos + tar_vx*tar_vector;
		float new_y = y_pos + tar_vy*tar_vector;
		float new_z = z_pos + tar_vz*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		x_pos = new_x;
		y_pos = new_y;
		z_pos = new_z;

		mlog(AI__WAYPOINTS, "Calculating new position2 to (%.3f, %.3f, %.3f), old vector (%.3f, %.3f, %.3f)", x, y, z, tar_vx, tar_vy, tar_vz);

		uint8 NPCFlyMode = 0;

		if(IsNPC()) {
			if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
				NPCFlyMode = 1;
		}

		//fix up pathing Z
		if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving))
		{
			if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
				(zone->HasWaterMap() && !zone->watermap->InWater(x_pos, y_pos, z_pos)))
			{
				Map::Vertex dest(x_pos, y_pos, z_pos);

				float newz = zone->zonemap->FindBestZ(dest, nullptr) + 2.0f;

				mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);

				if( (newz > -2000) && ABS(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
				{
					if((ABS(x - x_pos) < 0.5) && (ABS(y - y_pos) < 0.5))
					{
						if(ABS(z-z_pos) <= RuleR(Map, FixPathingZMaxDeltaMoving))
							z_pos = z;
						else
							z_pos = newz + 1;
					}
					else
						z_pos = newz + 1;
				}
			}
		}

		tar_ndx++;
		return true;
	}


	if (tar_ndx>50) {
		tar_ndx--;
	} else {
		tar_ndx=0;
	}
	tarx=x;
	tary=y;
	tarz=z;

	float nx = this->x_pos;
	float ny = this->y_pos;
	float nz = this->z_pos;
//	float nh = this->heading;

	tar_vx = x - nx;
	tar_vy = y - ny;
	tar_vz = z - nz;

	//pRunAnimSpeed = (int8)(speed*NPC_RUNANIM_RATIO);
	//speed *= NPC_SPEED_MULTIPLIER;

	mlog(AI__WAYPOINTS, "Calculating new position2 to (%.3f, %.3f, %.3f), new vector (%.3f, %.3f, %.3f) rate %.3f, RAS %d", x, y, z, tar_vx, tar_vy, tar_vz, speed, pRunAnimSpeed);

	// --------------------------------------------------------------------------
	// 2: get unit vector
	// --------------------------------------------------------------------------
	float mag = sqrtf (tar_vx*tar_vx + tar_vy*tar_vy + tar_vz*tar_vz);
	tar_vector = speed / mag;

// mob move fix
	int numsteps = (int) ( mag * 20 / speed) + 1;


// mob move fix

	if (numsteps<20)
	{
		if (numsteps>1)
		{
			tar_vector=1.0f				;
			tar_vx = tar_vx/numsteps;
			tar_vy = tar_vy/numsteps;
			tar_vz = tar_vz/numsteps;

			float new_x = x_pos + tar_vx;
			float new_y = y_pos + tar_vy;
			float new_z = z_pos + tar_vz;
			if(IsNPC()) {
				entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
			}

			x_pos = new_x;
			y_pos = new_y;
			z_pos = new_z;
			tar_ndx=22-numsteps;
			heading = CalculateHeadingToTarget(x, y);
			mlog(AI__WAYPOINTS, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", x_pos, y_pos, z_pos, numsteps);
		}
		else
		{
			if(IsNPC()) {
				entity_list.ProcessMove(CastToNPC(), x, y, z);
			}

			x_pos = x;
			y_pos = y;
			z_pos = z;

			mlog(AI__WAYPOINTS, "Only a single step to get there... jumping.");

		}
	}

	else {
		tar_vector/=20;

		float new_x = x_pos + tar_vx*tar_vector;
		float new_y = y_pos + tar_vy*tar_vector;
		float new_z = z_pos + tar_vz*tar_vector;
		if(IsNPC()) {
			entity_list.ProcessMove(CastToNPC(), new_x, new_y, new_z);
		}

		x_pos = new_x;
		y_pos = new_y;
		z_pos = new_z;
		heading = CalculateHeadingToTarget(x, y);
		mlog(AI__WAYPOINTS, "Next position2 (%.3f, %.3f, %.3f) (%d steps)", x_pos, y_pos, z_pos, numsteps);
	}

	uint8 NPCFlyMode = 0;

	if(IsNPC()) {
		if(CastToNPC()->GetFlyMode() == 1 || CastToNPC()->GetFlyMode() == 2)
			NPCFlyMode = 1;
	}

	//fix up pathing Z
	if(!NPCFlyMode && checkZ && zone->HasMap() && RuleB(Map, FixPathingZWhenMoving)) {

		if(!RuleB(Watermap, CheckForWaterWhenMoving) || !zone->HasWaterMap() ||
			(zone->HasWaterMap() && !zone->watermap->InWater(x_pos, y_pos, z_pos)))
		{
			Map::Vertex dest(x_pos, y_pos, z_pos);

			float newz = zone->zonemap->FindBestZ(dest, nullptr); + 2.0f;

			mlog(AI__WAYPOINTS, "BestZ returned %4.3f at %4.3f, %4.3f, %4.3f", newz,x_pos,y_pos,z_pos);

			if( (newz > -2000) && ABS(newz - dest.z) < RuleR(Map, FixPathingZMaxDeltaMoving)) // Sanity check.
			{
				if(ABS(x - x_pos) < 0.5 && ABS(y - y_pos) < 0.5)
				{
					if(ABS(z - z_pos) <= RuleR(Map, FixPathingZMaxDeltaMoving))
						z_pos = z;
					else
						z_pos = newz + 1;
				}
				else
					z_pos = newz+1;
				}
		}
	}

	SetMoving(true);
	moved=true;

	delta_x=x_pos-nx;
	delta_y=y_pos-ny;
	delta_z=z_pos-nz;
	delta_heading=0;

	if (IsClient())
		SendPosUpdate(1);
	else
		SendPosUpdate();

	SetAppearance(eaStanding, false);
	pLastChange = Timer::GetCurrentTime();
	return true;
}
コード例 #15
0
ファイル: aura.cpp プロジェクト: SecretsOTheP/Server
void Aura::ProcessOnGroupMembersPets(Mob *owner)
{
	auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline
	std::set<int> delayed_remove;
	bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter
	// This type can either live on the pet (level 55/70 MAG aura) or on the pet owner (level 85 MAG aura)
	auto group_member = owner->GetOwnerOrSelf();

	if (group_member->IsRaidGrouped() && group_member->IsClient()) { // currently raids are just client, but safety check
		auto raid = group_member->GetRaid();
		if (raid == nullptr) { // well shit
			owner->RemoveAura(GetID(), false, true);
			return;
		}
		auto group_id = raid->GetGroup(group_member->CastToClient());

		// some lambdas so the for loop is less horrible ...
		auto verify_raid_client_pet = [&raid, &group_id, &group_member, this](Mob *m) {
			auto idx = raid->GetPlayerIndex(m->GetOwner()->CastToClient());
			if (m->GetOwner()->GetID() == group_member->GetID()) {
				return DistanceSquared(GetPosition(), m->GetPosition()) <= distance;
			} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
				return false;
			} else if (DistanceSquared(GetPosition(), m->GetPosition()) > distance) {
				return false;
			}
			return true;
		};

		auto verify_raid_client_swarm = [&raid, &group_id, &group_member, this](NPC *n) {
			auto owner = entity_list.GetMob(n->GetSwarmOwner());
			if (owner == nullptr)
				return false;
			auto idx = raid->GetPlayerIndex(owner->CastToClient());
			if (owner->GetID() == group_member->GetID()) {
				return DistanceSquared(GetPosition(), n->GetPosition()) <= distance;
			} else if (idx == 0xFFFFFFFF || raid->members[idx].GroupNumber != group_id || raid->members[idx].GroupNumber == 0xFFFFFFFF) {
				return false;
			} else if (DistanceSquared(GetPosition(), n->GetPosition()) > distance) {
				return false;
			}
			return true;
		};

		for (auto &e : mob_list) {
			auto mob = e.second;
			// step 1: check if we're already managing this NPC's buff
			auto it = casted_on.find(mob->GetID());
			if (it != casted_on.end()) {
				// verify still good!
				if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner()) {
					if (!verify_raid_client_pet(mob))
						delayed_remove.insert(mob->GetID());
				} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
					auto npc = mob->CastToNPC();
					if (!verify_raid_client_swarm(npc))
						delayed_remove.insert(mob->GetID());
				}
			} else { // we're not on it!
				if (mob->IsClient()) {
					continue; // never hit client
				} else if (mob->IsPet() && mob->IsPetOwnerClient() && mob->GetOwner() && verify_raid_client_pet(mob)) {
					casted_on.insert(mob->GetID());
					if (is_buff)
						SpellFinished(spell_id, mob);
				} else if (mob->IsNPC() && mob->IsPetOwnerClient()) {
					auto npc = mob->CastToNPC();
					if (verify_raid_client_swarm(npc)) {
						casted_on.insert(mob->GetID());
						if (is_buff)
							SpellFinished(spell_id, mob);
					}
				}
			}
		}
	} else if (group_member->IsGrouped()) {
		auto group = group_member->GetGroup();
		if (group == nullptr) { // uh oh
			owner->RemoveAura(GetID(), false, true);
			return;
		}

		// lambdas to make for loop less ugly
		auto verify_group_pet = [&group, this](Mob *m) {
			auto owner = m->GetOwner();
			if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), m->GetPosition()) <= distance)
				return true;
			return false;
		};

		auto verify_group_swarm = [&group, this](NPC *n) {
			auto owner = entity_list.GetMob(n->GetSwarmOwner());
			if (owner != nullptr && group->IsGroupMember(owner) && DistanceSquared(GetPosition(), n->GetPosition()) <= distance)
				return true;
			return false;
		};

		for (auto &e : mob_list) {
			auto mob = e.second;
			auto it = casted_on.find(mob->GetID());

			if (it != casted_on.end()) { // make sure we're still valid
				if (mob->IsPet()) {
					if (!verify_group_pet(mob))
						delayed_remove.insert(mob->GetID());
				} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo()) {
					if (!verify_group_swarm(mob->CastToNPC()))
						delayed_remove.insert(mob->GetID());
				}
			} else { // not on, check if we should be!
				if (mob->IsClient()) {
					continue;
				} else if (mob->IsPet() && verify_group_pet(mob)) {
					casted_on.insert(mob->GetID());
					if (is_buff)
						SpellFinished(spell_id, mob);
				} else if (mob->IsNPC() && mob->CastToNPC()->GetSwarmInfo() && verify_group_swarm(mob->CastToNPC())) {
					casted_on.insert(mob->GetID());
					if (is_buff)
						SpellFinished(spell_id, mob);
				}
			}
		}
	} else {
		auto verify_solo = [&group_member, this](Mob *m) {
			if (m->IsPet() && m->GetOwnerID() == group_member->GetID())
				return true;
			else if (m->IsNPC() && m->CastToNPC()->GetSwarmOwner() == group_member->GetID())
				return true;
			else
				return false;
		};
		for (auto &e : mob_list) {
			auto mob = e.second;
			auto it = casted_on.find(mob->GetID());
			bool good = verify_solo(mob);

			if (it != casted_on.end()) { // make sure still valid
				if (!good || DistanceSquared(GetPosition(), mob->GetPosition()) > distance) {
					delayed_remove.insert(mob->GetID());
				}
			} else if (good && DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) {
				casted_on.insert(mob->GetID());
				if (is_buff)
					SpellFinished(spell_id, mob);
			}
		}
	}

	for (auto &e : delayed_remove) {
		auto mob = entity_list.GetMob(e);
		if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove
			mob->BuffFadeBySpellIDAndCaster(spell_id, GetID());
		casted_on.erase(e);
	}

	// so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it
	if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty())
		cast_timer.Start();

	if (!cast_timer.Enabled() || !cast_timer.Check())
		return;

	// some auras have to recast (DRU for example, non-buff too)
	for (auto &e : casted_on) {
		auto mob = entity_list.GetMob(e);
		if (mob != nullptr)
			SpellFinished(spell_id, mob);
	}
}
コード例 #16
0
ファイル: aggro.cpp プロジェクト: j883376/Server
bool Mob::IsAttackAllowed(Mob *target, bool isSpellAttack)
{

	Mob *mob1 = nullptr, *mob2 = nullptr, *tempmob = nullptr;
	Client *c1 = nullptr, *c2 = nullptr, *becomenpc = nullptr;
//	NPC *npc1, *npc2;
	int reverse;

	if(!zone->CanDoCombat())
		return false;

	// some special cases
	if(!target)
		return false;

	if(this == target)	// you can attack yourself
		return true;

	if(target->GetSpecialAbility(NO_HARM_FROM_CLIENT)){
		return false;
	}

	// can't damage own pet (applies to everthing)
	Mob *target_owner = target->GetOwner();
	Mob *our_owner = GetOwner();
	if(target_owner && target_owner == this)
		return false;
	else if(our_owner && our_owner == target)
		return false;

	// invalidate for swarm pets for later on if their owner is a corpse
	if (IsNPC() && CastToNPC()->GetSwarmInfo() && our_owner &&
			our_owner->IsCorpse() && !our_owner->IsPlayerCorpse())
		our_owner = nullptr;
	if (target->IsNPC() && target->CastToNPC()->GetSwarmInfo() && target_owner &&
			target_owner->IsCorpse() && !target_owner->IsPlayerCorpse())
		target_owner = nullptr;

	//cannot hurt untargetable mobs
	bodyType bt = target->GetBodyType();

	if(bt == BT_NoTarget || bt == BT_NoTarget2) {
		if (RuleB(Pets, UnTargetableSwarmPet)) {
			if (target->IsNPC()) {
				if (!target->CastToNPC()->GetSwarmOwner()) {
					return(false);
				}
			} else {
				return(false);
			}
		} else {
			return(false);
		}
	}

	if(!isSpellAttack)
	{
		if(GetClass() == LDON_TREASURE)
		{
			return false;
		}
	}

	// the format here is a matrix of mob type vs mob type.
	// redundant ones are omitted and the reverse is tried if it falls through.

	// first figure out if we're pets. we always look at the master's flags.
	// no need to compare pets to anything
	mob1 = our_owner ? our_owner : this;
	mob2 = target_owner ? target_owner : target;

	reverse = 0;
	do
	{
		if(_CLIENT(mob1))
		{
			if(_CLIENT(mob2))					// client vs client
			{
				c1 = mob1->CastToClient();
				c2 = mob2->CastToClient();

				if	// if both are pvp they can fight
				(
					c1->GetPVP() &&
					c2->GetPVP()
				)
					return true;
				else if	// if they're dueling they can go at it
				(
					c1->IsDueling() &&
					c2->IsDueling() &&
					c1->GetDuelTarget() == c2->GetID() &&
					c2->GetDuelTarget() == c1->GetID()
				)
					return true;
				else
					return false;
			}
			else if(_NPC(mob2))				// client vs npc
			{
				return true;
			}
			else if(_BECOMENPC(mob2))	// client vs becomenpc
			{
				c1 = mob1->CastToClient();
				becomenpc = mob2->CastToClient();

				if(c1->GetLevel() > becomenpc->GetBecomeNPCLevel())
					return false;
				else
					return true;
			}
			else if(_CLIENTCORPSE(mob2))	// client vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// client vs npc corpse
			{
				return false;
			}
		}
		else if(_NPC(mob1))
		{
			if(_NPC(mob2))						// npc vs npc
			{
/*
this says that an NPC can NEVER attack a faction ally...
this is stupid... somebody else should check this rule if they want to
enforce it, this just says 'can they possibly fight based on their
type', in which case, the answer is yes.
*/
/*				npc1 = mob1->CastToNPC();
				npc2 = mob2->CastToNPC();
				if
				(
					npc1->GetPrimaryFaction() != 0 &&
					npc2->GetPrimaryFaction() != 0 &&
					(
						npc1->GetPrimaryFaction() == npc2->GetPrimaryFaction() ||
						npc1->IsFactionListAlly(npc2->GetPrimaryFaction())
					)
				)
					return false;
				else
*/
					return true;
			}
			else if(_BECOMENPC(mob2))	// npc vs becomenpc
			{
				return true;
			}
			else if(_CLIENTCORPSE(mob2))	// npc vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// npc vs npc corpse
			{
				return false;
			}
		}
		else if(_BECOMENPC(mob1))
		{
			if(_BECOMENPC(mob2))			// becomenpc vs becomenpc
			{
				return true;
			}
			else if(_CLIENTCORPSE(mob2))	// becomenpc vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// becomenpc vs npc corpse
			{
				return false;
			}
		}
		else if(_CLIENTCORPSE(mob1))
		{
			if(_CLIENTCORPSE(mob2))		// client corpse vs client corpse
			{
				return false;
			}
			else if(_NPCCORPSE(mob2))	// client corpse vs npc corpse
			{
				return false;
			}
		}
		else if(_NPCCORPSE(mob1))
		{
			if(_NPCCORPSE(mob2))			// npc corpse vs npc corpse
			{
				return false;
			}
		}

#ifdef BOTS
		bool HasRuleDefined = false;
		bool IsBotAttackAllowed = false;
		IsBotAttackAllowed = Bot::IsBotAttackAllowed(mob1, mob2, HasRuleDefined);
		if(HasRuleDefined)
			return IsBotAttackAllowed;
#endif //BOTS

		// we fell through, now we swap the 2 mobs and run through again once more
		tempmob = mob1;
		mob1 = mob2;
		mob2 = tempmob;
	}
	while( reverse++ == 0 );

	Log(Logs::General, Logs::None, "Mob::IsAttackAllowed: don't have a rule for this - %s vs %s\n", this->GetName(), target->GetName());
	return false;
}