示例#1
0
int32 Client::GetACMit() {

	int mitigation = 0;
	if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
		mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI/10)/4 + (itembonuses.AC+1);
		mitigation -= 4;
	}
	else {
		mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI/10)/3 + ((itembonuses.AC*4)/3);
		if(m_pp.class_ == MONK)
			mitigation += GetLevel() * 13/10;	//the 13/10 might be wrong, but it is close...
	}

	// Shield AC bonus for HeroicSTR
	if(itembonuses.HeroicSTR) {
		bool equiped = CastToClient()->m_inv.GetItem(MainSecondary);
		if(equiped) {
			uint8 shield = CastToClient()->m_inv.GetItem(MainSecondary)->GetItem()->ItemType;
			if(shield == ItemTypeShield)
				mitigation += itembonuses.HeroicSTR/2;
		}
	}

	return(mitigation*1000/847);
}
示例#2
0
void Mob::RemoveAllAuras()
{
	if (IsClient()) {
		database.SaveAuras(CastToClient());
		EQApplicationPacket outapp(OP_UpdateAura, 4);
		outapp.WriteUInt32(2);
		CastToClient()->QueuePacket(&outapp);
	}

	// this is sent on camp/zone, so it just despawns?
	if (aura_mgr.count) {
		for (auto &e : aura_mgr.auras) {
			if (e.aura)
				e.aura->Depop();
		}
	}

	aura_mgr.count = 0;

	if (trap_mgr.count) {
		for (auto &e : trap_mgr.auras) {
			if (e.aura)
				e.aura->Depop();
		}
	}

	trap_mgr.count = 0;

	return;
}
示例#3
0
文件: aa.cpp 项目: af4t/Server
void Mob::ExpendAlternateAdvancementCharge(uint32 aa_id) {
	for(auto &iter : aa_ranks) {
		AA::Ability *ability = zone->GetAlternateAdvancementAbility(iter.first);
		if(ability && aa_id == ability->id) {
			if(iter.second.second > 0) {
				iter.second.second -= 1;

				if(iter.second.second == 0) {
					if(IsClient()) {
						AA::Rank *r = ability->GetRankByPointsSpent(iter.second.first);
						if(r) {
							CastToClient()->GetEPP().expended_aa += r->cost;
						}
					}
					if (IsClient()) {
						auto c = CastToClient();
						c->RemoveExpendedAA(ability->first_rank_id);
					}
					aa_ranks.erase(iter.first);
				}

				if(IsClient()) {
					Client *c = CastToClient();
					c->SaveAA();
					c->SendAlternateAdvancementPoints();
				}
			}

			return;
		}
	}
}
示例#4
0
文件: aa.cpp 项目: af4t/Server
bool Mob::CanUseAlternateAdvancementRank(AA::Rank *rank) {
	AA::Ability *ability = rank->base_ability;

	if(!ability)
		return false;

	if(!(ability->classes & (1 << GetClass()))) {
		return false;
	}

	// Passive and Active Shroud AAs
	// For now we skip them
	if(ability->category == 3 || ability->category == 4) {
		return false;
	}

	//the one titanium hack i will allow
	//just to make sure we dont crash the client with newer aas
	//we'll exclude any expendable ones
	if(IsClient() && CastToClient()->ClientVersionBit() & EQEmu::versions::maskTitaniumAndEarlier) {
		if(ability->charges > 0) {
			return false;
		}
	}

	if(IsClient()) {
		if(rank->expansion && !(CastToClient()->GetPP().expansions & (1 << (rank->expansion - 1)))) {
			return false;
		}
	} else {
		if(rank->expansion && !(RuleI(World, ExpansionSettings) & (1 << (rank->expansion - 1)))) {
			return false;
		}
	}

	auto race = GetPlayerRaceValue(GetBaseRace());
	race = race > 16 ? 1 : race;
	if(!(ability->races & (1 << (race - 1)))) {
		return false;
	}

	auto deity = GetDeityBit();
	if(!(ability->deities & deity)) {
		return false;
	}

	if(IsClient() && CastToClient()->Admin() < ability->status) {
		return false;
	}

	if(GetBaseRace() == 522) {
		//drakkin_heritage
		if(!(ability->drakkin_heritage & (1 << GetDrakkinHeritage()))) {
			return false;
		}
	}

	return true;
}
示例#5
0
void Mob::RemoveAura(int spawn_id, bool skip_strip, bool expired)
{
	for (int i = 0; i < aura_mgr.count; ++i) {
		auto &aura = aura_mgr.auras[i];
		if (aura.spawn_id == spawn_id) {
			if (aura.aura)
				aura.aura->Depop(skip_strip);
			if (expired && IsClient()) {
				CastToClient()->SendColoredText(
				    CC_Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color
				// need to update client UI too
				auto app = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraDestory_Struct));
				auto ads = (AuraDestory_Struct *)app->pBuffer;
				ads->action = 1; // delete
				ads->entity_id = spawn_id;
				CastToClient()->QueuePacket(app);
				safe_delete(app);
			}
			while (aura_mgr.count - 1 > i) {
				i++;
				aura.spawn_id = aura_mgr.auras[i].spawn_id;
				aura.icon = aura_mgr.auras[i].icon;
				aura.aura = aura_mgr.auras[i].aura;
				aura_mgr.auras[i].aura = nullptr;
				strn0cpy(aura.name, aura_mgr.auras[i].name, 64);
			}
			aura_mgr.count--;
			return;
		}
	}

	for (int i = 0; i < trap_mgr.count; ++i) {
		auto &aura = trap_mgr.auras[i];
		if (aura.spawn_id == spawn_id) {
			if (aura.aura)
				aura.aura->Depop(skip_strip);
			if (expired && IsClient())
				CastToClient()->SendColoredText(
				    CC_Yellow, StringFormat("%s has expired.", aura.name)); // TODO: verify color
			while (trap_mgr.count - 1 > i) {
				i++;
				aura.spawn_id = trap_mgr.auras[i].spawn_id;
				aura.icon = trap_mgr.auras[i].icon;
				aura.aura = trap_mgr.auras[i].aura;
				trap_mgr.auras[i].aura = nullptr;
				strn0cpy(aura.name, trap_mgr.auras[i].name, 64);
			}
			trap_mgr.count--;
			return;
		}
	}

	return;
}
示例#6
0
// This is a testing formula for AC, the value this returns should be the same value as the one the client shows...
// ac1 and ac2 are probably the damage migitation and damage avoidance numbers, not sure which is which.
// I forgot to include the iksar defense bonus and i cant find my notes now...
// AC from spells are not included (cant even cast spells yet..)
int32 Client::CalcAC()
{
	// new formula
	int avoidance = (acmod() + ((GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) * 16) / 9);
	if (avoidance < 0) {
		avoidance = 0;
	}
	int mitigation = 0;
	if (m_pp.class_ == WIZARD || m_pp.class_ == MAGICIAN || m_pp.class_ == NECROMANCER || m_pp.class_ == ENCHANTER) {
		//something is wrong with this, naked casters have the wrong natural AC
//		mitigation = (spellbonuses.AC/3) + (GetSkill(DEFENSE)/2) + (itembonuses.AC+1);
		mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 4 + (itembonuses.AC + 1);
		//this might be off by 4..
		mitigation -= 4;
	}
	else {
//		mitigation = (spellbonuses.AC/4) + (GetSkill(DEFENSE)/3) + ((itembonuses.AC*4)/3);
		mitigation = (GetSkill(SkillDefense) + itembonuses.HeroicAGI / 10) / 3 + ((itembonuses.AC * 4) / 3);
		if (m_pp.class_ == MONK) {
			mitigation += GetLevel() * 13 / 10;    //the 13/10 might be wrong, but it is close...
		}
	}
	int displayed = 0;
	displayed += ((avoidance + mitigation) * 1000) / 847;	//natural AC
	//Iksar AC, untested
	if (GetRace() == IKSAR) {
		displayed += 12;
		int iksarlevel = GetLevel();
		iksarlevel -= 10;
		if (iksarlevel > 25) {
			iksarlevel = 25;
		}
		if (iksarlevel > 0) {
			displayed += iksarlevel * 12 / 10;
		}
	}
	// Shield AC bonus for HeroicSTR
	if (itembonuses.HeroicSTR) {
		bool equiped = CastToClient()->m_inv.GetItem(MainSecondary);
		if (equiped) {
			uint8 shield = CastToClient()->m_inv.GetItem(MainSecondary)->GetItem()->ItemType;
			if (shield == ItemTypeShield) {
				displayed += itembonuses.HeroicSTR / 2;
			}
		}
	}
	//spell AC bonuses are added directly to natural total
	displayed += spellbonuses.AC;
	AC = displayed;
	return (AC);
}
示例#7
0
void Pet::SetTarget(Mob *mob)
{
	if (mob == GetTarget())
		return;

	auto owner = GetOwner();
	if (owner && owner->IsClient() && owner->CastToClient()->ClientVersionBit() & EQEmu::versions::bit_UFAndLater) {
		auto app = new EQApplicationPacket(OP_PetHoTT, sizeof(ClientTarget_Struct));
		auto ct = (ClientTarget_Struct *)app->pBuffer;
		ct->new_target = mob ? mob->GetID() : 0;
		owner->CastToClient()->QueuePacket(app);
		safe_delete(app);
	}
	NPC::SetTarget(mob);
}
示例#8
0
//healing and buffing aggro
int32 Mob::CheckHealAggroAmount(uint16 spellid, uint32 heal_possible) {
	uint16 spell_id = spellid;
	int32 AggroAmount = 0;

	for (int o = 0; o < EFFECT_COUNT; o++) {
		switch(spells[spell_id].effectid[o]) {
			case SE_CurrentHP: {
				AggroAmount += spells[spell_id].mana;
				break;
			}
			case SE_Rune: {
				AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[0], spells[spell_id].base[0], spells[spell_id].max[o], this->GetLevel(), spellid) * 2;
				break;
			}
			case SE_HealOverTime:{
				AggroAmount += CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], this->GetLevel(), spell_id);
				break;
			}
			default:{
				break;
			}
		}
	}
	if (IsBardSong(spell_id))
		AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100;
	if (GetOwner() && IsPet())
		AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;

	if(AggroAmount > 0)
	{
		int HateMod = RuleI(Aggro, SpellAggroMod);

		if(IsClient())
		{
			HateMod += CastToClient()->GetFocusEffect(focusSpellHateMod, spell_id);
		}

		//Live AA - Spell casting subtlety
		HateMod += aabonuses.hatemod + spellbonuses.hatemod + itembonuses.hatemod;

		AggroAmount = (AggroAmount * HateMod) / 100;

		//made up number probably scales a bit differently on live but it seems like it will be close enough
		//every time you cast on live you get a certain amount of "this is a spell" aggro
		//confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected
		//by hate modifiers either.
		//AggroAmount += (slevel*slevel/72); // Moved Below


	}


	if(AggroAmount < 0)
		return 0;
	else
		return AggroAmount;
}
示例#9
0
文件: pets.cpp 项目: josheb/emu_dc
void Mob::SetPetID(uint16 NewPetID) {
	if (NewPetID == GetID() && NewPetID != 0)
		return;
	petid = NewPetID;

	if(IsClient())
	{
		Mob* NewPet = entity_list.GetMob(NewPetID);
		CastToClient()->UpdateXTargetType(MyPet, NewPet);
	}
}
示例#10
0
bool Aura::ShouldISpawnFor(Client *c)
{
	if (spawn_type == AuraSpawns::Noone)
		return false;

	if (spawn_type == AuraSpawns::Everyone)
		return true;

	// hey, it's our owner!
	if (c->GetID() == m_owner)
		return true;

	// so this one is a bit trickier
	auto owner = GetOwner();
	if (owner == nullptr)
		return false; // hmm

	owner = owner->GetOwnerOrSelf(); // pet auras we need the pet's owner
	if (owner == nullptr) // shouldn't really be needed
		return false;

	// gotta check again for pet aura case -.-
	if (owner == c)
		return true;

	if (owner->IsRaidGrouped() && owner->IsClient()) {
		auto raid = owner->GetRaid();
		if (raid == nullptr)
			return false; // hmm
		auto group_id = raid->GetGroup(owner->CastToClient());
		if (group_id == 0xFFFFFFFF) // owner handled above, and they're in a raid and groupless
			return false;

		auto idx = raid->GetPlayerIndex(c);
		if (idx == 0xFFFFFFFF) // they're not in our raid!
			return false;

		if (raid->members[idx].GroupNumber != group_id) // in our raid, but not our group
			return false;

		return true; // we got here so we know that 1 they're in our raid and 2 they're in our group!
	} else if (owner->IsGrouped()) {
		auto group = owner->GetGroup();
		if (group == nullptr)
			return false; // hmm

		// easy, in our group
		return group->IsGroupMember(c);
	}

	// our owner is not raided or grouped, and they're handled above so we don't spawn!
	return false;
}
示例#11
0
void Mob::AddAura(Aura *aura, AuraRecord &record)
{
	// this is called only when it's safe
	assert(aura != nullptr);
	strn0cpy(aura_mgr.auras[aura_mgr.count].name, aura->GetCleanName(), 64);
	aura_mgr.auras[aura_mgr.count].spawn_id = aura->GetID();
	aura_mgr.auras[aura_mgr.count].aura = aura;
	if (record.icon == -1)
		aura_mgr.auras[aura_mgr.count].icon = spells[record.spell_id].new_icon;
	else
		aura_mgr.auras[aura_mgr.count].icon = record.icon;
	if (IsClient()) {
		auto outapp = new EQApplicationPacket(OP_UpdateAura, sizeof(AuraCreate_Struct));
		auto aura_create = (AuraCreate_Struct *)outapp->pBuffer;
		aura_create->action = 0;
		aura_create->type = 1; // this can be 0 sometimes too
		strn0cpy(aura_create->aura_name, aura_mgr.auras[aura_mgr.count].name, 64);
		aura_create->entity_id = aura_mgr.auras[aura_mgr.count].spawn_id;
		aura_create->icon = aura_mgr.auras[aura_mgr.count].icon;
		CastToClient()->FastQueuePacket(&outapp);
	}
	// we can increment this now
	aura_mgr.count++;
}
示例#12
0
文件: aa.cpp 项目: Outakyoutou/Server
void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
	AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
	if(!rank) {
		return;
	}

	AA::Ability *ability = rank->base_ability;
	if(!ability) {
		return;
	}

	if(!IsValidSpell(rank->spell)) {
		return;
	}

	if(!CanUseAlternateAdvancementRank(rank)) {
		return;
	}

	//make sure it is not a passive
	if(!rank->effects.empty()) {
		return;
	}

	uint32 charges = 0;
	// We don't have the AA
	if (!GetAA(rank_id, &charges))
		return;

	//if expendable make sure we have charges
	if(ability->charges > 0 && charges < 1)
		return;

	//check cooldown
	if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart)) {
		uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
		uint32 aaremain_hr = aaremain / (60 * 60);
		uint32 aaremain_min = (aaremain / 60) % 60;
		uint32 aaremain_sec = aaremain % 60;

		if(aaremain_hr >= 1) {
			Message(13, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
			aaremain_hr, aaremain_min, aaremain_sec);
		}
		else {
			Message(13, "You can use this ability again in %u minute(s) %u seconds",
			aaremain_min, aaremain_sec);
		}

		return;
	}

	//calculate cooldown
	int cooldown = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank);
	if(cooldown < 0) {
		cooldown = 0;
	}

	if (!IsCastWhileInvis(rank->spell))
		CommonBreakInvisible();
	// Bards can cast instant cast AAs while they are casting another song
	if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
		if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), ALTERNATE_ABILITY_SPELL_SLOT, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
			return;
		}
		ExpendAlternateAdvancementCharge(ability->id);
	} else {
		if(!CastSpell(rank->spell, target_id, ALTERNATE_ABILITY_SPELL_SLOT, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
			return;
		}
	}

	CastToClient()->GetPTimers().Start(rank->spell_type + pTimerAAStart, cooldown);
	SendAlternateAdvancementTimer(rank->spell_type, 0, 0);
}
示例#13
0
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;
}
示例#14
0
文件: aa.cpp 项目: af4t/Server
void Mob::TemporaryPets(uint16 spell_id, Mob *targ, const char *name_override, uint32 duration_override, bool followme, bool sticktarg) {

	//It might not be a bad idea to put these into the database, eventually..

	//Dook- swarms and wards

	// do nothing if it's a corpse
	if (targ != nullptr && targ->IsCorpse())
		return;

	// yep, even these need pet power!
	int act_power = 0;

	if (IsClient()) {
		act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
		act_power = CastToClient()->mod_pet_power(act_power, spell_id);
	}

	PetRecord record;
	if (!database.GetPoweredPetEntry(spells[spell_id].teleport_zone, act_power, &record))
	{
		Log(Logs::General, Logs::Error, "Unknown swarm pet spell id: %d, check pets table", spell_id);
		Message(13, "Unable to find data for pet %s", spells[spell_id].teleport_zone);
		return;
	}

	SwarmPet_Struct pet;
	pet.count = 1;
	pet.duration = 1;

	for (int x = 0; x < MAX_SWARM_PETS; x++)
	{
		if (spells[spell_id].effectid[x] == SE_TemporaryPets)
		{
			pet.count = spells[spell_id].base[x];
			pet.duration = spells[spell_id].max[x];
		}
	}

	pet.duration += GetFocusEffect(focusSwarmPetDuration, spell_id) / 1000;

	pet.npc_id = record.npc_type;

	NPCType *made_npc = nullptr;

	const NPCType *npc_type = database.LoadNPCTypesData(pet.npc_id);
	if (npc_type == nullptr) {
		//log write
		Log(Logs::General, Logs::Error, "Unknown npc type for swarm pet spell id: %d", spell_id);
		Message(0, "Unable to find pet!");
		return;
	}

	if (name_override != nullptr) {
		//we have to make a custom NPC type for this name change
		made_npc = new NPCType;
		memcpy(made_npc, npc_type, sizeof(NPCType));
		strcpy(made_npc->name, name_override);
		npc_type = made_npc;
	}

	int summon_count = 0;
	summon_count = pet.count;

	if (summon_count > MAX_SWARM_PETS)
		summon_count = MAX_SWARM_PETS;

	static const glm::vec2 swarmPetLocations[MAX_SWARM_PETS] = {
		glm::vec2(5, 5), glm::vec2(-5, 5), glm::vec2(5, -5), glm::vec2(-5, -5),
		glm::vec2(10, 10), glm::vec2(-10, 10), glm::vec2(10, -10), glm::vec2(-10, -10),
		glm::vec2(8, 8), glm::vec2(-8, 8), glm::vec2(8, -8), glm::vec2(-8, -8)
	};

	while (summon_count > 0) {
		int pet_duration = pet.duration;
		if (duration_override > 0)
			pet_duration = duration_override;

		//this is a little messy, but the only way to do it right
		//it would be possible to optimize out this copy for the last pet, but oh well
		NPCType *npc_dup = nullptr;
		if (made_npc != nullptr) {
			npc_dup = new NPCType;
			memcpy(npc_dup, made_npc, sizeof(NPCType));
		}

		NPC* swarm_pet_npc = new NPC(
			(npc_dup != nullptr) ? npc_dup : npc_type,	//make sure we give the NPC the correct data pointer
			0,
			GetPosition() + glm::vec4(swarmPetLocations[summon_count], 0.0f, 0.0f),
			GravityBehavior::Water);

		if (followme)
			swarm_pet_npc->SetFollowID(GetID());

		if (!swarm_pet_npc->GetSwarmInfo()) {
			auto nSI = new SwarmPet;
			swarm_pet_npc->SetSwarmInfo(nSI);
			swarm_pet_npc->GetSwarmInfo()->duration = new Timer(pet_duration * 1000);
		}
		else {
			swarm_pet_npc->GetSwarmInfo()->duration->Start(pet_duration * 1000);
		}

		swarm_pet_npc->StartSwarmTimer(pet_duration * 1000);

		//removing this prevents the pet from attacking
		swarm_pet_npc->GetSwarmInfo()->owner_id = GetID();

		//give the pets somebody to "love"
		if (targ != nullptr) {
			swarm_pet_npc->AddToHateList(targ, 1000, 1000);
			if (RuleB(Spells, SwarmPetTargetLock) || sticktarg)
				swarm_pet_npc->GetSwarmInfo()->target = targ->GetID();
			else
				swarm_pet_npc->GetSwarmInfo()->target = 0;
		}

		//we allocated a new NPC type object, give the NPC ownership of that memory
		if (npc_dup != nullptr)
			swarm_pet_npc->GiveNPCTypeData(npc_dup);

		entity_list.AddNPC(swarm_pet_npc, true, true);
		summon_count--;
	}

	//the target of these swarm pets will take offense to being cast on...
	if (targ != nullptr)
		targ->AddToHateList(this, 1, 0);

	// The other pointers we make are handled elsewhere.
	delete made_npc;
}
示例#15
0
文件: aa.cpp 项目: af4t/Server
bool Mob::CanPurchaseAlternateAdvancementRank(AA::Rank *rank, bool check_price, bool check_grant) {
	AA::Ability *ability = rank->base_ability;

	if(!ability)
		return false;

	if(!CanUseAlternateAdvancementRank(rank)) {
		return false;
	}

	//You can't purchase grant only AAs they can only be assigned
	if(check_grant && ability->grant_only) {
		return false;
	}

	//check level req
	if(rank->level_req > GetLevel()) {
		return false;
	}

	uint32 current_charges = 0;
	auto points = GetAA(rank->id, &current_charges);

	//check that we are on previous rank already (if exists)
	//grant ignores the req to own the previous rank.
	if(check_grant && rank->prev) {
		if(points != rank->prev->current_value) {
			return false;
		}
	}

	//check that we aren't already on this rank or one ahead of us
	if(points >= rank->current_value) {
		return false;
	}

	//if expendable only let us purchase if we have no charges already
	//not quite sure on how this functions client side atm
	//I intend to look into it later to make sure the behavior is right
	if(ability->charges > 0 && current_charges > 0) {
		return false;
	}

	//check prereqs
	for(auto &prereq : rank->prereqs) {
		AA::Ability *prereq_ability = zone->GetAlternateAdvancementAbility(prereq.first);

		if(prereq_ability) {
			auto ranks = GetAA(prereq_ability->first_rank_id);
			if(ranks < prereq.second) {
				return false;
			}
		}
	}

	//check price, if client
	if(check_price && IsClient()) {
		if(rank->cost > CastToClient()->GetAAPoints()) {
			return false;
		}
	}

	return true;
}
示例#16
0
///////////////////////////////////////////////////
// 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();
}
示例#17
0
文件: aa.cpp 项目: af4t/Server
void Client::ActivateAlternateAdvancementAbility(int rank_id, int target_id) {
	AA::Rank *rank = zone->GetAlternateAdvancementRank(rank_id);
	if(!rank) {
		return;
	}

	AA::Ability *ability = rank->base_ability;
	if(!ability) {
		return;
	}

	if(!IsValidSpell(rank->spell)) {
		return;
	}

	if(!CanUseAlternateAdvancementRank(rank)) {
		return;
	}

	//make sure it is not a passive
	if(!rank->effects.empty()) {
		return;
	}

	uint32 charges = 0;
	// We don't have the AA
	if (!GetAA(rank_id, &charges))
		return;

	//if expendable make sure we have charges
	if(ability->charges > 0 && charges < 1)
		return;

	//check cooldown
	if(!p_timers.Expired(&database, rank->spell_type + pTimerAAStart, false)) {
		uint32 aaremain = p_timers.GetRemainingTime(rank->spell_type + pTimerAAStart);
		uint32 aaremain_hr = aaremain / (60 * 60);
		uint32 aaremain_min = (aaremain / 60) % 60;
		uint32 aaremain_sec = aaremain % 60;

		if(aaremain_hr >= 1) {
			Message(13, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
			aaremain_hr, aaremain_min, aaremain_sec);
		}
		else {
			Message(13, "You can use this ability again in %u minute(s) %u seconds",
			aaremain_min, aaremain_sec);
		}

		return;
	}

	//calculate cooldown
	int cooldown = rank->recast_time - GetAlternateAdvancementCooldownReduction(rank);
	if(cooldown < 0) {
		cooldown = 0;
	}

	if (!IsCastWhileInvis(rank->spell))
		CommonBreakInvisible();

	if (spells[rank->spell].sneak && (!hidden || (hidden && (Timer::GetCurrentTime() - tmHidden) < 4000))) {
		Message_StringID(MT_SpellFailure, SNEAK_RESTRICT);
		return;
	}
	//
	// Modern clients don't require pet targeted for AA casts that are ST_Pet
	if (spells[rank->spell].targettype == ST_Pet || spells[rank->spell].targettype == ST_SummonedPet)
		target_id = GetPetID();

	// extra handling for cast_not_standing spells
	if (!spells[rank->spell].cast_not_standing) {
		if (GetAppearance() == eaSitting) // we need to stand!
			SetAppearance(eaStanding, false);

		if (GetAppearance() != eaStanding) {
			Message_StringID(MT_SpellFailure, STAND_TO_CAST);
			return;
		}
	}

	// Bards can cast instant cast AAs while they are casting another song
	if(spells[rank->spell].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
		if(!SpellFinished(rank->spell, entity_list.GetMob(target_id), EQEmu::spells::CastingSlot::AltAbility, spells[rank->spell].mana, -1, spells[rank->spell].ResistDiff, false)) {
			return;
		}
		ExpendAlternateAdvancementCharge(ability->id);
	} else {
		if(!CastSpell(rank->spell, target_id, EQEmu::spells::CastingSlot::AltAbility, -1, -1, 0, -1, rank->spell_type + pTimerAAStart, cooldown, nullptr, rank->id)) {
			return;
		}
	}

	CastToClient()->GetPTimers().Start(rank->spell_type + pTimerAAStart, cooldown);
	SendAlternateAdvancementTimer(rank->spell_type, 0, 0);
}
示例#18
0
//offensive spell aggro
int32 Mob::CheckAggroAmount(uint16 spell_id, bool isproc)
{
	int32 AggroAmount = 0;
	int32 nonModifiedAggro = 0;
	uint16 slevel = GetLevel();

	for (int o = 0; o < EFFECT_COUNT; o++) {
		switch (spells[spell_id].effectid[o]) {
			case SE_CurrentHPOnce:
			case SE_CurrentHP: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if(val < 0)
					AggroAmount -= val;
				break;
			}
			case SE_MovementSpeed: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount += (2 + ((slevel * slevel) / 8));
				break;
			}
			case SE_AttackSpeed:
			case SE_AttackSpeed2:
			case SE_AttackSpeed3: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 100)
					AggroAmount += (5 + ((slevel * slevel) / 5));
				break;
			}
			case SE_Stun: {
				int val = (5 + ((slevel * slevel) / 6));
				if (isproc && RuleI(Aggro,MaxStunProcAggro) > -1 && (val > RuleI(Aggro,MaxStunProcAggro)))
					val = RuleI(Aggro,MaxStunProcAggro);
				AggroAmount += val;
				break;
			}
			case SE_Blind: {
				AggroAmount += (5 + ((slevel * slevel) / 6));
				break;
			}
			case SE_Mez: {
				AggroAmount += (5 + ((slevel * slevel) / 5));
				break;
			}
			case SE_Charm: {
				AggroAmount += (5 + ((slevel * slevel) / 5));
				break;
			}
			case SE_Root: {
				AggroAmount += (2 + ((slevel * slevel) / 8));
				break;
			}
			case SE_Fear: {
				AggroAmount += (5 + ((slevel * slevel) / 6));
				break;
			}
			case SE_ATK:
			case SE_ACv2:
			case SE_ArmorClass: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 2;
				break;
			}
			case SE_ResistMagic:
			case SE_ResistFire:
			case SE_ResistCold:
			case SE_ResistPoison:
			case SE_ResistDisease: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 3;
				break;
			}
			case SE_ResistAll: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 6;
				break;
			}
			case SE_STR:
			case SE_STA:
			case SE_DEX:
			case SE_AGI:
			case SE_INT:
			case SE_WIS:
			case SE_CHA: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 2;
				break;
			}
			case SE_AllStats: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 6;
				break;
			}
			case SE_BardAEDot: {
				AggroAmount += slevel * 2;
				break;
			}
			case SE_SpinTarget: {
				AggroAmount += (5 + ((slevel * slevel) / 5));
				break;
			}
			case SE_Amnesia:
			case SE_Silence: {
				AggroAmount += slevel * 2;
				break;
			}
			case SE_Destroy: {
				AggroAmount += slevel * 2;
				break;
			}
			case SE_Harmony:
			case SE_CastingLevel:
			case SE_MeleeMitigation:
			case SE_CriticalHitChance:
			case SE_AvoidMeleeChance:
			case SE_RiposteChance:
			case SE_DodgeChance:
			case SE_ParryChance:
			case SE_DualWieldChance:
			case SE_DoubleAttackChance:
			case SE_MeleeSkillCheck:
			case SE_HitChance:
			case SE_IncreaseArchery:
			case SE_DamageModifier:
			case SE_MinDamageModifier:
			case SE_IncreaseBlockChance:
			case SE_Accuracy:
			case SE_DamageShield:
			case SE_SpellDamageShield:
			case SE_ReverseDS: {
				AggroAmount += slevel * 2;
				break;
			}
			case SE_CurrentMana:
			case SE_ManaRegen_v2:
			case SE_ManaPool:
			case SE_CurrentEndurance: {
				int val = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				if (val < 0)
					AggroAmount -= val * 2;
				break;
			}
			case SE_CancelMagic:
			case SE_DispelDetrimental: {
				AggroAmount += slevel;
				break;
			}
			case SE_ReduceHate:
			case SE_InstantHate: {
				nonModifiedAggro = CalcSpellEffectValue_formula(spells[spell_id].formula[o], spells[spell_id].base[o], spells[spell_id].max[o], slevel, spell_id);
				break;
			}
		}
	}

	if (IsAEDurationSpell(spell_id))
		AggroAmount /= 2;

	if (spells[spell_id].HateAdded > 0)
		AggroAmount = spells[spell_id].HateAdded;

	if (IsBardSong(spell_id))
		AggroAmount = AggroAmount * RuleI(Aggro, SongAggroMod) / 100;
	if (GetOwner() && IsPet())
		AggroAmount = AggroAmount * RuleI(Aggro, PetSpellAggroMod) / 100;

	if (AggroAmount > 0) {

		int HateMod = RuleI(Aggro, SpellAggroMod);

		if (IsClient())
			HateMod += CastToClient()->GetFocusEffect(focusSpellHateMod, spell_id);

		AggroAmount = (AggroAmount * HateMod) / 100;

		//made up number probably scales a bit differently on live but it seems like it will be close enough
		//every time you cast on live you get a certain amount of "this is a spell" aggro
		//confirmed by EQ devs to be 100 exactly at level 85. From their wording it doesn't seem like it's affected
		//by hate modifiers either.
		//AggroAmount += (slevel*slevel/72);
		// Saved so I can reimplement it;
		// this should only be on the spell to aggro the npc not every spell

	}

	return AggroAmount + spells[spell_id].bonushate + nonModifiedAggro;
}
示例#19
0
//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);
}
示例#20
0
文件: pets.cpp 项目: epicemu/Server
// Split from the basic MakePet to allow backward compatiblity with existing code while also 
// making it possible for petpower to be retained without the focus item having to
// stay equipped when the character zones. petpower of -1 means that the currently equipped petfocus
// of a client is searched for and used instead.
void Mob::MakePoweredPet(int16 spell_id, const char* pettype, sint16 petpower, const char *petname) {
	// Sanity and early out checking first.
	if(HasPet() || pettype == NULL)
		return;

	sint16 act_power = 0; // lets see if this works to randomize pet levels // The actual pet power we'll use.
	if (petpower == 0) {  // was == -1
		if (this->IsClient())
			act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);
	}
	if (petpower == -1)  {
		act_power = petpower + MakeRandomInt(0,5);
	}


	// optional rule: classic style variance in pets. Achieve this by
	// adding a random 0-4 to pet power, since it only comes in increments
	// of five from focus effects.

	//lookup our pets table record for this type
	PetRecord record;
	if(!database.GetPoweredPetEntry(pettype, act_power, &record)) {
		Message(13, "Unable to find data for pet %s", pettype);
		LogFile->write(EQEMuLog::Error, "Unable to find data for pet %s, check pets table.", pettype);
		return;
	}

	//find the NPC data for the specified NPC type
	const NPCType *base = database.GetNPCType(record.npc_type);
	if(base == NULL) {
		Message(13, "Unable to load NPC data for pet %s", pettype);
		LogFile->write(EQEMuLog::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type);
		return;
	}

	//we copy the npc_type data because we need to edit it a bit
	NPCType *npc_type = new NPCType;
	memcpy(npc_type, base, sizeof(NPCType));

	// If pet power is set to -1 in the DB, use stat scaling
	if (this->IsClient() && petpower == -1) 
	{
		float scale_power = (float)act_power / 100.0f;
		if(scale_power > 0)
		{
			npc_type->max_hp *= (1 + scale_power);
			npc_type->cur_hp = npc_type->max_hp;
			npc_type->AC *= (1 + scale_power);
			npc_type->level += (float)scale_power * 50; //(int)act_power; // gains an additional level for every 25 pet power
			npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2)));
			npc_type->max_dmg = (npc_type->max_dmg * (1 + (scale_power / 2)));
			npc_type->size *= (1 + (scale_power / 2));
		}
		petpower = act_power;
	}
	
	switch (GetAA(aaElementalDurability))
	{
	case 1:
		npc_type->max_hp *= 1.02;
		npc_type->cur_hp = npc_type->max_hp;
		break;
	case 2:
		npc_type->max_hp *= 1.05;
		npc_type->cur_hp = npc_type->max_hp;
		break;
	case 3:
		npc_type->max_hp *= 1.10;
		npc_type->cur_hp = npc_type->max_hp;
		break;
	}

	//TODO: think about regen (engaged vs. not engaged)
	
	// Pet naming:
	// 0 - `s pet
	// 1 - `s familiar
	// 2 - `s Warder
	// 3 - Random name if client, `s pet for others
	// 4 - Keep DB name


	if (petname != NULL) {
		// Name was provided, use it.
		strn0cpy(npc_type->name, petname, 64);
	} else if (record.petnaming == 0) {
		strcpy(npc_type->name, this->GetCleanName());
		npc_type->name[25] = '\0';
		strcat(npc_type->name, "`s_pet");
	} else if (record.petnaming == 1) {
		strcpy(npc_type->name, this->GetName());
		npc_type->name[19] = '\0';
		strcat(npc_type->name, "`s_familiar");
	} else if (record.petnaming == 2) {
		strcpy(npc_type->name, this->GetName());
		npc_type->name[21] = 0;
		strcat(npc_type->name, "`s_Warder");
	} else if (record.petnaming == 4) {
		// Keep the DB name
	} else if (record.petnaming == 3 && IsClient()) {
		strcpy(npc_type->name, GetRandPetName());
	} else {
		strcpy(npc_type->name, this->GetCleanName());
		npc_type->name[25] = '\0';
		strcat(npc_type->name, "`s_pet");
	}
	
	//handle beastlord pet appearance
	if(record.petnaming == 2) 
	{
		switch(GetBaseRace()) 
		{
		case VAHSHIR: 
			npc_type->race = TIGER; 
			npc_type->size *= 0.8f; 
			break;
		case TROLL: 
			npc_type->race = ALLIGATOR; 
			npc_type->size *= 2.5f; 
			break;
		case OGRE: 
			npc_type->race = BEAR; 
			npc_type->texture = 3; 
			npc_type->gender = 2; 
			break;
		case BARBARIAN: 
			npc_type->race = WOLF; 
			npc_type->texture = 2;
			break;
		case IKSAR: 
			npc_type->race = WOLF; 
			npc_type->texture = 0; 
			npc_type->gender = 1; 
			npc_type->size *= 2.0f;
			npc_type->luclinface = 0;
			break;
		default: 
			npc_type->race = WOLF; 
			npc_type->texture = 0;
		}
	}

	// handle monster summoning pet appearance
	if(record.monsterflag) {
		char errbuf[MYSQL_ERRMSG_SIZE];
		char* query = 0;
		MYSQL_RES *result = NULL;
		MYSQL_ROW row = NULL;
		uint32 monsterid;
		
		// get a random npc id from the spawngroups assigned to this zone
		if (database.RunQuery(query,	MakeAnyLenString(&query,
			"SELECT npcID FROM (spawnentry INNER JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID) "
			"INNER JOIN npc_types ON npc_types.id = spawnentry.npcID "
			"WHERE spawn2.zone = '%s' AND npc_types.bodytype NOT IN (11, 33, 66, 67) "
			"AND npc_types.race NOT IN (0,1,2,3,4,5,6,7,8,9,10,11,12,44,55,67,71,72,73,77,78,81,90,92,93,94,106,112,114,127,128,130,139,141,183,236,237,238,239,254,266,330,378,379,380,381,382,383,404,522) "
			"ORDER BY RAND() LIMIT 1",	zone->GetShortName()), errbuf, &result))
		{
			row = mysql_fetch_row(result);
			if (row) 
				monsterid = atoi(row[0]);
			else 
				monsterid = 567;	// since we don't have any monsters, just make it look like an earth pet for now
		}
		else {	// if the database query failed
			LogFile->write(EQEMuLog::Error, "Error querying database for monster summoning pet in zone %s (%s)", zone->GetShortName(), errbuf);
			monsterid = 567;
		}
		
		// give the summoned pet the attributes of the monster we found
		const NPCType* monster = database.GetNPCType(monsterid);
		if(monster) {
			npc_type->race = monster->race;
			npc_type->size = monster->size;
			npc_type->texture = monster->texture;
			npc_type->gender = monster->gender;
		}
		else {
			LogFile->write(EQEMuLog::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid);
		}

		safe_delete_array(query);
	}

	//this takes ownership of the npc_type data
	Pet *npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower);

	// Now that we have an actual object to interact with, load
	// the base items for the pet. These are always loaded
	// so that a rank 1 suspend minion does not kill things
	// like the special back items some focused pets may receive.
	int32 petinv[MAX_WORN_INVENTORY];
	memset(petinv, 0, sizeof(petinv));
	const Item_Struct *item = 0;

	if (database.GetBasePetItems(record.equipmentset, petinv)) {
		for (int i=0; i<MAX_WORN_INVENTORY; i++)
			if (petinv[i]) {
				item = database.GetItem(petinv[i]);
				npc->AddLootDrop(item, &npc->itemlist, 0, true, true);
			}
	}


	entity_list.AddNPC(npc, true, true);
	SetPetID(npc->GetID());
	// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet
}
示例#21
0
// Split from the basic MakePet to allow backward compatiblity with existing code while also
// making it possible for petpower to be retained without the focus item having to
// stay equipped when the character zones. petpower of -1 means that the currently equipped petfocus
// of a client is searched for and used instead.
void Mob::MakePoweredPet(uint16 spell_id, const char* pettype, int16 petpower,
		const char *petname, float in_size) {
	// Sanity and early out checking first.
	if(HasPet() || pettype == nullptr)
		return;

	int16 act_power = 0; // The actual pet power we'll use.
	if (petpower == -1) {
		if (this->IsClient()) {
			act_power = CastToClient()->GetFocusEffect(focusPetPower, spell_id);//Client only
			act_power = CastToClient()->mod_pet_power(act_power, spell_id);
		}
#ifdef BOTS
		else if (this->IsBot())
			act_power = CastToBot()->GetBotFocusEffect(Bot::BotfocusPetPower, spell_id);
#endif
	}
	else if (petpower > 0)
		act_power = petpower;

	// optional rule: classic style variance in pets. Achieve this by
	// adding a random 0-4 to pet power, since it only comes in increments
	// of five from focus effects.

	//lookup our pets table record for this type
	PetRecord record;
	if(!database.GetPoweredPetEntry(pettype, act_power, &record)) {
		Message(13, "Unable to find data for pet %s", pettype);
		Log.Out(Logs::General, Logs::Error, "Unable to find data for pet %s, check pets table.", pettype);
		return;
	}

	//find the NPC data for the specified NPC type
	const NPCType *base = database.LoadNPCTypesData(record.npc_type);
	if(base == nullptr) {
		Message(13, "Unable to load NPC data for pet %s", pettype);
		Log.Out(Logs::General, Logs::Error, "Unable to load NPC data for pet %s (NPC ID %d), check pets and npc_types tables.", pettype, record.npc_type);
		return;
	}

	//we copy the npc_type data because we need to edit it a bit
	auto npc_type = new NPCType;
	memcpy(npc_type, base, sizeof(NPCType));

	// If pet power is set to -1 in the DB, use stat scaling
	if ((this->IsClient() 
#ifdef BOTS
		|| this->IsBot()
#endif
		) && record.petpower == -1)
	{
		float scale_power = (float)act_power / 100.0f;
		if(scale_power > 0)
		{
			npc_type->max_hp *= (1 + scale_power);
			npc_type->cur_hp = npc_type->max_hp;
			npc_type->AC *= (1 + scale_power);
			npc_type->level += 1 + ((int)act_power / 25) > npc_type->level + RuleR(Pets, PetPowerLevelCap) ? RuleR(Pets, PetPowerLevelCap) : 1 + ((int)act_power / 25); // gains an additional level for every 25 pet power
			npc_type->min_dmg = (npc_type->min_dmg * (1 + (scale_power / 2)));
			npc_type->max_dmg = (npc_type->max_dmg * (1 + (scale_power / 2)));
			npc_type->size = npc_type->size * (1 + (scale_power / 2)) > npc_type->size * 3 ? npc_type->size * 3 : npc_type-> size * (1 + (scale_power / 2));
		}
		record.petpower = act_power;
	}

	//Live AA - Elemental Durability
	int16 MaxHP = aabonuses.PetMaxHP + itembonuses.PetMaxHP + spellbonuses.PetMaxHP;

	if (MaxHP){
		npc_type->max_hp += (npc_type->max_hp*MaxHP)/100;
		npc_type->cur_hp = npc_type->max_hp;
	}

	//TODO: think about regen (engaged vs. not engaged)

	// Pet naming:
	// 0 - `s pet
	// 1 - `s familiar
	// 2 - `s Warder
	// 3 - Random name if client, `s pet for others
	// 4 - Keep DB name


	if (petname != nullptr) {
		// Name was provided, use it.
		strn0cpy(npc_type->name, petname, 64);
	} else if (record.petnaming == 0) {
		strcpy(npc_type->name, this->GetCleanName());
		npc_type->name[25] = '\0';
		strcat(npc_type->name, "`s_pet");
	} else if (record.petnaming == 1) {
		strcpy(npc_type->name, this->GetName());
		npc_type->name[19] = '\0';
		strcat(npc_type->name, "`s_familiar");
	} else if (record.petnaming == 2) {
		strcpy(npc_type->name, this->GetName());
		npc_type->name[21] = 0;
		strcat(npc_type->name, "`s_Warder");
	} else if (record.petnaming == 4) {
		// Keep the DB name
	} else if (record.petnaming == 3 && IsClient()) {
		strcpy(npc_type->name, GetRandPetName());
	} else {
		strcpy(npc_type->name, this->GetCleanName());
		npc_type->name[25] = '\0';
		strcat(npc_type->name, "`s_pet");
	}

	//handle beastlord pet appearance
	if(record.petnaming == 2)
	{
		switch(GetBaseRace())
		{
		case VAHSHIR:
			npc_type->race = TIGER;
			npc_type->size *= 0.8f;
			break;
		case TROLL:
			npc_type->race = ALLIGATOR;
			npc_type->size *= 2.5f;
			break;
		case OGRE:
			npc_type->race = BEAR;
			npc_type->texture = 3;
			npc_type->gender = 2;
			break;
		case BARBARIAN:
			npc_type->race = WOLF;
			npc_type->texture = 2;
			break;
		case IKSAR:
			npc_type->race = WOLF;
			npc_type->texture = 0;
			npc_type->gender = 1;
			npc_type->size *= 2.0f;
			npc_type->luclinface = 0;
			break;
		default:
			npc_type->race = WOLF;
			npc_type->texture = 0;
		}
	}

	// handle monster summoning pet appearance
	if(record.monsterflag) {

		uint32 monsterid = 0;

		// get a random npc id from the spawngroups assigned to this zone
		auto query = StringFormat("SELECT npcID "
									"FROM (spawnentry INNER JOIN spawn2 ON spawn2.spawngroupID = spawnentry.spawngroupID) "
									"INNER JOIN npc_types ON npc_types.id = spawnentry.npcID "
									"WHERE spawn2.zone = '%s' AND npc_types.bodytype NOT IN (11, 33, 66, 67) "
									"AND npc_types.race NOT IN (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 44, "
									"55, 67, 71, 72, 73, 77, 78, 81, 90, 92, 93, 94, 106, 112, 114, 127, 128, "
									"130, 139, 141, 183, 236, 237, 238, 239, 254, 266, 329, 330, 378, 379, "
									"380, 381, 382, 383, 404, 522) "
									"ORDER BY RAND() LIMIT 1", zone->GetShortName());
		auto results = database.QueryDatabase(query);
		if (!results.Success()) {
			safe_delete(npc_type);
			return;
		}

		if (results.RowCount() != 0) {
			auto row = results.begin();
			monsterid = atoi(row[0]);
		}

		// since we don't have any monsters, just make it look like an earth pet for now
		if (monsterid == 0)
			monsterid = 567;

		// give the summoned pet the attributes of the monster we found
		const NPCType* monster = database.LoadNPCTypesData(monsterid);
		if(monster) {
			npc_type->race = monster->race;
			npc_type->size = monster->size;
			npc_type->texture = monster->texture;
			npc_type->gender = monster->gender;
			npc_type->luclinface = monster->luclinface;
			npc_type->helmtexture = monster->helmtexture;
			npc_type->herosforgemodel = monster->herosforgemodel;
		} else
			Log.Out(Logs::General, Logs::Error, "Error loading NPC data for monster summoning pet (NPC ID %d)", monsterid);

	}

	//this takes ownership of the npc_type data
	auto npc = new Pet(npc_type, this, (PetType)record.petcontrol, spell_id, record.petpower);

	// Now that we have an actual object to interact with, load
	// the base items for the pet. These are always loaded
	// so that a rank 1 suspend minion does not kill things
	// like the special back items some focused pets may receive.
	uint32 petinv[EQEmu::legacy::EQUIPMENT_SIZE];
	memset(petinv, 0, sizeof(petinv));
	const EQEmu::ItemData *item = 0;

	if (database.GetBasePetItems(record.equipmentset, petinv)) {
		for (int i = 0; i < EQEmu::legacy::EQUIPMENT_SIZE; i++)
			if (petinv[i]) {
				item = database.GetItem(petinv[i]);
				npc->AddLootDrop(item, &npc->itemlist, 0, 1, 127, true, true);
			}
	}

	npc->UpdateEquipmentLight();

	// finally, override size if one was provided
	if (in_size > 0.0f)
		npc->size = in_size;

	entity_list.AddNPC(npc, true, true);
	SetPetID(npc->GetID());
	// We need to handle PetType 5 (petHatelist), add the current target to the hatelist of the pet


	if (record.petcontrol == petTargetLock)
	{
		Mob* target = GetTarget();

		if (target){
			npc->AddToHateList(target, 1);
			npc->SetPetTargetLockID(target->GetID());
			npc->SetSpecialAbility(IMMUNE_AGGRO, 1);
		}
		else
			npc->Kill(); //On live casts spell 892 Unsummon (Kayen - Too limiting to use that for emu since pet can have more than 20k HP)
	}
}
示例#22
0
bool Client::UseDiscipline(uint32 spell_id, uint32 target) {
    // Dont let client waste a reuse timer if they can't use the disc
    if (IsStunned() || IsFeared() || IsMezzed() || IsAmnesiad() || IsPet())
    {
        return(false);
    }

    //make sure we have the spell...
    int r;
    for(r = 0; r < MAX_PP_DISCIPLINES; r++) {
        if(m_pp.disciplines.values[r] == spell_id)
            break;
    }
    if(r == MAX_PP_DISCIPLINES)
        return(false);	//not found.

    //Check the disc timer
    pTimerType DiscTimer = pTimerDisciplineReuseStart + spells[spell_id].EndurTimerIndex;
    if(!p_timers.Expired(&database, DiscTimer)) {
        /*char val1[20]={0};*/	//unused
        /*char val2[20]={0};*/	//unused
        uint32 remain = p_timers.GetRemainingTime(DiscTimer);
        //Message_StringID(0, DISCIPLINE_CANUSEIN, ConvertArray((remain)/60,val1), ConvertArray(remain%60,val2));
        Message(0, "You can use this discipline in %d minutes %d seconds.", ((remain)/60), (remain%60));
        return(false);
    }

    //make sure we can use it..
    if(!IsValidSpell(spell_id)) {
        Message(13, "This tome contains invalid knowledge.");
        return(false);
    }

    //can we use the spell?
    const SPDat_Spell_Struct &spell = spells[spell_id];
    uint8 level_to_use = spell.classes[GetClass() - 1];
    if(level_to_use == 255) {
        Message(13, "Your class cannot learn from this tome.");
        //should summon them a new one...
        return(false);
    }

    if(level_to_use > GetLevel()) {
        Message_StringID(13, DISC_LEVEL_USE_ERROR);
        //should summon them a new one...
        return(false);
    }

    if(GetEndurance() > spell.EndurCost) {
        SetEndurance(GetEndurance() - spell.EndurCost);
    } else {
        Message(11, "You are too fatigued to use this skill right now.");
        return(false);
    }

    if(spell.recast_time > 0)
    {
        uint32 reduced_recast = spell.recast_time / 1000;
        reduced_recast -= CastToClient()->GetFocusEffect(focusReduceRecastTime, spell_id);
        if(reduced_recast < 0)
            reduced_recast = 0;

        CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT, -1, -1, 0, -1, (uint32)DiscTimer, reduced_recast);
        if(spells[spell_id].EndurTimerIndex < MAX_DISCIPLINE_TIMERS)
        {
            EQApplicationPacket *outapp = new EQApplicationPacket(OP_DisciplineTimer, sizeof(DisciplineTimer_Struct));
            DisciplineTimer_Struct *dts = (DisciplineTimer_Struct *)outapp->pBuffer;
            dts->TimerID = spells[spell_id].EndurTimerIndex;
            dts->Duration = reduced_recast;
            QueuePacket(outapp);
            safe_delete(outapp);
        }
    }
    else
    {
        CastSpell(spell_id, target, DISCIPLINE_SPELL_SLOT);
    }
    return(true);
}
示例#23
0
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);
	}
}