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"
2018-08-28 20:51:25 -04:00
# include "../BoundingBox.h"
2017-07-01 08:36:43 -04:00
# include "../Items/ItemSpawnEgg.h"
2012-06-14 09:06:06 -04:00
2020-03-22 11:50:34 -04:00
cPassiveMonster : : cPassiveMonster ( const AString & a_ConfigName , eMonsterType a_MobType , const AString & a_SoundHurt , const AString & a_SoundDeath , const AString & a_SoundAmbient , double a_Width , double a_Height ) :
2020-04-13 12:38:06 -04:00
Super ( a_ConfigName , a_MobType , a_SoundHurt , a_SoundDeath , a_SoundAmbient , a_Width , a_Height ) ,
2015-11-29 13:13:31 -05:00
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
{
2020-04-13 12:38:06 -04:00
if ( ! Super : : DoTakeDamage ( a_TDI ) )
2014-04-25 18:32:30 -04:00
{
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 ( ) ;
}
2020-04-13 12:38:06 -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
{
2020-04-13 12:38:06 -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-11 17:20:49 -04:00
cPassiveMonster * Baby = nullptr ;
m_World - > DoWithEntityByID ( BabyID , [ & ] ( cEntity & a_Entity )
2015-12-12 14:55:58 -05:00
{
2017-09-11 17:20:49 -04:00
Baby = static_cast < cPassiveMonster * > ( & a_Entity ) ;
2015-12-12 14:55:58 -05:00
return true ;
}
2017-09-11 17:20:49 -04:00
) ;
2015-12-12 14:55:58 -05:00
2017-09-11 17:20:49 -04:00
if ( Baby ! = nullptr )
2015-12-12 14:55:58 -05:00
{
2017-09-11 17:20:49 -04:00
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 )
{
2018-08-02 10:59:10 -04:00
m_World - > DoWithNearestPlayer ( GetPosition ( ) , static_cast < float > ( m_SightDistance ) , [ & ] ( cPlayer & a_Player ) - > bool
2015-11-29 13:13:31 -05:00
{
2020-05-14 18:15:35 -04:00
const cItem & EquippedItem = a_Player . GetEquippedItem ( ) ;
2015-11-29 13:13:31 -05:00
if ( FollowedItems . ContainsType ( EquippedItem ) )
{
2018-08-02 10:59:10 -04:00
Vector3d PlayerPos = a_Player . GetPosition ( ) ;
2015-11-29 13:13:31 -05:00
MoveToPosition ( PlayerPos ) ;
}
2018-08-02 10:59:10 -04:00
return true ;
} ) ;
2015-11-29 13:13:31 -05:00
}
}
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-11 17:20:49 -04:00
m_World - > ForEachEntityInBox ( cBoundingBox ( GetPosition ( ) , 8 , 8 ) , [ = ] ( cEntity & a_Entity )
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-11 17:20:49 -04:00
if ( ( a_Entity . GetEntityType ( ) ! = etMonster ) | | ( & a_Entity = = this ) )
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-11 17:20:49 -04:00
auto & Me = static_cast < cPassiveMonster & > ( * this ) ;
auto & 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-11 17:20:49 -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-11 17:20:49 -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-11 17:20:49 -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-11 17:20:49 -04:00
) ;
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 )
{
2020-04-13 12:38:06 -04:00
Super : : OnRightClicked ( a_Player ) ;
2015-11-29 13:13:31 -05:00
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
}