diff options
Diffstat (limited to 'src/Mobs')
-rw-r--r-- | src/Mobs/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/Mobs/Ocelot.cpp | 205 | ||||
-rw-r--r-- | src/Mobs/Ocelot.h | 49 | ||||
-rw-r--r-- | src/Mobs/PassiveMonster.cpp | 2 |
4 files changed, 252 insertions, 5 deletions
diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt index 44c664b6e..55ae36e1e 100644 --- a/src/Mobs/CMakeLists.txt +++ b/src/Mobs/CMakeLists.txt @@ -20,6 +20,7 @@ SET (SRCS MagmaCube.cpp Monster.cpp Mooshroom.cpp + Ocelot.cpp PassiveAggressiveMonster.cpp PassiveMonster.cpp Path.cpp diff --git a/src/Mobs/Ocelot.cpp b/src/Mobs/Ocelot.cpp new file mode 100644 index 000000000..47776670c --- /dev/null +++ b/src/Mobs/Ocelot.cpp @@ -0,0 +1,205 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Ocelot.h" +#include "../World.h" +#include "../Entities/Player.h" +#include "../Items/ItemHandler.h" +#include "Broadcaster.h" + + + + + +cOcelot::cOcelot(void) : + super("Ocelot", mtOcelot, "entity.cat.hurt", "entity.cat.death", 0.6, 0.8), + m_IsSitting(false), + m_IsTame(false), + m_IsBegging(false), + m_CatType(ctWildOcelot), + m_OwnerName("") +{ +} + + + + + +void cOcelot::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 (!IsTame() && !IsBaby()) + { + if (m_CheckPlayerTickCount == 23) + { + cPlayer * a_Closest_Player = m_World->FindClosestPlayer(GetPosition(), 10, true); + if (a_Closest_Player != nullptr) + { + cItems Items; + GetBreedingItems(Items); + if (Items.ContainsType(a_Closest_Player->GetEquippedItem().m_ItemType)) + { + if (!IsBegging()) + { + SetIsBegging(true); + m_World->BroadcastEntityMetadata(*this); + } + + MoveToPosition(a_Closest_Player->GetPosition()); + } + else + { + if (IsBegging()) + { + SetIsBegging(false); + m_World->BroadcastEntityMetadata(*this); + } + } + } + + m_CheckPlayerTickCount = 0; + } + else + { + m_CheckPlayerTickCount++; + } + } + + if (IsTame() && !IsSitting()) + { + TickFollowPlayer(); + } + else if (IsSitting()) + { + StopMovingToPosition(); + } + + m_World->BroadcastEntityMetadata(*this); +} + + + + + +void cOcelot::TickFollowPlayer() +{ + class cCallback : + public cPlayerListCallback + { + virtual bool Item(cPlayer * a_Player) override + { + OwnerPos = a_Player->GetPosition(); + OwnerFlying = a_Player->IsFlying(); + return true; + } + public: + Vector3d OwnerPos; + bool OwnerFlying; + } Callback; + + if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback)) + { + // The player is present in the world, follow him: + double Distance = (Callback.OwnerPos - GetPosition()).Length(); + if (Distance > 12) + { + if (!Callback.OwnerFlying) + { + Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z); + TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z); + } + } + if (Distance < 2) + { + StopMovingToPosition(); + } + else + { + if (!Callback.OwnerFlying) + { + MoveToPosition(Callback.OwnerPos); + } + } + } +} + + + + + +void cOcelot::OnRightClicked(cPlayer & a_Player) +{ + if (!IsTame()) + { + if ( + IsBegging() && + ((a_Player.GetPosition() - GetPosition()).Length() <= 3) + ) + { + cItems Items; + GetBreedingItems(Items); + if (Items.ContainsType(a_Player.GetEquippedItem().m_ItemType)) + { + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + + auto & Random = GetRandomProvider(); + + if (Random.RandBool(1.0 / 3.0)) + { + // Taming succeeded + SetIsBegging(false); + + SetMaxHealth(20); + SetIsTame(true); + SetOwner(a_Player.GetName(), a_Player.GetUUID()); + SetCatType(static_cast<eCatType>(Random.RandInt<int>(1, 3))); + m_World->BroadcastEntityStatus(*this, esWolfTamed); + m_World->GetBroadcaster().BroadcastParticleEffect("heart", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5); + } + else + { + // Taming failed + m_World->BroadcastEntityStatus(*this, esWolfTaming); + m_World->GetBroadcaster().BroadcastParticleEffect("smoke", static_cast<Vector3f>(GetPosition()), Vector3f{}, 0, 5); + } + } + } + else + { + super::OnRightClicked(a_Player); + } + } + else if (a_Player.GetUUID() == m_OwnerUUID) + { + super::OnRightClicked(a_Player); + SetIsSitting(!IsSitting()); + } + m_World->BroadcastEntityMetadata(*this); +} + + + + + +void cOcelot::SpawnOn(cClientHandle & a_ClientHandle) +{ + super::SpawnOn(a_ClientHandle); + if (!IsBaby() && GetRandomProvider().RandBool(1.0 / 7.0)) + { + m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true); + m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true); + } +} + + + + diff --git a/src/Mobs/Ocelot.h b/src/Mobs/Ocelot.h index a352e5854..fbff991c7 100644 --- a/src/Mobs/Ocelot.h +++ b/src/Mobs/Ocelot.h @@ -2,6 +2,7 @@ #pragma once #include "PassiveMonster.h" +#include "../Entities/Entity.h" @@ -13,17 +14,57 @@ class cOcelot : typedef cPassiveMonster super; public: - cOcelot(void) : - super("Ocelot", mtOcelot, "entity.cat.hurt", "entity.cat.death", 0.6, 0.8) + + enum eCatType { - } + ctWildOcelot, + ctTuxedo, + ctTabby, + ctSiamese, + } ; + + cOcelot(void); + CLASS_PROTODEF(cOcelot) + + virtual void OnRightClicked(cPlayer & a_Player) override; + virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override; + virtual void TickFollowPlayer(); + virtual void SpawnOn(cClientHandle & a_ClientHandle) override; virtual void GetBreedingItems(cItems & a_Items) override { a_Items.Add(E_ITEM_RAW_FISH); } - CLASS_PROTODEF(cOcelot) + // Get functions + bool IsSitting (void) const override { return m_IsSitting; } + bool IsTame (void) const override { return m_IsTame; } + bool IsBegging (void) const { return m_IsBegging; } + AString GetOwnerName (void) const { return m_OwnerName; } + AString GetOwnerUUID (void) const { return m_OwnerUUID; } + eCatType GetOcelotType (void) const { return m_CatType; } + + // Set functions + void SetIsSitting (bool a_IsSitting) { m_IsSitting = a_IsSitting; } + void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; } + void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; } + void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID) + { + m_OwnerName = a_NewOwnerName; + m_OwnerUUID = a_NewOwnerUUID; + } + void SetCatType (eCatType a_CatType) { m_CatType = a_CatType; } + +protected: + + bool m_IsSitting; + bool m_IsTame; + bool m_IsBegging; + eCatType m_CatType; + /** Only check for a nearby player holding the breeding items every 23 ticks. */ + int m_CheckPlayerTickCount; + AString m_OwnerName; + AString m_OwnerUUID; } ; diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp index 02e16d22f..73defaf7f 100644 --- a/src/Mobs/PassiveMonster.cpp +++ b/src/Mobs/PassiveMonster.cpp @@ -247,7 +247,7 @@ void cPassiveMonster::OnRightClicked(cPlayer & a_Player) eMonsterType MonsterType = cItemSpawnEggHandler::ItemDamageToMonsterType(EquippedItem.m_ItemDamage); if ( (MonsterType == m_MobType) && - (GetWorld()->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true) != cEntity::INVALID_ID) // Spawning succeeded + (m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), m_MobType, true) != cEntity::INVALID_ID) // Spawning succeeded ) { if (!a_Player.IsGameModeCreative()) |