summaryrefslogblamecommitdiffstats
path: root/src/Mobs/PassiveMonster.cpp
blob: e39f6e23d42dfc2d01da6aaadb59841bd88e7246 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                                                                                              
                           
                     
                               
                        



 
                                                                                                                                                                                    




                                                                                     



                                  
 


 
                                                          
 



                                        
                                                                    
         
                                     
         
                    

 



 
























                                                                                                                                                               
                                                                            
 
                                   
 
                                  
         
                                       
         
                                                                       
         
                                        
         
                                     
         

                                                                          
                 













                                                                                                

                 































































                                                                                                                                    



 
 
 























                                                                                

#include "Globals.h"  // NOTE: MSVC stupidness requires this to be the same across all modules

#include "PassiveMonster.h"
#include "../World.h"
#include "../Entities/Player.h"
#include "BoundingBox.h"




cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
	super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height),
	m_LovePartner(nullptr),
	m_LoveTimer(0),
	m_LoveCooldown(0),
	m_MatingTimer(0)
{
	m_EMPersonality = PASSIVE;
}





bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
{
	if (!super::DoTakeDamage(a_TDI))
	{
		return false;
	}
	if ((a_TDI.Attacker != this) && (a_TDI.Attacker != nullptr))
	{
		m_EMState = ESCAPING;
	}
	return true;
}





void cPassiveMonster::EngageLoveMode(cPassiveMonster * a_Partner)
{
	m_LovePartner = a_Partner;
	m_MatingTimer = 50;  // about 3 seconds of mating
}





void cPassiveMonster::ResetLoveMode()
{
	m_LovePartner = nullptr;
	m_LoveTimer = 0;
	m_MatingTimer = 0;
	m_LoveCooldown = 20 * 60 * 5;  // 5 minutes

	// when an animal is in love mode, the client only stops sending the hearts if we let them know it's in cooldown, which is done with the "age" metadata
	m_World->BroadcastEntityMetadata(*this);
}





void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
	super::Tick(a_Dt, a_Chunk);

	if (m_EMState == ESCAPING)
	{
		CheckEventLostPlayer();
	}
	if ((m_LovePartner != nullptr) && m_LovePartner->IsDestroyed())
	{
		m_LovePartner = nullptr;
	}
	if (m_LovePartner != nullptr)
	{
		// if we have a partner, bump into them until baby is made
		if (m_MatingTimer > 0)
		{
			Vector3d Pos = m_LovePartner->GetPosition();
			MoveToPosition(Pos);
		}
		else
		{
			// spawn baby
			Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5;
			m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true);

			cFastRandom Random;
			m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, 1 + Random.NextInt(6));

			m_LovePartner->ResetLoveMode();
			ResetLoveMode();
		}
	}
	else
	{
		cItems FollowedItems;
		GetFollowedItems(FollowedItems);
		if (FollowedItems.Size() > 0)
		{
			cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), static_cast<float>(m_SightDistance));
			if (a_Closest_Player != nullptr)
			{
				cItem EquippedItem = a_Closest_Player->GetEquippedItem();
				if (FollowedItems.ContainsType(EquippedItem))
				{
					Vector3d PlayerPos = a_Closest_Player->GetPosition();
					MoveToPosition(PlayerPos);
				}
			}
		}
	}

	if (m_LoveTimer > 0)
	{
		if (m_LovePartner == nullptr)
		{
			class LookForLover : public cEntityCallback
			{
			public:
				cEntity * m_Me;

				LookForLover(cEntity * a_Me) :
					m_Me(a_Me)
				{
				}

				virtual bool Item(cEntity * a_Entity) override
				{
					// if we're the same species as someone around and they dont have a partner, swipe right
					if ((a_Entity->GetEntityType() == m_Me->GetEntityType()) && (a_Entity != m_Me))
					{
						cPassiveMonster * Me = static_cast<cPassiveMonster*>(m_Me);
						cPassiveMonster * Partner = static_cast<cPassiveMonster*>(a_Entity);
						if (Partner->IsInLove() && (Partner->GetPartner() == nullptr))
						{
							Partner->EngageLoveMode(Me);
							Me->EngageLoveMode(Partner);
							return true;
						}
					}
					return false;
				}
			} Callback(this);

			m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8), Callback);
		}

		m_LoveTimer--;
	}
	if (m_MatingTimer > 0)
	{
		m_MatingTimer--;
	}
	if (m_LoveCooldown > 0)
	{
		m_LoveCooldown--;
	}
}





void cPassiveMonster::OnRightClicked(cPlayer & a_Player)
{
	super::OnRightClicked(a_Player);

	// if right clicked on the player with breeding items, go into lovemode
	if ((m_LoveCooldown == 0) && !IsInLove() && !IsBaby())
	{
		short HeldItem = a_Player.GetEquippedItem().m_ItemType;
		cItems Items;
		GetBreedingItems(Items);
		if (Items.ContainsType(HeldItem))
		{
			if (!a_Player.IsGameModeCreative())
			{
				a_Player.GetInventory().RemoveOneEquippedItem();
			}
			m_LoveTimer = 20 * 30;  // half a minute
			m_World->BroadcastEntityStatus(*this, esMobInLove);
		}
	}
}