Beispiel #1
0
void cOcelot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);
	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}

	if (!IsTame() && !IsBaby())
	{
		if (m_CheckPlayerTickCount == 23)
		{
			m_World->DoWithNearestPlayer(GetPosition(), 10, [&](cPlayer & a_Player) -> bool
			{
				cItems Items;
				GetBreedingItems(Items);
				if (Items.ContainsType(a_Player.GetEquippedItem().m_ItemType))
				{
					if (!IsBegging())
					{
						SetIsBegging(true);
						m_World->BroadcastEntityMetadata(*this);
					}

					MoveToPosition(a_Player.GetPosition());
				}
				else
				{
					if (IsBegging())
					{
						SetIsBegging(false);
						m_World->BroadcastEntityMetadata(*this);
					}
				}

				return true;
			}, true);
			m_CheckPlayerTickCount = 0;
		}
		else
		{
			m_CheckPlayerTickCount++;
		}
	}

	if (IsTame() && !IsSitting())
	{
		TickFollowPlayer();
	}
	else if (IsSitting())
	{
		StopMovingToPosition();
	}

	m_World->BroadcastEntityMetadata(*this);
}
Beispiel #2
0
int32 Client::CalcManaRegen()
{
	uint8 clevel = GetLevel();
	int32 regen = 0;
	//this should be changed so we dont med while camping, etc...
	if (IsSitting() || (GetHorseId() != 0))
	{
		BuffFadeBySitModifier();
		if(HasSkill(SkillMeditate)) {
			this->medding = true;
			regen = (((GetSkill(SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4;
			regen += spellbonuses.ManaRegen + itembonuses.ManaRegen;
			CheckIncreaseSkill(SkillMeditate, nullptr, -5);
		}
		else
			regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
	}
	else {
		this->medding = false;
		regen = 2 + spellbonuses.ManaRegen + itembonuses.ManaRegen;
	}

	//AAs
	regen += aabonuses.ManaRegen;

	return (regen * RuleI(Character, ManaRegenMultiplier) / 100);
}
Beispiel #3
0
void cWolf::TickFollowPlayer()
{
	class cCallback :
		public cPlayerListCallback
	{
		virtual bool Item(cPlayer * a_Player) override
		{
			OwnerPos = a_Player->GetPosition();
			return false;
		}
	public:
		Vector3f OwnerPos;
	} Callback;
	if (m_World->DoWithPlayer(m_OwnerName, Callback))
	{
		// The player is present in the world, follow them:
		double Distance = (Callback.OwnerPos - GetPosition()).Length();
		if (Distance < 3)
		{
			m_bMovingToDestination = false;
		}
		else if ((Distance > 30) && (!IsSitting()))
		{
			TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
		}
		else
		{
			m_Destination = Callback.OwnerPos;
		}
	}
}
Beispiel #4
0
void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
{
	if (!IsAngry())
	{
		cMonster::Tick(a_Dt, a_Chunk);
	}
	else
	{
		super::Tick(a_Dt, a_Chunk);
	}

	if (IsSitting())
	{
		m_bMovingToDestination = false;
	}

	cPlayer * a_Closest_Player = FindClosestPlayer();
	if (a_Closest_Player != NULL)
	{
		switch (a_Closest_Player->GetEquippedItem().m_ItemType)
		{
			case E_ITEM_BONE:
			case E_ITEM_RAW_BEEF:
			case E_ITEM_STEAK:
			case E_ITEM_RAW_CHICKEN:
			case E_ITEM_COOKED_CHICKEN:
			case E_ITEM_ROTTEN_FLESH:
			{
				if (!IsBegging())
				{
					SetIsBegging(true);
					m_World->BroadcastEntityMetadata(*this);
				}
				Vector3f a_NewDestination = a_Closest_Player->GetPosition();
				a_NewDestination.y = a_NewDestination.y + 1; // Look at the head of the player, not his feet.
				m_Destination = Vector3f(a_NewDestination);
				m_bMovingToDestination = false;
				break;
			}
			default:
			{
				if (IsBegging())
				{
					SetIsBegging(false);
					m_World->BroadcastEntityMetadata(*this);
				}
			}
		}
	}

	if (IsTame())
	{
		TickFollowPlayer();
	}
}
Beispiel #5
0
void cOcelot::OnRightClicked(cPlayer & a_Player)
{
	if (!IsTame())
	{
		if (
			IsBegging() &&
			((a_Player.GetPosition() - GetPosition()).Length() <= 3)
		)
		{
			cItems Items;
			GetBreedingItems(Items);
			if (Items.ContainsType(a_Player.GetEquippedItem().m_ItemType))
			{
				if (!a_Player.IsGameModeCreative())
				{
					a_Player.GetInventory().RemoveOneEquippedItem();
				}

				auto & Random = GetRandomProvider();

				if (Random.RandBool(1.0 / 3.0))
				{
					// Taming succeeded
					SetIsBegging(false);

					SetMaxHealth(20);
					SetIsTame(true);
					SetOwner(a_Player.GetName(), a_Player.GetUUID());
					SetCatType(static_cast<eCatType>(Random.RandInt<int>(1, 3)));
					m_World->BroadcastEntityStatus(*this, esWolfTamed);
					m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
				}
				else
				{
					// Taming failed
					m_World->BroadcastEntityStatus(*this, esWolfTaming);
					m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
				}
			}
		}
		else
		{
			super::OnRightClicked(a_Player);
		}
	}
	else if (a_Player.GetUUID() == m_OwnerUUID)
	{
		super::OnRightClicked(a_Player);
		SetIsSitting(!IsSitting());
	}
	m_World->BroadcastEntityMetadata(*this);
}
Beispiel #6
0
void cWolf::OnRightClicked(cPlayer & a_Player)
{
	if (!IsTame() && !IsAngry())
	{
		if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE)
		{
			if (!a_Player.IsGameModeCreative())
			{
				a_Player.GetInventory().RemoveOneEquippedItem();
			}

			if (m_World->GetTickRandomNumber(7) == 0)
			{
				SetMaxHealth(20);
				SetIsTame(true);
				SetOwner(a_Player.GetName());
				m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED);
			}
			else
			{
				m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING);
			}
		}
	}
	else if (IsTame())
	{
		if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
		{
			if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_DYE)
			{
				SetCollarColor(15 - a_Player.GetEquippedItem().m_ItemDamage);
				if (!a_Player.IsGameModeCreative())
				{
					a_Player.GetInventory().RemoveOneEquippedItem();
				}
			} 
			else if (IsSitting()) 
			{
				SetIsSitting(false);
			}
			else
			{
				SetIsSitting(true);
			}
		}
	}
	
	m_World->BroadcastEntityMetadata(*this);
}
Beispiel #7
0
int32 Client::CalcBaseManaRegen()
{
	uint8 clevel = GetLevel();
	int32 regen = 0;
	if (IsSitting() || (GetHorseId() != 0))
	{
		if(HasSkill(SkillMeditate))
			regen = (((GetSkill(SkillMeditate) / 10) + (clevel - (clevel / 4))) / 4) + 4;
		else
			regen = 2;
	}
	else {
		regen = 2;
	}
	return regen;
}
Beispiel #8
0
void cWolf::ReceiveNearbyFightInfo(const cUUID & a_PlayerID, cPawn * a_Opponent, bool a_IsPlayerInvolved)
{
	if (
		(a_Opponent == nullptr) || IsSitting() || (!IsTame()) ||
		(!a_Opponent->IsPawn()) || (a_PlayerID != m_OwnerUUID)
	)
	{
		return;
	}

	// If we already have a target
	if (GetTarget() != nullptr)
	{
		// If a wolf is asking for help and we already have a target, do nothing
		if (!a_IsPlayerInvolved)
		{
			return;
		}
		// If a player is asking for help and we already have a target,
		// there's a 50% chance of helping and a 50% chance of doing nothing
		// This helps spread a wolf pack's targets over several mobs
		else if (GetRandomProvider().RandBool())
		{
			return;
		}
	}

	if (a_Opponent->IsPlayer() && static_cast<cPlayer *>(a_Opponent)->GetUUID() == m_OwnerUUID)
	{
		return;  // Our owner has hurt himself, avoid attacking them.
	}

	if (a_Opponent->IsMob() && static_cast<cMonster *>(a_Opponent)->GetMobType() == mtWolf)
	{
		cWolf * Wolf = static_cast<cWolf *>(a_Opponent);
		if (Wolf->GetOwnerUUID() == GetOwnerUUID())
		{
			return;  // Our owner attacked one of their wolves. Abort attacking wolf.
		}
	}

	SetTarget(a_Opponent);


}
Beispiel #9
0
void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	if (!IsAngry())
	{
		cMonster::Tick(a_Dt, a_Chunk);
		if (m_NotificationCooldown > 0)
		{
			m_NotificationCooldown -= 1;
		}
	}
	else
	{
		super::Tick(a_Dt, a_Chunk);
	}

	if (!IsTicking())
	{
		// The base class tick destroyed us
		return;
	}

	if (GetTarget() == nullptr)
	{
		m_World->DoWithNearestPlayer(GetPosition(), static_cast<float>(m_SightDistance), [&](cPlayer & a_Player) -> bool
		{
			switch (a_Player.GetEquippedItem().m_ItemType)
			{
				case E_ITEM_BONE:
				case E_ITEM_RAW_BEEF:
				case E_ITEM_STEAK:
				case E_ITEM_RAW_CHICKEN:
				case E_ITEM_COOKED_CHICKEN:
				case E_ITEM_ROTTEN_FLESH:
				case E_ITEM_RAW_PORKCHOP:
				case E_ITEM_COOKED_PORKCHOP:
				{
					if (!IsBegging())
					{
						SetIsBegging(true);
						m_World->BroadcastEntityMetadata(*this);
					}

					m_FinalDestination = a_Player.GetPosition();  // So that we will look at a player holding food

					// Don't move to the player if the wolf is sitting.
					if (!IsSitting())
					{
						MoveToPosition(a_Player.GetPosition());
					}

					break;
				}
				default:
				{
					if (IsBegging())
					{
						SetIsBegging(false);
						m_World->BroadcastEntityMetadata(*this);
					}
				}
			}

			return true;
		});
	}
	else
	{
		if (IsSitting())
		{
			SetTarget(nullptr);
		}
		else
		{
			MoveToPosition(GetTarget()->GetPosition());
			if (TargetIsInRange())
			{
				Attack(a_Dt);
			}
		}
	}

	if (IsTame() && !IsSitting())
	{
		TickFollowPlayer();
	}
	else if (IsSitting())
	{
		StopMovingToPosition();
	}
}
Beispiel #10
0
void cWolf::OnRightClicked(cPlayer & a_Player)
{
	const cItem & EquippedItem = a_Player.GetEquippedItem();
	const int EquippedItemType = EquippedItem.m_ItemType;

	if (!IsTame() && !IsAngry())
	{
		// If the player is holding a bone, try to tame the wolf:
		if (EquippedItemType == E_ITEM_BONE)
		{
			if (!a_Player.IsGameModeCreative())
			{
				a_Player.GetInventory().RemoveOneEquippedItem();
			}

			if (GetRandomProvider().RandBool(0.125))
			{
				// Taming succeeded
				SetMaxHealth(20);
				SetIsTame(true);
				SetOwner(a_Player.GetName(), a_Player.GetUUID());
				m_World->BroadcastEntityStatus(*this, esWolfTamed);
				m_World->BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
			}
			else
			{
				// Taming failed
				m_World->BroadcastEntityStatus(*this, esWolfTaming);
				m_World->BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5);
			}
		}
	}
	else if (IsTame())
	{
		// Feed the wolf, restoring its health, or dye its collar:
		switch (EquippedItemType)
		{
			case E_ITEM_RAW_BEEF:
			case E_ITEM_STEAK:
			case E_ITEM_RAW_PORKCHOP:
			case E_ITEM_COOKED_PORKCHOP:
			case E_ITEM_RAW_CHICKEN:
			case E_ITEM_COOKED_CHICKEN:
			case E_ITEM_ROTTEN_FLESH:
			{
				if (m_Health < m_MaxHealth)
				{
					Heal(ItemHandler(EquippedItemType)->GetFoodInfo(&EquippedItem).FoodLevel);
					if (!a_Player.IsGameModeCreative())
					{
						a_Player.GetInventory().RemoveOneEquippedItem();
					}
				}
				break;
			}
			case E_ITEM_DYE:
			{
				if (a_Player.GetUUID() == m_OwnerUUID)  // Is the player the owner of the dog?
				{
					SetCollarColor(EquippedItem.m_ItemDamage);
					if (!a_Player.IsGameModeCreative())
					{
						a_Player.GetInventory().RemoveOneEquippedItem();
					}
				}
				break;
			}
			default:
			{
				if (a_Player.GetUUID() == m_OwnerUUID)  // Is the player the owner of the dog?
				{
					SetIsSitting(!IsSitting());
				}
			}
		}
	}

	m_World->BroadcastEntityMetadata(*this);
}
Beispiel #11
0
void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	if (!IsAngry())
	{
		cMonster::Tick(a_Dt, a_Chunk);
	}
	else
	{
		super::Tick(a_Dt, a_Chunk);
	}

	cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance));
	if (a_Closest_Player != nullptr)
	{
		switch (a_Closest_Player->GetEquippedItem().m_ItemType)
		{
			case E_ITEM_BONE:
			case E_ITEM_RAW_BEEF:
			case E_ITEM_STEAK:
			case E_ITEM_RAW_CHICKEN:
			case E_ITEM_COOKED_CHICKEN:
			case E_ITEM_ROTTEN_FLESH:
			case E_ITEM_RAW_PORKCHOP:
			case E_ITEM_COOKED_PORKCHOP:
			{
				if (!IsBegging())
				{
					SetIsBegging(true);
					m_World->BroadcastEntityMetadata(*this);
				}

				m_FinalDestination = a_Closest_Player->GetPosition();  // So that we will look at a player holding food

				// Don't move to the player if the wolf is sitting.
				if (!IsSitting())
				{
					MoveToPosition(a_Closest_Player->GetPosition());
				}

				break;
			}
			default:
			{
				if (IsBegging())
				{
					SetIsBegging(false);
					m_World->BroadcastEntityMetadata(*this);
				}
			}
		}
	}

	if (IsTame() && !IsSitting())
	{
		TickFollowPlayer();
	}
	else if (IsSitting())
	{
		StopMovingToPosition();
	}
}
Beispiel #12
0
int32 Client::LevelRegen()
{
	bool sitting = IsSitting();
	bool feigned = GetFeigned();
	int level = GetLevel();
	bool bonus = GetRaceBitmask(GetBaseRace()) & RuleI(Character, BaseHPRegenBonusRaces);
	uint8 multiplier1 = bonus ? 2 : 1;
	int32 hp = 0;

	//these calculations should match up with the info from Monkly Business, which was last updated ~05/2008: http://www.monkly-business.net/index.php?pageid=abilities
	if (level < 51) {
		if (sitting) {
			if (level < 20)
				hp += 2 * multiplier1;
			else if (level < 50)
				hp += 3 * multiplier1;
			else	//level == 50
				hp += 4 * multiplier1;
		}
		else	//feigned or standing
			hp += 1 * multiplier1;
	}
	//there may be an easier way to calculate this next part, but I don't know what it is
	else {	//level >= 51
		int32 tmp = 0;
		float multiplier2 = 1;
		if (level < 56) {
			tmp = 2;
			if (bonus)
				multiplier2 = 3;
		}
		else if (level < 60) {
			tmp = 3;
			if (bonus)
				multiplier2 = 3.34;
		}
		else if (level < 61) {
			tmp = 4;
			if (bonus)
				multiplier2 = 3;
		}
		else if (level < 63) {
			tmp = 5;
			if (bonus)
				multiplier2 = 2.8;
		}
		else if (level < 65) {
			tmp = 6;
			if (bonus)
				multiplier2 = 2.67;
		}
		else {	//level >= 65
			tmp = 7;
			if (bonus)
				multiplier2 = 2.58;
		}

		hp += int32(float(tmp) * multiplier2);

		if (sitting)
			hp += 3 * multiplier1;
		else if (feigned)
			hp += 1 * multiplier1;
	}

	return hp;
}
Beispiel #13
0
void Client::ActivateAA(aaID activate){
	if (activate < 0 || activate >= aaHighestID)
		return;
	if (IsStunned() || IsFeared() || IsMezzed() || IsSilenced() || IsPet() || IsSitting() || GetFeigned())
		return;

	int AATimerID = GetAATimerID(activate);

	SendAA_Struct* aa2 = nullptr;
	aaID aaid = activate;
	uint8 activate_val = GetAA(activate);
	//this wasn't taking into acct multi tiered act talents before...
	if (activate_val == 0){
		aa2 = zone->FindAA(activate);
		if (!aa2){
			int i;
			int a;
			for (i = 1; i<MAX_AA_ACTION_RANKS; i++){
				a = activate - i;
				if (a <= 0)
					break;

				aa2 = zone->FindAA(a);
				if (aa2 != nullptr)
					break;
			}
		}
		if (aa2){
			aaid = (aaID)aa2->id;
			activate_val = GetAA(aa2->id);
		}
	}

	if (activate_val == 0){
		return;
	}

	if (aa2)
	{
		if (aa2->account_time_required)
		{
			if ((Timer::GetTimeSeconds() + account_creation) < aa2->account_time_required)
			{
				return;
			}
		}
	}

	if (!p_timers.Expired(&database, AATimerID + pTimerAAStart))
	{
		uint32 aaremain = p_timers.GetRemainingTime(AATimerID + pTimerAAStart);
		uint32 aaremain_hr = aaremain / (60 * 60);
		uint32 aaremain_min = (aaremain / 60) % 60;
		uint32 aaremain_sec = aaremain % 60;

		if (aa2) {
			if (aaremain_hr >= 1)	//1 hour or more
				Message(CC_Red, "You can use the ability %s again in %u hour(s) %u minute(s) %u seconds",
				aa2->name, aaremain_hr, aaremain_min, aaremain_sec);
			else	//less than an hour
				Message(CC_Red, "You can use the ability %s again in %u minute(s) %u seconds",
				aa2->name, aaremain_min, aaremain_sec);
		}
		else {
			if (aaremain_hr >= 1)	//1 hour or more
				Message(CC_Red, "You can use this ability again in %u hour(s) %u minute(s) %u seconds",
				aaremain_hr, aaremain_min, aaremain_sec);
			else	//less than an hour
				Message(CC_Red, "You can use this ability again in %u minute(s) %u seconds",
				aaremain_min, aaremain_sec);
		}
		return;
	}

	if (activate_val > MAX_AA_ACTION_RANKS)
		activate_val = MAX_AA_ACTION_RANKS;
	activate_val--;		//to get array index.

	//get our current node, now that the indices are well bounded
	const AA_DBAction *caa = &AA_Actions[aaid][activate_val];

	if ((aaid == aaImprovedHarmTouch || aaid == aaLeechTouch) && !p_timers.Expired(&database, pTimerHarmTouch)){
		Message(CC_Red, "Ability recovery time not yet met.");
		return;
	}

	//everything should be configured out now

	uint16 target_id = 0;

	//figure out our target
	switch (caa->target) {
	case aaTargetUser:
	case aaTargetGroup:
		target_id = GetID();
		break;
	case aaTargetCurrent:
	case aaTargetCurrentGroup:
		if (GetTarget() == nullptr) {
			Message_StringID(MT_DefaultText, AA_NO_TARGET);	//You must first select a target for this ability!
			p_timers.Clear(&database, AATimerID + pTimerAAStart);
			return;
		}
		target_id = GetTarget()->GetID();
		break;
	case aaTargetPet:
		if (GetPet() == nullptr) {
			Message(0, "A pet is required for this skill.");
			return;
		}
		target_id = GetPetID();
		break;
	}

	//handle non-spell action
	if (caa->action != aaActionNone) {
		if (caa->mana_cost > 0) {
			if (GetMana() < caa->mana_cost) {
				Message_StringID(CC_Red, INSUFFICIENT_MANA);
				return;
			}
			SetMana(GetMana() - caa->mana_cost);
		}
		if (caa->reuse_time > 0)
		{
			uint32 timer_base = CalcAAReuseTimer(caa);
			if (activate == aaImprovedHarmTouch || activate == aaLeechTouch)
			{
				p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime);
			}
			p_timers.Start(AATimerID + pTimerAAStart, timer_base);
			SendAATimer(activate, static_cast<uint32>(time(nullptr)), static_cast<uint32>(time(nullptr)));
		}
		HandleAAAction(aaid);
	}

	//cast the spell, if we have one
	if (caa->spell_id > 0 && caa->spell_id < SPDAT_RECORDS) {

		if (caa->reuse_time > 0)
		{
			uint32 timer_base = CalcAAReuseTimer(caa);
			SendAATimer(activate, static_cast<uint32>(time(nullptr)), static_cast<uint32>(time(nullptr)));
			p_timers.Start(AATimerID + pTimerAAStart, timer_base);
			if (activate == aaImprovedHarmTouch || activate == aaLeechTouch)
			{
				p_timers.Start(pTimerHarmTouch, HarmTouchReuseTime);
			}
			// Bards can cast instant cast AAs while they are casting another song
			if (spells[caa->spell_id].cast_time == 0 && GetClass() == BARD && IsBardSong(casting_spell_id)) {
				if (!SpellFinished(caa->spell_id, entity_list.GetMob(target_id), 10, -1, -1, spells[caa->spell_id].ResistDiff, false)) {
					//Reset on failed cast
					SendAATimer(activate, 0, 0xFFFFFF);
					Message_StringID(CC_Yellow, ABILITY_FAILED);
					p_timers.Clear(&database, AATimerID + pTimerAAStart);
					return;
				}
			}
			else {
				if (!CastSpell(caa->spell_id, target_id, USE_ITEM_SPELL_SLOT, -1, -1, 0, -1, AATimerID + pTimerAAStart, timer_base, 1)) {
					//Reset on failed cast
					SendAATimer(activate, 0, 0xFFFFFF);
					Message_StringID(CC_Yellow, ABILITY_FAILED);
					p_timers.Clear(&database, AATimerID + pTimerAAStart);
					return;
				}
			}
		}
		else
		{
			if (!CastSpell(caa->spell_id, target_id))
				return;
		}
	}
}
Beispiel #14
0
int32 Client::CalcManaRegen(bool bCombat)
{
	int regen = 0;
	auto level = GetLevel();
	// so the new formulas break down with older skill caps where you don't have the skill until 4 or 8
	// so for servers that want to use the old skill progression they can set this rule so they
	// will get at least 1 for standing and 2 for sitting.
	bool old = RuleB(Character, OldMinMana);
	if (!IsStarved()) {
		// client does some base regen for shrouds here
		if (IsSitting() || CanMedOnHorse()) {
			// kind of weird to do it here w/e
			// client does some base medding regen for shrouds here
			if (GetClass() != BARD) {
				auto skill = GetSkill(EQEmu::skills::SkillMeditate);
				if (skill > 0) {
					regen++;
					if (skill > 1)
						regen++;
					if (skill >= 15)
						regen += skill / 15;
				}
			}
			if (old)
				regen = std::max(regen, 2);
		} else if (old) {
			regen = std::max(regen, 1);
		}
	}

	if (level > 61) {
		regen++;
		if (level > 63)
			regen++;
	}

	regen += aabonuses.ManaRegen;
	// add in + 1 bonus for SE_CompleteHeal, but we don't do anything for it yet?

	int item_bonus = itembonuses.ManaRegen; // this is capped already
	int heroic_bonus = 0;

	switch (GetCasterClass()) {
	case 'W':
		heroic_bonus = GetHeroicWIS();
		break;
	default:
		heroic_bonus = GetHeroicINT();
		break;
	}

	item_bonus += heroic_bonus / 25;
	regen += item_bonus;

	if (level <= 70 && regen > 65)
		regen = 65;

	regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f;

	if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
		auto max_mana = GetMaxMana();
		int fast_regen = 6 * (max_mana / zone->newzone_data.FastRegenMana);
		if (regen < fast_regen) // weird, but what the client is doing
			regen = fast_regen;
	}

	regen += spellbonuses.ManaRegen; // TODO: live does this in buff tick
	return (regen * RuleI(Character, ManaRegenMultiplier) / 100);
}
Beispiel #15
0
int32 Client::CalcHPRegen(bool bCombat)
{
	int item_regen = itembonuses.HPRegen; // worn spells and +regen, already capped
	item_regen += GetHeroicSTA() / 20;

	item_regen += aabonuses.HPRegen;

	int base = 0;
	auto base_data = database.GetBaseData(GetLevel(), GetClass());
	if (base_data)
		base = static_cast<int>(base_data->hp_regen);

	auto level = GetLevel();
	bool skip_innate = false;

	if (IsSitting()) {
		if (level >= 50) {
			base++;
			if (level >= 65)
				base++;
		}

		if ((Timer::GetCurrentTime() - tmSitting) > 60000) {
			if (!IsAffectedByBuffByGlobalGroup(GlobalGroup::Lich)) {
				auto tic_diff = std::min((Timer::GetCurrentTime() - tmSitting) / 60000, static_cast<uint32>(9));
				if (tic_diff != 1) { // starts at 2 mins
					int tic_bonus = tic_diff * 1.5 * base;
					if (m_pp.InnateSkills[InnateRegen] != InnateDisabled)
						tic_bonus = tic_bonus * 1.2;
					base = tic_bonus;
					skip_innate = true;
				} else if (m_pp.InnateSkills[InnateRegen] == InnateDisabled) { // no innate regen gets first tick
					int tic_bonus = base * 1.5;
					base = tic_bonus;
				}
			}
		}
	}

	if (!skip_innate && m_pp.InnateSkills[InnateRegen] != InnateDisabled) {
		if (level >= 50) {
			++base;
			if (level >= 55) {
				++base;
			}
		}
		base *= 2;
	}

	if (IsStarved())
		base = 0;

	base += GroupLeadershipAAHealthRegeneration();
	// some IsKnockedOut that sets to -1
	base = base * 100.0f * AreaHPRegen * 0.01f + 0.5f;
	// another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later

	if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
		auto max_hp = GetMaxHP();
		int fast_regen = 6 * (max_hp / zone->newzone_data.FastRegenHP);
		if (base < fast_regen) // weird, but what the client is doing
			base = fast_regen;
	}

	int regen = base + item_regen + spellbonuses.HPRegen; // TODO: client does this in buff tick
	return (regen * RuleI(Character, HPRegenMultiplier) / 100);
}
Beispiel #16
0
int32 Client::CalcEnduranceRegen(bool bCombat)
{
	int base = 0;
	if (!IsStarved()) {
		auto base_data = database.GetBaseData(GetLevel(), GetClass());
		if (base_data) {
			base = static_cast<int>(base_data->end_regen);
			if (!auto_attack && base > 0)
				base += base / 2;
		}
	}

	// so when we are mounted, our local client SpeedRun is always 0, so this is always false, but the packets we process it to our own shit :P
	bool is_running = runmode && animation != 0 && GetHorseId() == 0; // TODO: animation is really what MQ2 calls SpeedRun

	int weight_limit = GetSTR();
	auto level = GetLevel();
	if (GetClass() == MONK) {
		if (level > 99)
			weight_limit = 58;
		else if (level > 94)
			weight_limit = 57;
		else if (level > 89)
			weight_limit = 56;
		else if (level > 84)
			weight_limit = 55;
		else if (level > 79)
			weight_limit = 54;
		else if (level > 64)
			weight_limit = 53;
		else if (level > 63)
			weight_limit = 50;
		else if (level > 61)
			weight_limit = 47;
		else if (level > 59)
			weight_limit = 45;
		else if (level > 54)
			weight_limit = 40;
		else if (level > 50)
			weight_limit = 38;
		else if (level > 44)
			weight_limit = 36;
		else if (level > 29)
			weight_limit = 34;
		else if (level > 14)
			weight_limit = 32;
		else
			weight_limit = 30;
	}

	bool encumbered = (CalcCurrentWeight() / 10) >= weight_limit;

	if (is_running)
		base += level / -15;

	if (encumbered)
		base += level / -15;

	auto item_bonus = GetHeroicAGI() + GetHeroicDEX() + GetHeroicSTA() + GetHeroicSTR();
	item_bonus = item_bonus / 4 / 50;
	item_bonus += itembonuses.EnduranceRegen; // this is capped already
	base += item_bonus;

	base = base * AreaEndRegen + 0.5f;

	auto aa_regen = aabonuses.EnduranceRegen;

	int regen = base;
	if (!bCombat && CanFastRegen() && (IsSitting() || CanMedOnHorse())) {
		auto max_end = GetMaxEndurance();
		int fast_regen = 6 * (max_end / zone->newzone_data.FastRegenEndurance);
		if (aa_regen < fast_regen) // weird, but what the client is doing
			aa_regen = fast_regen;
	}

	regen += aa_regen;
	regen += spellbonuses.EnduranceRegen; // TODO: client does this in buff tick

	return (regen * RuleI(Character, EnduranceRegenMultiplier) / 100);
}