diff options
author | LogicParrot <LogicParrot@users.noreply.github.com> | 2017-09-01 21:12:44 +0200 |
---|---|---|
committer | LogicParrot <LogicParrot@users.noreply.github.com> | 2017-09-01 21:12:44 +0200 |
commit | 6e3e7552e67dfc0254c3e99bcd32fea02f10d062 (patch) | |
tree | 84bfd40d2c2693cab44a47d4902aa601d8a715e6 /src/Mobs | |
parent | d (diff) | |
parent | SetSwimState now takes into account head height (diff) | |
download | cuberite-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.cpp | 15 | ||||
-rw-r--r-- | src/Mobs/Enderman.cpp | 17 | ||||
-rw-r--r-- | src/Mobs/Monster.cpp | 15 | ||||
-rw-r--r-- | src/Mobs/Ocelot.cpp | 61 | ||||
-rw-r--r-- | src/Mobs/PassiveMonster.cpp | 246 | ||||
-rw-r--r-- | src/Mobs/Squid.h | 1 | ||||
-rw-r--r-- | src/Mobs/Wither.cpp | 19 | ||||
-rw-r--r-- | src/Mobs/Wolf.cpp | 43 |
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); } } } |