2012-06-14 09:06:06 -04:00
# include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
2012-09-23 16:53:08 -04:00
# include "PassiveMonster.h"
2013-08-16 04:48:19 -04:00
# include "../World.h"
2014-01-29 13:15:26 -05:00
# include "../Entities/Player.h"
2015-11-29 13:13:31 -05:00
# include "BoundingBox.h"
2017-07-01 08:36:43 -04:00
# include "../Items/ItemSpawnEgg.h"
2012-06-14 09:06:06 -04:00
2014-09-17 13:40:10 -04: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 13:13:31 -05: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 09:06:06 -04:00
{
m_EMPersonality = PASSIVE ;
}
2012-12-21 06:04:08 -05:00
2014-04-25 18:32:30 -04:00
bool cPassiveMonster : : DoTakeDamage ( TakeDamageInfo & a_TDI )
2012-06-14 09:06:06 -04:00
{
2014-04-25 18:32:30 -04:00
if ( ! super : : DoTakeDamage ( a_TDI ) )
{
return false ;
}
2014-10-20 16:55:07 -04:00
if ( ( a_TDI . Attacker ! = this ) & & ( a_TDI . Attacker ! = nullptr ) )
2012-12-21 06:04:08 -05:00
{
2012-06-14 09:06:06 -04:00
m_EMState = ESCAPING ;
2012-12-21 06:04:08 -05:00
}
2014-04-25 18:32:30 -04:00
return true ;
2012-06-14 09:06:06 -04:00
}
2012-12-21 06:04:08 -05:00
2015-11-29 13:13:31 -05: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 ) ;
}
2016-02-07 12:07:14 -05:00
void cPassiveMonster : : Destroyed ( )
{
if ( m_LovePartner ! = nullptr )
{
m_LovePartner - > ResetLoveMode ( ) ;
}
2016-03-28 11:35:54 -04:00
super : : Destroyed ( ) ;
2016-02-07 12:07:14 -05:00
}
2015-01-11 16:12:26 -05:00
void cPassiveMonster : : Tick ( std : : chrono : : milliseconds a_Dt , cChunk & a_Chunk )
2012-06-14 09:06:06 -04:00
{
2013-04-13 17:02:10 -04:00
super : : Tick ( a_Dt , a_Chunk ) ;
2016-09-03 07:31:27 -04:00
if ( ! IsTicking ( ) )
{
// The base class tick destroyed us
return ;
}
2012-06-14 09:06:06 -04:00
2014-01-24 14:57:32 -05:00
if ( m_EMState = = ESCAPING )
2012-06-14 09:06:06 -04:00
{
2014-01-24 14:57:32 -05:00
CheckEventLostPlayer ( ) ;
2012-06-14 09:06:06 -04:00
}
2015-11-30 04:07:55 -05:00
// if we have a partner, mate
2015-11-29 13:13:31 -05:00
if ( m_LovePartner ! = nullptr )
2014-01-29 13:15:26 -05:00
{
2015-11-30 04:07:55 -05:00
2015-11-29 13:13:31 -05:00
if ( m_MatingTimer > 0 )
2014-01-29 13:15:26 -05:00
{
2015-11-30 04:07:55 -05:00
// If we should still mate, keep bumping into them until baby is made
2015-11-29 13:13:31 -05:00
Vector3d Pos = m_LovePartner - > GetPosition ( ) ;
MoveToPosition ( Pos ) ;
}
else
{
2015-11-30 04:07:55 -05:00
// Mating finished. Spawn baby
2015-11-29 13:13:31 -05:00
Vector3f Pos = ( GetPosition ( ) + m_LovePartner - > GetPosition ( ) ) * 0.5 ;
2015-12-12 14:55:58 -05:00
UInt32 BabyID = m_World - > SpawnMob ( Pos . x , Pos . y , Pos . z , GetMobType ( ) , true ) ;
2017-09-02 03:45:06 -04:00
class cBabyInheritCallback :
public cEntityCallback
{
public :
cPassiveMonster * Baby ;
cBabyInheritCallback ( ) : Baby ( nullptr ) { }
virtual bool Item ( cEntity * a_Entity ) override
2015-12-12 14:55:58 -05:00
{
2017-09-02 03:45:06 -04:00
Baby = static_cast < cPassiveMonster * > ( a_Entity ) ;
2015-12-12 14:55:58 -05:00
return true ;
}
2017-09-02 03:45:06 -04:00
} Callback ;
2015-12-12 14:55:58 -05:00
2017-09-02 03:45:06 -04:00
m_World - > DoWithEntityByID ( BabyID , Callback ) ;
if ( Callback . Baby ! = nullptr )
2015-12-12 14:55:58 -05:00
{
2017-09-02 03:45:06 -04:00
Callback . Baby - > InheritFromParents ( this , m_LovePartner ) ;
2015-12-12 14:55:58 -05:00
}
2015-11-29 13:13:31 -05:00
2017-06-13 15:35:30 -04:00
m_World - > SpawnExperienceOrb ( Pos . x , Pos . y , Pos . z , GetRandomProvider ( ) . RandInt ( 1 , 6 ) ) ;
2015-11-29 13:13:31 -05:00
m_LovePartner - > ResetLoveMode ( ) ;
ResetLoveMode ( ) ;
2014-01-29 13:15:26 -05:00
}
}
2015-11-29 13:13:31 -05:00
else
{
2015-11-30 04:07:55 -05:00
// We have no partner, so we just chase the player if they have our breeding item
2015-11-29 13:13:31 -05: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 04:07:55 -05:00
// If we are in love mode but we have no partner, search for a partner neabry
2015-11-29 13:13:31 -05:00
if ( m_LoveTimer > 0 )
{
if ( m_LovePartner = = nullptr )
{
2017-09-02 03:45:06 -04:00
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-29 13:13:31 -05:00
{
2016-02-04 07:09:06 -05:00
// If the entity is not a monster, don't breed with it
// Also, do not self-breed
2017-09-02 03:45:06 -04:00
if ( ( a_Entity - > GetEntityType ( ) ! = etMonster ) | | ( a_Entity = = m_Me ) )
2015-11-29 13:13:31 -05:00
{
2016-02-04 07:09:06 -05:00
return false ;
2015-11-29 13:13:31 -05:00
}
2016-02-04 07:09:06 -05:00
2017-09-02 03:45:06 -04:00
cPassiveMonster * Me = static_cast < cPassiveMonster * > ( m_Me ) ;
cPassiveMonster * PotentialPartner = static_cast < cPassiveMonster * > ( a_Entity ) ;
2016-02-04 07:09:06 -05:00
// If the potential partner is not of the same species, don't breed with it
2017-09-02 03:45:06 -04:00
if ( PotentialPartner - > GetMobType ( ) ! = Me - > GetMobType ( ) )
2016-02-04 07:09:06 -05:00
{
return false ;
}
// If the potential partner is not in love
// Or they already have a mate, do not breed with them
2017-09-02 03:45:06 -04:00
if ( ( ! PotentialPartner - > IsInLove ( ) ) | | ( PotentialPartner - > GetPartner ( ) ! = nullptr ) )
2016-02-04 07:09:06 -05:00
{
return false ;
}
// All conditions met, let's breed!
2017-09-02 03:45:06 -04:00
PotentialPartner - > EngageLoveMode ( Me ) ;
Me - > EngageLoveMode ( PotentialPartner ) ;
2016-02-04 07:09:06 -05:00
return true ;
2015-11-29 13:13:31 -05:00
}
2017-09-02 03:45:06 -04:00
} Callback ( this ) ;
m_World - > ForEachEntityInBox ( cBoundingBox ( GetPosition ( ) , 8 , 8 , - 4 ) , Callback ) ;
2015-11-29 13:13:31 -05:00
}
m_LoveTimer - - ;
}
if ( m_MatingTimer > 0 )
{
m_MatingTimer - - ;
}
if ( m_LoveCooldown > 0 )
{
m_LoveCooldown - - ;
}
2012-12-21 06:04:08 -05:00
}
2013-09-07 14:02:50 -04:00
2012-12-21 06:04:08 -05:00
2015-11-29 13:13:31 -05:00
void cPassiveMonster : : OnRightClicked ( cPlayer & a_Player )
{
super : : OnRightClicked ( a_Player ) ;
2017-07-01 08:36:43 -04:00
const cItem & EquippedItem = a_Player . GetEquippedItem ( ) ;
2015-11-30 04:07:55 -05:00
// If a player holding breeding items right-clicked me, go into love mode
2015-11-29 13:13:31 -05:00
if ( ( m_LoveCooldown = = 0 ) & & ! IsInLove ( ) & & ! IsBaby ( ) )
{
cItems Items ;
GetBreedingItems ( Items ) ;
2017-07-01 08:36:43 -04:00
if ( Items . ContainsType ( EquippedItem . m_ItemType ) )
2015-11-29 13:13:31 -05:00
{
if ( ! a_Player . IsGameModeCreative ( ) )
{
a_Player . GetInventory ( ) . RemoveOneEquippedItem ( ) ;
}
m_LoveTimer = 20 * 30 ; // half a minute
m_World - > BroadcastEntityStatus ( * this , esMobInLove ) ;
}
}
2017-07-01 08:36:43 -04:00
// If a player holding my spawn egg right-clicked me, spawn a new baby
if ( EquippedItem . m_ItemType = = E_ITEM_SPAWN_EGG )
{
eMonsterType MonsterType = cItemSpawnEggHandler : : ItemDamageToMonsterType ( EquippedItem . m_ItemDamage ) ;
if (
( MonsterType = = m_MobType ) & &
2017-07-12 06:42:02 -04:00
( m_World - > SpawnMob ( GetPosX ( ) , GetPosY ( ) , GetPosZ ( ) , m_MobType , true ) ! = cEntity : : INVALID_ID ) // Spawning succeeded
2017-07-01 08:36:43 -04:00
)
{
if ( ! a_Player . IsGameModeCreative ( ) )
{
// The mob was spawned, "use" the item:
a_Player . GetInventory ( ) . RemoveOneEquippedItem ( ) ;
}
}
}
2015-11-29 13:13:31 -05:00
}