diff options
author | LogicParrot <LogicParrot@users.noreply.github.com> | 2017-08-22 12:23:03 +0200 |
---|---|---|
committer | LogicParrot <LogicParrot@users.noreply.github.com> | 2017-08-22 19:55:30 +0200 |
commit | 80d9c26c12a5be619a757d0251525664bf7065a6 (patch) | |
tree | 66d4f553ae12fd90dd94ffde9b85f595319ba5cb /src/Mobs/Behaviors/BehaviorBreeder.cpp | |
parent | Added check in cEntity::TickBurning for whether the entity is planning to change worlds. (#3943) (diff) | |
download | cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar.gz cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar.bz2 cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar.lz cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar.xz cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.tar.zst cuberite-80d9c26c12a5be619a757d0251525664bf7065a6.zip |
Diffstat (limited to 'src/Mobs/Behaviors/BehaviorBreeder.cpp')
-rw-r--r-- | src/Mobs/Behaviors/BehaviorBreeder.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/Mobs/Behaviors/BehaviorBreeder.cpp b/src/Mobs/Behaviors/BehaviorBreeder.cpp new file mode 100644 index 000000000..ea3e10026 --- /dev/null +++ b/src/Mobs/Behaviors/BehaviorBreeder.cpp @@ -0,0 +1,233 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "BehaviorBreeder.h" +#include "../PassiveMonster.h" +#include "../../World.h" +#include "../Monster.h" +#include "../../Entities/Player.h" +#include "../../Item.h" +#include "../../BoundingBox.h" + +iBehaviorBreeder::~iBehaviorBreeder() +{ + +} + + + + + +cBehaviorBreeder::cBehaviorBreeder(cMonster * a_Parent, cItems & a_BreedingItems) : + m_Parent(a_Parent), + m_LovePartner(nullptr), + m_LoveTimer(0), + m_LoveCooldown(0), + m_MatingTimer(0), + m_BreedingItems(a_BreedingItems) +{ + m_Parent = dynamic_cast<cMonster *>(m_ParentInterface); + ASSERT(m_Parent != nullptr); +} + + + + + +bool cBehaviorBreeder::ActiveTick() +{ + cWorld * World = m_Parent->GetWorld(); + // 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(); + m_Parent->MoveToPosition(Pos); + } + else + { + // Mating finished. Spawn baby + Vector3f Pos = (m_Parent->GetPosition() + m_LovePartner->GetPosition()) * 0.5; + UInt32 BabyID = World->SpawnMob(Pos.x, Pos.y, Pos.z, m_Parent->GetMobType(), true); + + class cBabyInheritCallback : + public cEntityCallback + { + public: + cMonster * Baby; + cBabyInheritCallback() : Baby(nullptr) { } + virtual bool Item(cEntity * a_Entity) override + { + Baby = static_cast<cMonster *>(a_Entity); + return true; + } + } Callback; + + m_Parent->GetWorld()->DoWithEntityByID(BabyID, Callback); + if (Callback.Baby != nullptr) + { + Callback.Baby->InheritFromParents(m_Parent, m_LovePartner); + } + + cFastRandom Random; + World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, 1 + Random.NextInt(6)); + + m_LovePartner->GetBehaviorBreeder()->ResetLoveMode(); + ResetLoveMode(); + } + return true; + } + + // If we are in love mode and we have no partner + if (m_LoveTimer > 0) + { + class LookForLover : public cEntityCallback + { + public: + cMonster * m_Me; + LookForLover(cMonster * a_Me) : + m_Me(a_Me) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + // If the entity is not a monster, don't breed with it + // Also, do not self-breed + if ((a_Entity->GetEntityType() != cEntity::eEntityType::etMonster) || (a_Entity == m_Me)) + { + return false; + } + + auto PotentialPartner = static_cast<cMonster*>(a_Entity); + + // If the potential partner is not of the same species, don't breed with it + if (PotentialPartner->GetMobType() != m_Me->GetMobType()) + { + return false; + } + + auto PartnerBreedingBehavior = PotentialPartner->GetBehaviorBreeder(); + auto MyBreedingBehavior = m_Me->GetBehaviorBreeder(); + + // If the potential partner is not in love + // Or they already have a mate, do not breed with them + + if ((!PartnerBreedingBehavior->IsInLove()) || (PartnerBreedingBehavior->GetPartner() != nullptr)) + { + return false; + } + + // All conditions met, let's breed! + PartnerBreedingBehavior->EngageLoveMode(m_Me); + MyBreedingBehavior->EngageLoveMode(PotentialPartner); + return true; + } + } Callback(m_Parent); + + World->ForEachEntityInBox(cBoundingBox(m_Parent->GetPosition(), 8, 8), Callback); + if (m_LovePartner != nullptr) + { + return true; // We found love and took control of the monster, prevent other Behaviors from doing so + } + } + + return false; +} + + + + + +void cBehaviorBreeder::Tick() +{ + if (m_MatingTimer > 0) + { + m_MatingTimer--; + } + if (m_LoveCooldown > 0) + { + m_LoveCooldown--; + } + if (m_LoveTimer > 0) + { + m_LoveTimer--; + } +} + + + + + +void cBehaviorBreeder::Destroyed() +{ + if (m_LovePartner != nullptr) + { + m_LovePartner->GetBehaviorBreeder()->ResetLoveMode(); + } +} + + + + + +void cBehaviorBreeder::OnRightClicked(cPlayer & a_Player) +{ + // If a player holding breeding items right-clicked me, go into love mode + if ((m_LoveCooldown == 0) && !IsInLove() && !m_Parent->IsBaby()) + { + short HeldItem = a_Player.GetEquippedItem().m_ItemType; + if (m_BreedingItems.ContainsType(HeldItem)) + { + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + m_LoveTimer = 20 * 30; // half a minute + m_Parent->GetWorld()->BroadcastEntityStatus(*m_Parent, cEntity::eEntityStatus::esMobInLove); + } + } +} + + + +void cBehaviorBreeder::EngageLoveMode(cMonster * a_Partner) +{ + m_LovePartner = a_Partner; + m_MatingTimer = 50; // about 3 seconds of mating +} + + + + + +void cBehaviorBreeder::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_Parent->GetWorld()->BroadcastEntityMetadata(*m_Parent); +} + + + + + +bool cBehaviorBreeder::IsInLove() const +{ + return m_LoveTimer > 0; +} + + + + + +bool cBehaviorBreeder::IsInLoveCooldown() const +{ + return (m_LoveCooldown > 0); +} |