summaryrefslogtreecommitdiffstats
path: root/src/Mobs/Behaviors
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs/Behaviors')
-rw-r--r--src/Mobs/Behaviors/Behavior.cpp80
-rw-r--r--src/Mobs/Behaviors/Behavior.h13
-rw-r--r--src/Mobs/Behaviors/BehaviorAggressive.cpp25
-rw-r--r--src/Mobs/Behaviors/BehaviorAggressive.h41
-rw-r--r--src/Mobs/Behaviors/BehaviorBreeder.cpp310
-rw-r--r--src/Mobs/Behaviors/BehaviorBreeder.h60
-rw-r--r--src/Mobs/Behaviors/BehaviorChaser.cpp160
-rw-r--r--src/Mobs/Behaviors/BehaviorChaser.h17
-rw-r--r--src/Mobs/Behaviors/BehaviorCoward.cpp2
-rw-r--r--src/Mobs/Behaviors/BehaviorCoward.h4
-rw-r--r--src/Mobs/Behaviors/BehaviorDayLightBurner.cpp136
-rw-r--r--src/Mobs/Behaviors/BehaviorDayLightBurner.h14
-rw-r--r--src/Mobs/Behaviors/BehaviorItemFollower.cpp42
-rw-r--r--src/Mobs/Behaviors/BehaviorItemFollower.h18
-rw-r--r--src/Mobs/Behaviors/CMakeLists.txt2
15 files changed, 522 insertions, 402 deletions
diff --git a/src/Mobs/Behaviors/Behavior.cpp b/src/Mobs/Behaviors/Behavior.cpp
new file mode 100644
index 000000000..e7c8a2c8b
--- /dev/null
+++ b/src/Mobs/Behaviors/Behavior.cpp
@@ -0,0 +1,80 @@
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Behavior.h"
+
+
+
+
+
+bool cBehavior::IsControlDesired()
+{
+ return false;
+}
+
+
+
+
+
+bool cBehavior::ControlStarting()
+{
+ return true;
+}
+
+
+
+
+
+bool cBehavior::ControlEnding()
+{
+ return true;
+}
+
+
+
+
+
+void cBehavior::Tick()
+{
+ LOGD("ERROR: Called a TICK on a behavior that doesn't have one.");
+ ASSERT(1 == 0);
+}
+
+
+
+
+
+void cBehavior::PostTick()
+{
+ LOGD("ERROR: Called a PostTick on a behavior that doesn't have one.");
+ ASSERT(1 == 0);
+}
+
+
+
+
+
+void cBehavior::PreTick()
+{
+ LOGD("ERROR: Called a PreTick on a behavior that doesn't have one.");
+ ASSERT(1 == 0);
+}
+
+
+
+
+
+void cBehavior::onRightClicked()
+{
+ LOGD("ERROR: Called onRightClicked on a behavior that doesn't have one.");
+ ASSERT(1 == 0);
+}
+
+
+
+
+
+void cBehavior::Destroyed()
+{
+ LOGD("ERROR: Called Destroyed on a behavior that doesn't have one.");
+ ASSERT(1 == 0);
+}
diff --git a/src/Mobs/Behaviors/Behavior.h b/src/Mobs/Behaviors/Behavior.h
new file mode 100644
index 000000000..c3e5cad8e
--- /dev/null
+++ b/src/Mobs/Behaviors/Behavior.h
@@ -0,0 +1,13 @@
+class cBehavior
+{
+public:
+ virtual bool IsControlDesired();
+ virtual bool ControlStarting();
+ virtual bool ControlEnding();
+ virtual void Tick();
+ virtual void PostTick();
+ virtual void PreTick();
+ virtual void onRightClicked();
+ virtual void Destroyed();
+ virtual ~cBehavior() = 0;
+};
diff --git a/src/Mobs/Behaviors/BehaviorAggressive.cpp b/src/Mobs/Behaviors/BehaviorAggressive.cpp
index 2113cb1e6..b2c7cc9ef 100644
--- a/src/Mobs/Behaviors/BehaviorAggressive.cpp
+++ b/src/Mobs/Behaviors/BehaviorAggressive.cpp
@@ -10,23 +10,22 @@
cBehaviorAggressive::cBehaviorAggressive(cMonster * a_Parent) : m_Parent(a_Parent)
{
- ASSERT(m_Parent != nullptr);
- m_ParentChaser = m_Parent->GetBehaviorChaser();
- ASSERT(m_ParentChaser != nullptr);
+ ASSERT(m_Parent != nullptr);
+ m_ParentChaser = m_Parent->GetBehaviorChaser();
+ ASSERT(m_ParentChaser != nullptr);
}
-bool cBehaviorAggressive::ActiveTick()
+void cBehaviorAggressive::PreTick()
{
- // Target something new if we have no target
- if (m_ParentChaser->GetTarget() == nullptr)
- {
- m_ParentChaser->SetTarget(FindNewTarget());
- }
- return false;
+ // Target something new if we have no target
+ if (m_ParentChaser->GetTarget() == nullptr)
+ {
+ m_ParentChaser->SetTarget(FindNewTarget());
+ }
}
@@ -35,7 +34,7 @@ bool cBehaviorAggressive::ActiveTick()
void cBehaviorAggressive::Destroyed()
{
- m_Target = nullptr;
+ m_ParentChaser->SetTarget(nullptr);
}
@@ -44,6 +43,6 @@ void cBehaviorAggressive::Destroyed()
cPawn * cBehaviorAggressive::FindNewTarget()
{
- cPlayer * Closest = m_Parent->GetNearestPlayer();
- return Closest; // May be null
+ cPlayer * Closest = m_Parent->GetNearestPlayer();
+ return Closest; // May be null
}
diff --git a/src/Mobs/Behaviors/BehaviorAggressive.h b/src/Mobs/Behaviors/BehaviorAggressive.h
index ca2ad577b..14dfc1ab0 100644
--- a/src/Mobs/Behaviors/BehaviorAggressive.h
+++ b/src/Mobs/Behaviors/BehaviorAggressive.h
@@ -1,31 +1,40 @@
-// The mob is agressive toward specific mobtypes, or toward the player.
-// This Behavior has a dependency on BehaviorChaser.
#pragma once
+
+
+class cBehaviorAggressive;
+
+#include "Behavior.h"
+
class cPawn;
class cMonster;
class cBehaviorChaser;
-class cBehaviorAggressive
+
+
+
+
+/** The mob is agressive toward specific mobtypes, or toward the player.
+This Behavior has a dependency on BehaviorChaser. */
+class cBehaviorAggressive : public cBehavior
{
public:
- cBehaviorAggressive(cMonster * a_Parent);
+ cBehaviorAggressive(cMonster * a_Parent);
- // cBehaviorAggressive(cMonster * a_Parent, bool a_HatesPlayer);
- // TODO agression toward specific players, and specific mobtypes, etc
- // Agression under specific conditions (nighttime, etc)
+ // cBehaviorAggressive(cMonster * a_Parent, bool a_HatesPlayer);
+ // TODO agression toward specific players, and specific mobtypes, etc
+ // Agression under specific conditions (nighttime, etc)
- // Functions our host Monster should invoke:
- bool ActiveTick();
- void Destroyed();
+ // Functions our host Monster should invoke:
+ void PreTick() override;
private:
- cPawn * FindNewTarget();
+ cPawn * FindNewTarget();
- // Our parent
- cMonster * m_Parent;
- cBehaviorChaser * m_ParentChaser;
+ // Our parent
+ cMonster * m_Parent;
+ cBehaviorChaser * m_ParentChaser;
- // The mob we want to attack
- cPawn * m_Target;
+ // The mob we want to attack
+ cPawn * m_Target;
};
diff --git a/src/Mobs/Behaviors/BehaviorBreeder.cpp b/src/Mobs/Behaviors/BehaviorBreeder.cpp
index 8ba991989..34f5142e0 100644
--- a/src/Mobs/Behaviors/BehaviorBreeder.cpp
+++ b/src/Mobs/Behaviors/BehaviorBreeder.cpp
@@ -10,153 +10,163 @@
#include "../../BoundingBox.h"
cBehaviorBreeder::cBehaviorBreeder(cMonster * a_Parent) :
- m_Parent(a_Parent),
- m_LovePartner(nullptr),
- m_LoveTimer(0),
- m_LoveCooldown(0),
- m_MatingTimer(0)
+ m_Parent(a_Parent),
+ m_LovePartner(nullptr),
+ m_LoveTimer(0),
+ m_LoveCooldown(0),
+ m_MatingTimer(0)
{
- m_Parent = a_Parent;
- ASSERT(m_Parent != nullptr);
+ m_Parent = a_Parent;
+ ASSERT(m_Parent != nullptr);
}
-bool cBehaviorBreeder::ActiveTick()
+void cBehaviorBreeder::Tick()
{
- 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.RandInt() % 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;
+ 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.RandInt() % 6));
+
+ m_LovePartner->GetBehaviorBreeder()->ResetLoveMode();
+ ResetLoveMode();
+ }d
+ }
}
-void cBehaviorBreeder::Tick()
+void cBehaviorBreeder::PostTick()
{
- if (m_MatingTimer > 0)
- {
- m_MatingTimer--;
- }
- if (m_LoveCooldown > 0)
- {
- m_LoveCooldown--;
- }
- if (m_LoveTimer > 0)
- {
- m_LoveTimer--;
- }
+ if (m_MatingTimer > 0)
+ {
+ m_MatingTimer--;
+ }
+ if (m_LoveCooldown > 0)
+ {
+ m_LoveCooldown--;
+ }
+ if (m_LoveTimer > 0)
+ {
+ m_LoveTimer--;
+ }
}
+bool cBehaviorBreeder::IsControlDesired()
+{
+ cWorld * World = m_Parent->GetWorld();
+
+ // if we have a love partner, we should control the mob
+ if (m_LovePartner != nullptr)
+ {
+ return true;
+ }
+
+ // If we are in love mode and we have no partner, try to find one
+ 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::Destroyed()
{
- if (m_LovePartner != nullptr)
- {
- m_LovePartner->GetBehaviorBreeder()->ResetLoveMode();
- }
+ if (m_LovePartner != nullptr)
+ {
+ m_LovePartner->GetBehaviorBreeder()->ResetLoveMode();
+ }
}
@@ -165,30 +175,30 @@ void cBehaviorBreeder::Destroyed()
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;
- cItems BreedingItems;
- m_Parent->GetFollowedItems(BreedingItems);
- if (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);
- }
- }
+ // 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;
+ cItems BreedingItems;
+ m_Parent->GetFollowedItems(BreedingItems);
+ if (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
+ m_LovePartner = a_Partner;
+ m_MatingTimer = 50; // about 3 seconds of mating
}
@@ -197,13 +207,13 @@ void cBehaviorBreeder::EngageLoveMode(cMonster * a_Partner)
void cBehaviorBreeder::ResetLoveMode()
{
- m_LovePartner = nullptr;
- m_LoveTimer = 0;
- m_MatingTimer = 0;
- m_LoveCooldown = 20 * 60 * 5; // 5 minutes
+ 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);
+ // 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);
}
@@ -212,7 +222,7 @@ void cBehaviorBreeder::ResetLoveMode()
bool cBehaviorBreeder::IsInLove() const
{
- return m_LoveTimer > 0;
+ return m_LoveTimer > 0;
}
@@ -221,5 +231,5 @@ bool cBehaviorBreeder::IsInLove() const
bool cBehaviorBreeder::IsInLoveCooldown() const
{
- return (m_LoveCooldown > 0);
+ return (m_LoveCooldown > 0);
}
diff --git a/src/Mobs/Behaviors/BehaviorBreeder.h b/src/Mobs/Behaviors/BehaviorBreeder.h
index 51ed0501d..d95840f5e 100644
--- a/src/Mobs/Behaviors/BehaviorBreeder.h
+++ b/src/Mobs/Behaviors/BehaviorBreeder.h
@@ -1,9 +1,9 @@
#pragma once
-// Grants breeding capabilities to the mob
-
class cBehaviorBreeder;
+#include "Behavior.h"
+
class cWorld;
class cMonster;
class cPlayer;
@@ -13,46 +13,48 @@ class cItems;
-class cBehaviorBreeder
+/** Grants breeding capabilities to the mob. */
+class cBehaviorBreeder : public cBehavior
{
public:
- cBehaviorBreeder(cMonster * a_Parent);
+ cBehaviorBreeder(cMonster * a_Parent);
- // Functions our host Monster should invoke:
- void Tick();
- bool ActiveTick();
- void OnRightClicked(cPlayer & a_Player);
- void Destroyed();
+ // Functions our host Monster should invoke:
+ bool IsControlDesired() override;
+ void Tick() override;
+ void PostTick() override;
+ void OnRightClicked(cPlayer & a_Player);
+ void Destroyed() override;
- /** Returns the partner which the monster is currently mating with. */
- cMonster * GetPartner(void) const { return m_LovePartner; }
+ /** Returns the partner which the monster is currently mating with. */
+ cMonster * GetPartner(void) const { return m_LovePartner; }
- /** Start the mating process. Causes the monster to keep bumping into the partner until m_MatingTimer reaches zero. */
- void EngageLoveMode(cMonster * a_Partner);
+ /** Start the mating process. Causes the monster to keep bumping into the partner until m_MatingTimer reaches zero. */
+ void EngageLoveMode(cMonster * a_Partner);
- /** Finish the mating process. Called after a baby is born. Resets all breeding related timers and sets m_LoveCooldown to 20 minutes. */
- void ResetLoveMode();
+ /** Finish the mating process. Called after a baby is born. Resets all breeding related timers and sets m_LoveCooldown to 20 minutes. */
+ void ResetLoveMode();
- /** Returns whether the monster has just been fed and is ready to mate. If this is "true" and GetPartner isn't "nullptr", then the monster is mating. */
- bool IsInLove() const;
+ /** Returns whether the monster has just been fed and is ready to mate. If this is "true" and GetPartner isn't "nullptr", then the monster is mating. */
+ bool IsInLove() const;
- /** Returns whether the monster is tired of breeding and is in the cooldown state. */
- bool IsInLoveCooldown() const;
+ /** Returns whether the monster is tired of breeding and is in the cooldown state. */
+ bool IsInLoveCooldown() const;
private:
- /** Our parent */
- cMonster * m_Parent;
+ /** Our parent */
+ cMonster * m_Parent;
- /** The monster's breeding partner. */
- cMonster * m_LovePartner;
+ /** The monster's breeding partner. */
+ cMonster * m_LovePartner;
- /** If above 0, the monster is in love mode, and will breed if a nearby monster is also in love mode. Decrements by 1 per tick till reaching zero. */
- int m_LoveTimer;
+ /** If above 0, the monster is in love mode, and will breed if a nearby monster is also in love mode. Decrements by 1 per tick till reaching zero. */
+ int m_LoveTimer;
- /** If above 0, the monster is in cooldown mode and will refuse to breed. Decrements by 1 per tick till reaching zero. */
- int m_LoveCooldown;
+ /** If above 0, the monster is in cooldown mode and will refuse to breed. Decrements by 1 per tick till reaching zero. */
+ int m_LoveCooldown;
- /** The monster is engaged in mating, once this reaches zero, a baby will be born. Decrements by 1 per tick till reaching zero, then a baby is made and ResetLoveMode() is called. */
- int m_MatingTimer;
+ /** The monster is engaged in mating, once this reaches zero, a baby will be born. Decrements by 1 per tick till reaching zero, then a baby is made and ResetLoveMode() is called. */
+ int m_MatingTimer;
};
diff --git a/src/Mobs/Behaviors/BehaviorChaser.cpp b/src/Mobs/Behaviors/BehaviorChaser.cpp
index b022495eb..2cdafe98f 100644
--- a/src/Mobs/Behaviors/BehaviorChaser.cpp
+++ b/src/Mobs/Behaviors/BehaviorChaser.cpp
@@ -10,58 +10,62 @@
cBehaviorChaser::cBehaviorChaser(cMonster * a_Parent) :
- m_Parent(a_Parent)
+ m_Parent(a_Parent)
, m_AttackRate(3)
, m_AttackDamage(1)
, m_AttackRange(1)
, m_AttackCoolDownTicksLeft(0)
, m_TicksSinceLastDamaged(50)
{
- ASSERT(m_Parent != nullptr);
- m_StrikeBehavior = m_Parent->GetBehaviorStriker();
- ASSERT(m_StrikeBehavior != nullptr); // The monster that has an Attacker behavior must also have a Striker behavior
+ ASSERT(m_Parent != nullptr);
}
-bool cBehaviorChaser::ActiveTick()
+bool cBehaviorChaser::Tick()
{
- // Stop targeting out of range targets
- if (GetTarget() != nullptr)
- {
- if (TargetOutOfSight())
- {
- SetTarget(nullptr);
- }
- else
- {
- if (TargetIsInStrikeRange())
- {
- StrikeTarget();
- }
- else
- {
- ApproachTarget();
- }
- return true;
- }
- }
- return false;
+ // Stop targeting out of range targets
+ if (GetTarget() != nullptr)
+ {
+ if (TargetOutOfSight())
+ {
+ SetTarget(nullptr);
+ }
+ else
+ {
+ if (TargetIsInStrikeRange())
+ {
+ StrikeTarget();
+ }
+ else
+ {
+ ApproachTarget(); // potential mobTodo: decoupling approaching from attacking
+ // Not important now, but important for future extensibility, e.g.
+ // cow chases wheat but using the netherman approacher to teleport around.
+ }
+ return true;
+ }
+ }
+ return false;
}
+void cBehaviorChaser::ApproachTarget()
+{
+ // potential mobTodo inheritence for creaper approachers, etc
+ m_Parent->MoveToPosition(m_Target->GetPosition());
+}
-
-void cBehaviorChaser::Tick()
+void cBehaviorChaser::PostTick()
{
- ++m_TicksSinceLastDamaged;
- if (m_AttackCoolDownTicksLeft > 0)
- {
- m_AttackCoolDownTicksLeft -= 1;
- }
+ ++m_TicksSinceLastDamaged;
+ if (m_AttackCoolDownTicksLeft > 0)
+ {
+ m_AttackCoolDownTicksLeft -= 1;
+ }
}
@@ -70,7 +74,7 @@ void cBehaviorChaser::Tick()
void cBehaviorChaser::Destroyed()
{
- m_Target = nullptr;
+ SetTarget(nullptr);
}
@@ -79,7 +83,7 @@ void cBehaviorChaser::Destroyed()
void cBehaviorChaser::SetAttackRate(float a_AttackRate)
{
- m_AttackRate = a_AttackRate;
+ m_AttackRate = a_AttackRate;
}
@@ -88,7 +92,7 @@ void cBehaviorChaser::SetAttackRate(float a_AttackRate)
void cBehaviorChaser::SetAttackRange(int a_AttackRange)
{
- m_AttackRange = a_AttackRange;
+ m_AttackRange = a_AttackRange;
}
@@ -97,7 +101,7 @@ void cBehaviorChaser::SetAttackRange(int a_AttackRange)
void cBehaviorChaser::SetAttackDamage(int a_AttackDamage)
{
- m_AttackDamage = a_AttackDamage;
+ m_AttackDamage = a_AttackDamage;
}
@@ -105,7 +109,7 @@ void cBehaviorChaser::SetAttackDamage(int a_AttackDamage)
cPawn * cBehaviorChaser::GetTarget()
{
- return m_Target;
+ return m_Target;
}
@@ -114,16 +118,7 @@ cPawn * cBehaviorChaser::GetTarget()
void cBehaviorChaser::SetTarget(cPawn * a_Target)
{
- m_Target = a_Target;
-}
-
-
-
-
-
-cBehaviorChaser::~cBehaviorChaser()
-{
-
+ m_Target = a_Target;
}
@@ -132,26 +127,26 @@ cBehaviorChaser::~cBehaviorChaser()
bool cBehaviorChaser::TargetIsInStrikeRange()
{
- ASSERT(m_Target != nullptr);
- ASSERT(m_Parent != nullptr);
- /*
- #include "../../Tracer.h"
- cTracer LineOfSight(m_Parent->GetWorld());
- Vector3d MyHeadPosition = m_Parent->GetPosition() + Vector3d(0, m_Parent->GetHeight(), 0);
- Vector3d AttackDirection(m_ParentChaser->GetTarget()->GetPosition() + Vector3d(0, GetTarget()->GetHeight(), 0) - MyHeadPosition);
-
-
- if (GetTarget() != nullptr)
- {
- MoveToPosition(GetTarget()->GetPosition());
- }
- if (TargetIsInRange() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length())) && (GetHealth() > 0.0))
- {
- // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
- Attack(a_Dt);
- }
- */
- return ((m_Target->GetPosition() - m_Parent->GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange));
+ ASSERT(m_Target != nullptr);
+ ASSERT(m_Parent != nullptr);
+ /*
+ #include "../../Tracer.h"
+ cTracer LineOfSight(m_Parent->GetWorld());
+ Vector3d MyHeadPosition = m_Parent->GetPosition() + Vector3d(0, m_Parent->GetHeight(), 0);
+ Vector3d AttackDirection(m_ParentChaser->GetTarget()->GetPosition() + Vector3d(0, GetTarget()->GetHeight(), 0) - MyHeadPosition);
+
+
+ if (GetTarget() != nullptr)
+ {
+ MoveToPosition(GetTarget()->GetPosition());
+ }
+ if (TargetIsInRange() && !LineOfSight.Trace(MyHeadPosition, AttackDirection, static_cast<int>(AttackDirection.Length())) && (GetHealth() > 0.0))
+ {
+ // Attack if reached destination, target isn't null, and have a clear line of sight to target (so won't attack through walls)
+ Attack(a_Dt);
+ }
+ */
+ return ((m_Target->GetPosition() - m_Parent->GetPosition()).SqrLength() < (m_AttackRange * m_AttackRange));
}
@@ -160,12 +155,12 @@ bool cBehaviorChaser::TargetIsInStrikeRange()
bool cBehaviorChaser::TargetOutOfSight()
{
- ASSERT(m_Target != nullptr);
- if ((GetTarget()->GetPosition() - m_Parent->GetPosition()).Length() > m_Parent->GetSightDistance())
- {
- return true;
- }
- return false;
+ ASSERT(m_Target != nullptr);
+ if ((GetTarget()->GetPosition() - m_Parent->GetPosition()).Length() > m_Parent->GetSightDistance())
+ {
+ return true;
+ }
+ return false;
}
@@ -174,7 +169,7 @@ bool cBehaviorChaser::TargetOutOfSight()
void cBehaviorChaser::ResetStrikeCooldown()
{
- m_AttackCoolDownTicksLeft = static_cast<int>(3 * 20 * m_AttackRate); // A second has 20 ticks, an attack rate of 1 means 1 hit every 3 seconds
+ m_AttackCoolDownTicksLeft = static_cast<int>(3 * 20 * m_AttackRate); // A second has 20 ticks, an attack rate of 1 means 1 hit every 3 seconds
}
@@ -183,10 +178,13 @@ void cBehaviorChaser::ResetStrikeCooldown()
void cBehaviorChaser::StrikeTarget()
{
- if (m_AttackCoolDownTicksLeft != 0)
- {
- // mobTodo
- // m_StrikeBehavior->Strike(m_Target); // LogicParrot Todo animations (via counter passing?)
- ResetStrikeCooldown();
- }
+ if (m_AttackCoolDownTicksLeft != 0)
+ {
+ cBehaviorStriker * Striker = m_Parent->GetBehaviorStriker();
+ if (Striker != nullptr)
+ {
+ Striker->Strike(m_Target);
+ }
+ ResetStrikeCooldown();
+ }
}
diff --git a/src/Mobs/Behaviors/BehaviorChaser.h b/src/Mobs/Behaviors/BehaviorChaser.h
index fff5ebfa3..e924a9db3 100644
--- a/src/Mobs/Behaviors/BehaviorChaser.h
+++ b/src/Mobs/Behaviors/BehaviorChaser.h
@@ -1,12 +1,15 @@
-
#pragma once
+class cBehaviorChaser;
+
+#include "Behavior.h"
+
class cMonster;
class cPawn;
class cBehaviorStriker;
-/** Grants attack capability to the mob. Note that this is not the same as agression!
+/** Grants chase capability to the mob. Note that this is not the same as agression!
The mob may possess this trait and not attack anyone or only attack when provoked.
Unlike most traits, this one has several forms, and therefore it is an abstract type
You should use one of its derived classes, and you cannot use it directly. */
@@ -17,9 +20,9 @@ public:
cBehaviorChaser(cMonster * a_Parent);
// Functions our host Monster should invoke:
- bool ActiveTick();
- void Destroyed();
- void Tick();
+ bool Tick() override;
+ void Destroyed() override;
+ void PostTick() override;
// Our host monster will call these once it loads its config file
void SetAttackRate(float a_AttackRate);
@@ -34,12 +37,12 @@ public:
virtual ~cBehaviorChaser();
protected:
- virtual void ApproachTarget() = 0;
+ void ApproachTarget();
+ // virtual void ApproachTarget() = 0;
private:
/** Our parent */
cMonster * m_Parent;
- cBehaviorStriker * m_StrikeBehavior;
// The mob we want to attack
cPawn * m_Target;
diff --git a/src/Mobs/Behaviors/BehaviorCoward.cpp b/src/Mobs/Behaviors/BehaviorCoward.cpp
index 017227340..ec3626807 100644
--- a/src/Mobs/Behaviors/BehaviorCoward.cpp
+++ b/src/Mobs/Behaviors/BehaviorCoward.cpp
@@ -17,7 +17,7 @@ cBehaviorCoward::cBehaviorCoward(cMonster * a_Parent) :
-bool cBehaviorCoward::ActiveTick()
+bool cBehaviorCoward::Tick()
{
if (m_Attacker == nullptr)
{
diff --git a/src/Mobs/Behaviors/BehaviorCoward.h b/src/Mobs/Behaviors/BehaviorCoward.h
index 227715c00..ed0ad3ed5 100644
--- a/src/Mobs/Behaviors/BehaviorCoward.h
+++ b/src/Mobs/Behaviors/BehaviorCoward.h
@@ -1,5 +1,7 @@
#pragma once
+#include "Behavior.h"
+
// Makes the mob run away from any other mob that damages it
//fwds
@@ -14,7 +16,7 @@ public:
cBehaviorCoward(cMonster * a_Parent);
// Functions our host Monster should invoke:
- bool ActiveTick();
+ bool Tick();
void DoTakeDamage(TakeDamageInfo & a_TDI);
diff --git a/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp b/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
index 809f0190f..062d60bae 100644
--- a/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
+++ b/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
@@ -9,28 +9,28 @@
cBehaviorDayLightBurner::cBehaviorDayLightBurner(cMonster * a_Parent) : m_Parent(a_Parent)
{
- ASSERT(m_Parent != nullptr);
+ ASSERT(m_Parent != nullptr);
}
-void cBehaviorDayLightBurner::Tick(cChunk & a_Chunk, bool WouldBurn)
+void cBehaviorDayLightBurner::PostTick(cChunk & a_Chunk, bool WouldBurn)
{
- int RelY = static_cast<int>(m_Parent->GetPosY());
- if ((RelY < 0) || (RelY >= cChunkDef::Height))
- {
- // Outside the world
- return;
- }
- if (!a_Chunk.IsLightValid())
- {
- m_Parent->GetWorld()->QueueLightChunk(m_Parent->GetChunkX(), m_Parent->GetChunkZ());
- return;
- }
+ int RelY = static_cast<int>(m_Parent->GetPosY());
+ if ((RelY < 0) || (RelY >= cChunkDef::Height))
+ {
+ // Outside the world
+ return;
+ }
+ if (!a_Chunk.IsLightValid())
+ {
+ m_Parent->GetWorld()->QueueLightChunk(m_Parent->GetChunkX(), m_Parent->GetChunkZ());
+ return;
+ }
- if (!m_Parent->IsOnFire() && WouldBurn)
- {
- // Burn for 100 ticks, then decide again
- m_Parent->StartBurning(100);
- }
+ if (!m_Parent->IsOnFire() && WouldBurn)
+ {
+ // Burn for 100 ticks, then decide again
+ m_Parent->StartBurning(100);
+ }
}
@@ -38,57 +38,57 @@ void cBehaviorDayLightBurner::Tick(cChunk & a_Chunk, bool WouldBurn)
bool cBehaviorDayLightBurner::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
{
- int RelY = FloorC(a_Location.y);
- if (RelY <= 0)
- {
- // The mob is about to die, no point in burning
- return false;
- }
- if (RelY >= cChunkDef::Height)
- {
- // Always burn above the world
- return true;
- }
+ int RelY = FloorC(a_Location.y);
+ if (RelY <= 0)
+ {
+ // The mob is about to die, no point in burning
+ return false;
+ }
+ if (RelY >= cChunkDef::Height)
+ {
+ // Always burn above the world
+ return true;
+ }
- PREPARE_REL_AND_CHUNK(a_Location, a_Chunk);
- if (!RelSuccess)
- {
- return false;
- }
+ PREPARE_REL_AND_CHUNK(a_Location, a_Chunk);
+ if (!RelSuccess)
+ {
+ return false;
+ }
- if (
- (Chunk->GetBlock(Rel.x, Rel.y, Rel.z) != E_BLOCK_SOULSAND) && // Not on soulsand
- (m_Parent->GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime
- m_Parent->GetWorld()->IsWeatherSunnyAt(static_cast<int>(m_Parent->GetPosX()), static_cast<int>(m_Parent->GetPosZ())) // Not raining
- )
- {
- int MobHeight = static_cast<int>(a_Location.y) + static_cast<int>(round(m_Parent->GetHeight())) - 1; // The height of the mob head
- if (MobHeight >= cChunkDef::Height)
- {
- return true;
- }
- // Start with the highest block and scan down to the mob's head.
- // If a non transparent is found, return false (do not burn). Otherwise return true.
- // Note that this loop is not a performance concern as transparent blocks are rare and the loop almost always bailes out
- // instantly.(An exception is e.g. standing under a long column of glass).
- int CurrentBlock = Chunk->GetHeight(Rel.x, Rel.z);
- while (CurrentBlock >= MobHeight)
- {
- BLOCKTYPE Block = Chunk->GetBlock(Rel.x, CurrentBlock, Rel.z);
- if (
- // Do not burn if a block above us meets one of the following conditions:
- (!cBlockInfo::IsTransparent(Block)) ||
- (Block == E_BLOCK_LEAVES) ||
- (Block == E_BLOCK_NEW_LEAVES) ||
- (IsBlockWater(Block))
- )
- {
- return false;
- }
- --CurrentBlock;
- }
- return true;
+ if (
+ (Chunk->GetBlock(Rel.x, Rel.y, Rel.z) != E_BLOCK_SOULSAND) && // Not on soulsand
+ (m_Parent->GetWorld()->GetTimeOfDay() < 12000 + 1000) && // Daytime
+ m_Parent->GetWorld()->IsWeatherSunnyAt(static_cast<int>(m_Parent->GetPosX()), static_cast<int>(m_Parent->GetPosZ())) // Not raining
+ )
+ {
+ int MobHeight = static_cast<int>(a_Location.y) + static_cast<int>(round(m_Parent->GetHeight())) - 1; // The height of the mob head
+ if (MobHeight >= cChunkDef::Height)
+ {
+ return true;
+ }
+ // Start with the highest block and scan down to the mob's head.
+ // If a non transparent is found, return false (do not burn). Otherwise return true.
+ // Note that this loop is not a performance concern as transparent blocks are rare and the loop almost always bailes out
+ // instantly.(An exception is e.g. standing under a long column of glass).
+ int CurrentBlock = Chunk->GetHeight(Rel.x, Rel.z);
+ while (CurrentBlock >= MobHeight)
+ {
+ BLOCKTYPE Block = Chunk->GetBlock(Rel.x, CurrentBlock, Rel.z);
+ if (
+ // Do not burn if a block above us meets one of the following conditions:
+ (!cBlockInfo::IsTransparent(Block)) ||
+ (Block == E_BLOCK_LEAVES) ||
+ (Block == E_BLOCK_NEW_LEAVES) ||
+ (IsBlockWater(Block))
+ )
+ {
+ return false;
+ }
+ --CurrentBlock;
+ }
+ return true;
- }
- return false;
+ }
+ return false;
}
diff --git a/src/Mobs/Behaviors/BehaviorDayLightBurner.h b/src/Mobs/Behaviors/BehaviorDayLightBurner.h
index d967b5f68..f059965c5 100644
--- a/src/Mobs/Behaviors/BehaviorDayLightBurner.h
+++ b/src/Mobs/Behaviors/BehaviorDayLightBurner.h
@@ -11,15 +11,15 @@ class cChunk;
class cBehaviorDayLightBurner
{
public:
- cBehaviorDayLightBurner(cMonster * a_Parent);
+ cBehaviorDayLightBurner(cMonster * a_Parent);
- void Tick(cChunk & a_Chunk, bool WouldBurn);
- bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk);
+ void PostTick(cChunk & a_Chunk, bool WouldBurn);
+ bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk);
- // Functions our host Monster should invoke:
- void Tick();
+ // Functions our host Monster should invoke:
+ void Tick();
private:
- cMonster * m_Parent; // Our Parent
- cEntity * m_Attacker; // The entity we're running away from
+ cMonster * m_Parent; // Our Parent
+ cEntity * m_Attacker; // The entity we're running away from
};
diff --git a/src/Mobs/Behaviors/BehaviorItemFollower.cpp b/src/Mobs/Behaviors/BehaviorItemFollower.cpp
index 833050e69..2b0377c46 100644
--- a/src/Mobs/Behaviors/BehaviorItemFollower.cpp
+++ b/src/Mobs/Behaviors/BehaviorItemFollower.cpp
@@ -7,33 +7,33 @@
cBehaviorItemFollower::cBehaviorItemFollower(cMonster * a_Parent) :
- m_Parent(a_Parent)
+ m_Parent(a_Parent)
{
- m_Parent = a_Parent;
- ASSERT(m_Parent != nullptr);
+ m_Parent = a_Parent;
+ ASSERT(m_Parent != nullptr);
}
-bool cBehaviorItemFollower::ActiveTick()
+bool cBehaviorItemFollower::Tick()
{
- cItems FollowedItems;
- m_Parent->GetFollowedItems(FollowedItems);
- if (FollowedItems.Size() > 0)
- {
- cPlayer * a_Closest_Player = m_Parent->GetNearestPlayer();
- if (a_Closest_Player != nullptr)
- {
- cItem EquippedItem = a_Closest_Player->GetEquippedItem();
- if (FollowedItems.ContainsType(EquippedItem))
- {
- Vector3d PlayerPos = a_Closest_Player->GetPosition();
- m_Parent->MoveToPosition(PlayerPos);
- return true; // We took control of the monster, prevent other Behaviors from doing so
- }
- }
- }
- return false;
+ cItems FollowedItems;
+ m_Parent->GetFollowedItems(FollowedItems);
+ if (FollowedItems.Size() > 0)
+ {
+ cPlayer * a_Closest_Player = m_Parent->GetNearestPlayer();
+ if (a_Closest_Player != nullptr)
+ {
+ cItem EquippedItem = a_Closest_Player->GetEquippedItem();
+ if (FollowedItems.ContainsType(EquippedItem))
+ {
+ Vector3d PlayerPos = a_Closest_Player->GetPosition();
+ m_Parent->MoveToPosition(PlayerPos);
+ return true; // We took control of the monster, prevent other Behaviors from doing so
+ }
+ }
+ }
+ return false;
}
diff --git a/src/Mobs/Behaviors/BehaviorItemFollower.h b/src/Mobs/Behaviors/BehaviorItemFollower.h
index ee2bda638..09acfe473 100644
--- a/src/Mobs/Behaviors/BehaviorItemFollower.h
+++ b/src/Mobs/Behaviors/BehaviorItemFollower.h
@@ -1,24 +1,26 @@
#pragma once
// Makes the mob follow specific held items
-
class cBehaviorItemFollower;
-//fwds
+
+#include "Behavior.h"
+
+// fwds
class cMonster;
class cItems;
class cBehaviorItemFollower
{
public:
- cBehaviorItemFollower(cMonster * a_Parent);
+ cBehaviorItemFollower(cMonster * a_Parent);
- void GetBreedingItems(cItems & a_Items);
+ void GetBreedingItems(cItems & a_Items);
- // Functions our host Monster should invoke:
- bool ActiveTick();
+ // Functions our host Monster should invoke:
+ void Tick();
private:
- /** Our parent */
- cMonster * m_Parent;
+ /** Our parent */
+ cMonster * m_Parent;
};
diff --git a/src/Mobs/Behaviors/CMakeLists.txt b/src/Mobs/Behaviors/CMakeLists.txt
index 3e0a063d1..017fc0f35 100644
--- a/src/Mobs/Behaviors/CMakeLists.txt
+++ b/src/Mobs/Behaviors/CMakeLists.txt
@@ -5,6 +5,7 @@ project (Cuberite)
include_directories ("${PROJECT_SOURCE_DIR}/../")
SET (SRCS
+ Behavior.cpp
BehaviorAggressive.cpp
BehaviorChaser.cpp
BehaviorBreeder.cpp
@@ -17,6 +18,7 @@ SET (SRCS
)
SET (HDRS
+ Behavior.h
BehaviorAggressive.h
BehaviorChaser.h
BehaviorBreeder.h