summaryrefslogtreecommitdiffstats
path: root/src/Mobs
diff options
context:
space:
mode:
authorLogicParrot <LogicParrot@users.noreply.github.com>2017-09-01 21:12:44 +0200
committerLogicParrot <LogicParrot@users.noreply.github.com>2017-09-01 21:12:44 +0200
commit6e3e7552e67dfc0254c3e99bcd32fea02f10d062 (patch)
tree84bfd40d2c2693cab44a47d4902aa601d8a715e6 /src/Mobs
parentd (diff)
parentSetSwimState now takes into account head height (diff)
downloadcuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar.gz
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar.bz2
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar.lz
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar.xz
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.tar.zst
cuberite-6e3e7552e67dfc0254c3e99bcd32fea02f10d062.zip
Diffstat (limited to 'src/Mobs')
-rw-r--r--src/Mobs/Creeper.cpp15
-rw-r--r--src/Mobs/Enderman.cpp17
-rw-r--r--src/Mobs/Monster.cpp15
-rw-r--r--src/Mobs/Ocelot.cpp61
-rw-r--r--src/Mobs/PassiveMonster.cpp246
-rw-r--r--src/Mobs/Squid.h1
-rw-r--r--src/Mobs/Wither.cpp19
-rw-r--r--src/Mobs/Wolf.cpp43
8 files changed, 326 insertions, 91 deletions
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index 8de236863..c05076a1a 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -85,21 +85,16 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
a_Killer->IsProjectile() &&
((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID))
{
- class cProjectileCreatorCallback : public cEntityCallback
- {
- public:
- cProjectileCreatorCallback(void) {}
-
- virtual bool Item(cEntity * a_Entity) override
+ auto ProjectileCreatorCallback = [](cEntity & a_Entity)
{
- if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton))
+ if (a_Entity.IsMob() && ((static_cast<cMonster &>(a_Entity)).GetMobType() == mtSkeleton))
{
return true;
}
return false;
- }
- } PCC;
- if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC))
+ };
+
+ if (GetWorld()->DoWithEntityByID(static_cast<cProjectileEntity *>(a_Killer)->GetCreatorUniqueID(), ProjectileCreatorCallback))
{
AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC));
}
diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp
index 72301b21a..65b771406 100644
--- a/src/Mobs/Enderman.cpp
+++ b/src/Mobs/Enderman.cpp
@@ -10,8 +10,7 @@
////////////////////////////////////////////////////////////////////////////////
// cPlayerLookCheck
-class cPlayerLookCheck :
- public cPlayerListCallback
+class cPlayerLookCheck
{
public:
cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
@@ -21,29 +20,29 @@ public:
{
}
- virtual bool Item(cPlayer * a_Player) override
+ bool operator () (cPlayer & a_Player)
{
// Don't check players who cannot be targeted
- if (!a_Player->CanMobsTarget())
+ if (!a_Player.CanMobsTarget())
{
return false;
}
// Don't check players who are more than SightDistance (64) blocks away
- auto Direction = m_EndermanPos - a_Player->GetPosition();
+ auto Direction = m_EndermanPos - a_Player.GetPosition();
if (Direction.Length() > m_SightDistance)
{
return false;
}
// Don't check if the player has a pumpkin on his head
- if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
+ if (a_Player.GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
{
return false;
}
// If the player's crosshair is within 5 degrees of the enderman, it counts as looking
- auto LookVector = a_Player->GetLookVector();
+ auto LookVector = a_Player.GetLookVector();
auto dot = Direction.Dot(LookVector);
if (dot <= cos(0.09)) // 0.09 rad ~ 5 degrees
{
@@ -51,13 +50,13 @@ public:
}
// TODO: Check if endermen are angered through water in Vanilla
- if (!cLineBlockTracer::LineOfSightTrace(*a_Player->GetWorld(), m_EndermanPos, a_Player->GetPosition(), cLineBlockTracer::losAirWater))
+ if (!cLineBlockTracer::LineOfSightTrace(*a_Player.GetWorld(), m_EndermanPos, a_Player.GetPosition(), cLineBlockTracer::losAirWater))
{
// No direct line of sight
return false;
}
- m_Player = a_Player;
+ m_Player = &a_Player;
return true;
}
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 51bc0637b..f16120b55 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -1331,9 +1331,24 @@ void cMonster::AttachTickBehavior(cBehavior * a_Behavior)
void cMonster::AttachDestroyBehavior(cBehavior * a_Behavior)
{
+<<<<<<< HEAD
ASSERT(a_Behavior != nullptr);
m_AttachedDestroyBehaviors.push_back(a_Behavior);
}
+=======
+ // If the Y coord is out of range, return the most logical result without considering anything else:
+ int RelY = FloorC(a_Location.y);
+ if (RelY >= cChunkDef::Height)
+ {
+ // Always burn above the world
+ return true;
+ }
+ if (RelY <= 0)
+ {
+ // The mob is about to die, no point in burning
+ return false;
+ }
+>>>>>>> master
diff --git a/src/Mobs/Ocelot.cpp b/src/Mobs/Ocelot.cpp
index e89b18186..183cb74c4 100644
--- a/src/Mobs/Ocelot.cpp
+++ b/src/Mobs/Ocelot.cpp
@@ -91,30 +91,25 @@ void cOcelot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cOcelot::TickFollowPlayer()
{
- class cCallback :
- public cPlayerListCallback
+ Vector3d OwnerPos;
+ bool OwnerFlying = false;
+ auto Callback = [&](cPlayer & a_Player)
{
- virtual bool Item(cPlayer * a_Player) override
- {
- OwnerPos = a_Player->GetPosition();
- OwnerFlying = a_Player->IsFlying();
- return true;
- }
- public:
- Vector3d OwnerPos;
- bool OwnerFlying;
- } Callback;
+ OwnerPos = a_Player.GetPosition();
+ OwnerFlying = a_Player.IsFlying();
+ return true;
+ };
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
{
// The player is present in the world, follow him:
- double Distance = (Callback.OwnerPos - GetPosition()).Length();
+ double Distance = (OwnerPos - GetPosition()).Length();
if (Distance > 12)
{
- if (!Callback.OwnerFlying)
+ if (!OwnerFlying)
{
- Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
- TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
+ OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z);
+ TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z);
}
}
if (Distance < 2)
@@ -123,9 +118,9 @@ void cOcelot::TickFollowPlayer()
}
else
{
- if (!Callback.OwnerFlying)
+ if (!OwnerFlying)
{
- MoveToPosition(Callback.OwnerPos);
+ MoveToPosition(OwnerPos);
}
}
}
@@ -206,27 +201,19 @@ void cOcelot::SpawnOn(cClientHandle & a_ClientHandle)
-class cFindSittingCat :
- public cEntityCallback
-{
- virtual bool Item(cEntity * a_Entity) override
- {
- return (
- (a_Entity->GetEntityType() == cEntity::etMonster) &&
- (static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) &&
- (static_cast<cOcelot *>(a_Entity)->IsSitting())
- );
- }
-};
-
-
-
-
-
bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition)
{
- cFindSittingCat FindSittingCat;
- return a_World->ForEachEntityInBox(cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), FindSittingCat);
+ return a_World->ForEachEntityInBox(
+ cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1),
+ [=](cEntity & a_Entity)
+ {
+ return (
+ (a_Entity.GetEntityType() == cEntity::etMonster) &&
+ (static_cast<cMonster &>(a_Entity).GetMobType() == eMonsterType::mtOcelot) &&
+ (static_cast<cOcelot &>(a_Entity).IsSitting())
+ );
+ }
+ );
}
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
new file mode 100644
index 000000000..c9345662d
--- /dev/null
+++ b/src/Mobs/PassiveMonster.cpp
@@ -0,0 +1,246 @@
+
+#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"
+#include "../Items/ItemSpawnEgg.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::Destroyed()
+{
+ if (m_LovePartner != nullptr)
+ {
+ m_LovePartner->ResetLoveMode();
+ }
+ super::Destroyed();
+}
+
+
+
+
+
+void cPassiveMonster::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 (m_EMState == ESCAPING)
+ {
+ CheckEventLostPlayer();
+ }
+
+ // if we have a partner, mate
+ if (m_LovePartner != nullptr)
+ {
+
+ if (m_MatingTimer > 0)
+ {
+ // If we should still mate, keep bumping into them until baby is made
+ Vector3d Pos = m_LovePartner->GetPosition();
+ MoveToPosition(Pos);
+ }
+ else
+ {
+ // Mating finished. Spawn baby
+ Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5;
+ UInt32 BabyID = m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true);
+
+ cPassiveMonster * Baby = nullptr;
+
+ m_World->DoWithEntityByID(BabyID, [&](cEntity & a_Entity)
+ {
+ Baby = static_cast<cPassiveMonster *>(&a_Entity);
+ return true;
+ }
+ );
+
+ if (Baby != nullptr)
+ {
+ Baby->InheritFromParents(this, m_LovePartner);
+ }
+
+ m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6));
+
+ m_LovePartner->ResetLoveMode();
+ ResetLoveMode();
+ }
+ }
+ else
+ {
+ // We have no partner, so we just chase the player if they have our breeding item
+ 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 we are in love mode but we have no partner, search for a partner neabry
+ if (m_LoveTimer > 0)
+ {
+ if (m_LovePartner == nullptr)
+ {
+ m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8), [=](cEntity & a_Entity)
+ {
+ // If the entity is not a monster, don't breed with it
+ // Also, do not self-breed
+ if ((a_Entity.GetEntityType() != etMonster) || (&a_Entity == this))
+ {
+ return false;
+ }
+
+ auto & Me = static_cast<cPassiveMonster&>(*this);
+ auto & PotentialPartner = static_cast<cPassiveMonster&>(a_Entity);
+
+ // If the potential partner is not of the same species, don't breed with it
+ if (PotentialPartner.GetMobType() != Me.GetMobType())
+ {
+ return false;
+ }
+
+ // If the potential partner is not in love
+ // Or they already have a mate, do not breed with them
+ if ((!PotentialPartner.IsInLove()) || (PotentialPartner.GetPartner() != nullptr))
+ {
+ return false;
+ }
+
+ // All conditions met, let's breed!
+ PotentialPartner.EngageLoveMode(&Me);
+ Me.EngageLoveMode(&PotentialPartner);
+ return true;
+ }
+ );
+ }
+
+ m_LoveTimer--;
+ }
+ if (m_MatingTimer > 0)
+ {
+ m_MatingTimer--;
+ }
+ if (m_LoveCooldown > 0)
+ {
+ m_LoveCooldown--;
+ }
+}
+
+
+
+
+
+void cPassiveMonster::OnRightClicked(cPlayer & a_Player)
+{
+ super::OnRightClicked(a_Player);
+
+ const cItem & EquippedItem = a_Player.GetEquippedItem();
+
+ // If a player holding breeding items right-clicked me, go into love mode
+ if ((m_LoveCooldown == 0) && !IsInLove() && !IsBaby())
+ {
+ cItems Items;
+ GetBreedingItems(Items);
+ if (Items.ContainsType(EquippedItem.m_ItemType))
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ m_LoveTimer = 20 * 30; // half a minute
+ m_World->BroadcastEntityStatus(*this, esMobInLove);
+ }
+ }
+ // 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) &&
+ (m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true) != cEntity::INVALID_ID) // Spawning succeeded
+ )
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ // The mob was spawned, "use" the item:
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ }
+ }
+}
+
+
+
diff --git a/src/Mobs/Squid.h b/src/Mobs/Squid.h
index 20d87dbca..8039089e3 100644
--- a/src/Mobs/Squid.h
+++ b/src/Mobs/Squid.h
@@ -24,7 +24,6 @@ public:
// Squids do not drown (or float)
virtual void HandleAir(void) override {}
- virtual void SetSwimState(cChunk & a_Chunk) override {}
private:
cBehaviorDoNothing m_BehaviorDoNothing;
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index 99b9a3ce8..195c90fd2 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -102,28 +102,19 @@ void cWither::KilledBy(TakeDamageInfo & a_TDI)
{
super::KilledBy(a_TDI);
- class cPlayerCallback : public cPlayerListCallback
- {
- Vector3f m_Pos;
-
- virtual bool Item(cPlayer * a_Player)
+ Vector3d Pos = GetPosition();
+ m_World->ForEachPlayer([=](cPlayer & a_Player)
{
// TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
- double Dist = (a_Player->GetPosition() - m_Pos).Length();
+ double Dist = (a_Player.GetPosition() - Pos).Length();
if (Dist < 50.0)
{
// If player is close, award achievement
- a_Player->AwardAchievement(achKillWither);
+ a_Player.AwardAchievement(achKillWither);
}
return false;
}
-
- public:
- cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
-
- } PlayerCallback(GetPosition());
-
- m_World->ForEachPlayer(PlayerCallback);
+ );
}
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index c08e572fb..f1c082ce7 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -83,19 +83,22 @@ void cWolf::NotifyAlliesOfFight(cPawn * a_Opponent)
return;
}
m_NotificationCooldown = 15;
- class cCallback : public cPlayerListCallback
- {
- virtual bool Item(cPlayer * a_Player) override
+
+ m_World->DoWithPlayerByUUID(m_OwnerUUID, [=](cPlayer & a_Player)
{
- a_Player->NotifyNearbyWolves(m_Opponent, false);
+ a_Player.NotifyNearbyWolves(a_Opponent, false);
return false;
}
+<<<<<<< HEAD
public:
cPawn * m_Opponent;
} Callback;
Callback.m_Opponent = a_Opponent;
m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback);*/
+=======
+ );
+>>>>>>> master
}
/*bool cWolf::Attack(std::chrono::milliseconds a_Dt)
@@ -356,31 +359,31 @@ void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cWolf::TickFollowPlayer()
{
+<<<<<<< HEAD
/*
class cCallback :
public cPlayerListCallback
+=======
+ Vector3d OwnerPos;
+ bool OwnerFlying;
+ auto Callback = [&](cPlayer & a_Player)
+>>>>>>> master
{
- virtual bool Item(cPlayer * a_Player) override
- {
- OwnerPos = a_Player->GetPosition();
- OwnerFlying = a_Player->IsFlying();
- return true;
- }
- public:
- Vector3d OwnerPos;
- bool OwnerFlying;
- } Callback;
+ OwnerPos = a_Player.GetPosition();
+ OwnerFlying = a_Player.IsFlying();
+ return true;
+ };
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
{
// The player is present in the world, follow him:
- double Distance = (Callback.OwnerPos - GetPosition()).Length();
+ double Distance = (OwnerPos - GetPosition()).Length();
if (Distance > 20)
{
- if (!Callback.OwnerFlying)
+ if (!OwnerFlying)
{
- Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
- TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
+ OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z);
+ TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z);
SetTarget(nullptr);
}
}
@@ -395,9 +398,9 @@ void cWolf::TickFollowPlayer()
{
if (GetTarget() == nullptr)
{
- if (!Callback.OwnerFlying)
+ if (!OwnerFlying)
{
- MoveToPosition(Callback.OwnerPos);
+ MoveToPosition(OwnerPos);
}
}
}