2012-06-14 13:06:06 +00:00
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 20:53:08 +00:00
#include "PassiveMonster.h"
2013-08-16 10:48:19 +02:00
#include "../World.h"
2014-01-29 19:15:26 +01:00
#include "../Entities/Player.h"
2015-11-29 19:13:31 +01:00
#include "BoundingBox.h"
2012-06-14 13:06:06 +00:00
2014-09-17 18:40:10 +01:00
cPassiveMonster :: cPassiveMonster ( const AString & a_ConfigName , eMonsterType a_MobType , const AString & a_SoundHurt , const AString & a_SoundDeath , double a_Width , double a_Height ) :
2015-11-29 19:13:31 +01:00
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 )
2012-06-14 13:06:06 +00:00
{
m_EMPersonality = PASSIVE ;
}
2012-12-21 11:04:08 +00:00
2014-04-26 00:32:30 +02:00
bool cPassiveMonster :: DoTakeDamage ( TakeDamageInfo & a_TDI )
2012-06-14 13:06:06 +00:00
{
2014-04-26 00:32:30 +02:00
if ( ! super :: DoTakeDamage ( a_TDI ))
{
return false ;
}
2014-10-20 21:55:07 +01:00
if (( a_TDI . Attacker != this ) && ( a_TDI . Attacker != nullptr ))
2012-12-21 11:04:08 +00:00
{
2012-06-14 13:06:06 +00:00
m_EMState = ESCAPING ;
2012-12-21 11:04:08 +00:00
}
2014-04-26 00:32:30 +02:00
return true ;
2012-06-14 13:06:06 +00:00
}
2012-12-21 11:04:08 +00:00
2015-11-29 19:13:31 +01:00
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 );
}
2015-01-11 21:12:26 +00:00
void cPassiveMonster :: Tick ( std :: chrono :: milliseconds a_Dt , cChunk & a_Chunk )
2012-06-14 13:06:06 +00:00
{
2013-04-13 21:02:10 +00:00
super :: Tick ( a_Dt , a_Chunk );
2012-06-14 13:06:06 +00:00
2014-01-24 19:57:32 +00:00
if ( m_EMState == ESCAPING )
2012-06-14 13:06:06 +00:00
{
2014-01-24 19:57:32 +00:00
CheckEventLostPlayer ();
2012-06-14 13:06:06 +00:00
}
2015-11-29 19:13:31 +01:00
if (( m_LovePartner != nullptr ) && m_LovePartner -> IsDestroyed ())
2014-01-29 19:15:26 +01:00
{
2015-11-29 19:13:31 +01:00
m_LovePartner = nullptr ;
2014-01-29 19:15:26 +01:00
}
2015-11-30 11:07:55 +02:00
// if we have a partner, mate
2015-11-29 19:13:31 +01:00
if ( m_LovePartner != nullptr )
2014-01-29 19:15:26 +01:00
{
2015-11-30 11:07:55 +02:00
2015-11-29 19:13:31 +01:00
if ( m_MatingTimer > 0 )
2014-01-29 19:15:26 +01:00
{
2015-11-30 11:07:55 +02:00
// If we should still mate, keep bumping into them until baby is made
2015-11-29 19:13:31 +01:00
Vector3d Pos = m_LovePartner -> GetPosition ();
MoveToPosition ( Pos );
}
else
{
2015-11-30 11:07:55 +02:00
// Mating finished. Spawn baby
2015-11-29 19:13:31 +01:00
Vector3f Pos = ( GetPosition () + m_LovePartner -> GetPosition ()) * 0.5 ;
2015-12-12 20:55:58 +01:00
UInt32 BabyID = m_World -> SpawnMob ( Pos . x , Pos . y , Pos . z , GetMobType (), true );
class cBabyInheritCallback :
public cEntityCallback
{
public :
cPassiveMonster * Baby ;
cBabyInheritCallback () : Baby ( nullptr ) { }
virtual bool Item ( cEntity * a_Entity ) override
{
Baby = static_cast < cPassiveMonster *> ( a_Entity );
return true ;
}
} Callback ;
m_World -> DoWithEntityByID ( BabyID , Callback );
if ( Callback . Baby != nullptr )
{
Callback . Baby -> InheritFromParents ( this , m_LovePartner );
}
2015-11-29 19:13:31 +01:00
cFastRandom Random ;
m_World -> SpawnExperienceOrb ( Pos . x , Pos . y , Pos . z , 1 + Random . NextInt ( 6 ));
m_LovePartner -> ResetLoveMode ();
ResetLoveMode ();
2014-01-29 19:15:26 +01:00
}
}
2015-11-29 19:13:31 +01:00
else
{
2015-11-30 11:07:55 +02:00
// We have no partner, so we just chase the player if they have our breeding item
2015-11-29 19:13:31 +01:00
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 );
}
}
}
}
2015-11-30 11:07:55 +02:00
// If we are in love mode but we have no partner, search for a partner neabry
2015-11-29 19:13:31 +01:00
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
{
2015-11-30 11:07:55 +02:00
// if we're the same species as someone around and they don't have a partner, start mating with them
2015-11-29 19:13:31 +01:00
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 -- ;
}
2012-12-21 11:04:08 +00:00
}
2013-09-07 20:02:50 +02:00
2012-12-21 11:04:08 +00:00
2015-11-29 19:13:31 +01:00
void cPassiveMonster :: OnRightClicked ( cPlayer & a_Player )
{
super :: OnRightClicked ( a_Player );
2015-11-30 11:07:55 +02:00
// If a player holding breeding items right-clicked me, go into love mode
2015-11-29 19:13:31 +01:00
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 );
}
}
}