summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Mobs/Behaviors/Behavior.cpp24
-rw-r--r--src/Mobs/Behaviors/Behavior.h15
-rw-r--r--src/Mobs/Behaviors/BehaviorAggressive.h2
-rw-r--r--src/Mobs/Behaviors/BehaviorBreeder.h6
-rw-r--r--src/Mobs/Behaviors/BehaviorChaser.cpp15
-rw-r--r--src/Mobs/Behaviors/BehaviorChaser.h6
-rw-r--r--src/Mobs/Behaviors/BehaviorCoward.h4
-rw-r--r--src/Mobs/Behaviors/BehaviorDayLightBurner.cpp3
-rw-r--r--src/Mobs/Behaviors/BehaviorDayLightBurner.h7
-rw-r--r--src/Mobs/Behaviors/BehaviorItemFollower.h4
-rw-r--r--src/Mobs/Behaviors/BehaviorWanderer.h1
-rw-r--r--src/Mobs/Monster.cpp80
-rw-r--r--src/Mobs/Monster.h5
13 files changed, 139 insertions, 33 deletions
diff --git a/src/Mobs/Behaviors/Behavior.cpp b/src/Mobs/Behaviors/Behavior.cpp
index 7b54a3340..695343732 100644
--- a/src/Mobs/Behaviors/Behavior.cpp
+++ b/src/Mobs/Behaviors/Behavior.cpp
@@ -6,8 +6,10 @@
-bool cBehavior::IsControlDesired()
+bool cBehavior::IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
LOGD("ERROR: Probably forgot to implement cBehavior::IsControlDesired but implement cBehavior::Tick");
return false;
}
@@ -16,8 +18,10 @@ bool cBehavior::IsControlDesired()
-bool cBehavior::ControlStarting()
+bool cBehavior::ControlStarting(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
return true;
}
@@ -25,8 +29,10 @@ bool cBehavior::ControlStarting()
-bool cBehavior::ControlEnding()
+bool cBehavior::ControlEnding(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
return true;
}
@@ -34,8 +40,10 @@ bool cBehavior::ControlEnding()
-void cBehavior::Tick()
+void cBehavior::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
LOGD("ERROR: Called a TICK on a behavior that doesn't have one.");
ASSERT(1 == 0);
}
@@ -44,8 +52,10 @@ void cBehavior::Tick()
-void cBehavior::PostTick()
+void cBehavior::PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
LOGD("ERROR: Called a PostTick on a behavior that doesn't have one.");
ASSERT(1 == 0);
}
@@ -54,8 +64,10 @@ void cBehavior::PostTick()
-void cBehavior::PreTick()
+void cBehavior::PreTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ UNUSED(a_Dt);
+ UNUSED(a_Chunk);
LOGD("ERROR: Called a PreTick 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
index 81499eade..989addf8d 100644
--- a/src/Mobs/Behaviors/Behavior.h
+++ b/src/Mobs/Behaviors/Behavior.h
@@ -1,15 +1,18 @@
#pragma once
struct TakeDamageInfo;
+class cChunk;
+#include <chrono>
+
class cBehavior
{
public:
- virtual bool IsControlDesired();
- virtual bool ControlStarting();
- virtual bool ControlEnding();
- virtual void Tick();
- virtual void PostTick();
- virtual void PreTick();
+ virtual bool IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual bool ControlStarting(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual bool ControlEnding(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual void PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
+ virtual void PreTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
virtual void onRightClicked();
diff --git a/src/Mobs/Behaviors/BehaviorAggressive.h b/src/Mobs/Behaviors/BehaviorAggressive.h
index 14dfc1ab0..5bf86b23f 100644
--- a/src/Mobs/Behaviors/BehaviorAggressive.h
+++ b/src/Mobs/Behaviors/BehaviorAggressive.h
@@ -26,7 +26,7 @@ public:
// Agression under specific conditions (nighttime, etc)
// Functions our host Monster should invoke:
- void PreTick() override;
+ void PreTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
private:
cPawn * FindNewTarget();
diff --git a/src/Mobs/Behaviors/BehaviorBreeder.h b/src/Mobs/Behaviors/BehaviorBreeder.h
index d95840f5e..cf030b8f3 100644
--- a/src/Mobs/Behaviors/BehaviorBreeder.h
+++ b/src/Mobs/Behaviors/BehaviorBreeder.h
@@ -21,9 +21,9 @@ public:
cBehaviorBreeder(cMonster * a_Parent);
// Functions our host Monster should invoke:
- bool IsControlDesired() override;
- void Tick() override;
- void PostTick() override;
+ bool IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ void PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
void OnRightClicked(cPlayer & a_Player);
void Destroyed() override;
diff --git a/src/Mobs/Behaviors/BehaviorChaser.cpp b/src/Mobs/Behaviors/BehaviorChaser.cpp
index 71a50c55b..c486c049a 100644
--- a/src/Mobs/Behaviors/BehaviorChaser.cpp
+++ b/src/Mobs/Behaviors/BehaviorChaser.cpp
@@ -36,6 +36,21 @@ bool cBehaviorChaser::IsControlDesired()
void cBehaviorChaser::Tick()
{
+ /*
+ * if ((GetTarget() != nullptr))
+ {
+ ASSERT(GetTarget()->IsTicking());
+
+ if (GetTarget()->IsPlayer())
+ {
+ if (!static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
+ {
+ SetTarget(nullptr);
+ }
+ }
+ } //mobTodo copied from monster.cpp
+ * */
+
ASSERT((GetTarget() == nullptr) || (GetTarget()->IsPawn() && (GetTarget()->GetWorld() == m_Parent->GetWorld())));
// Stop targeting out of range targets
if (GetTarget() != nullptr)
diff --git a/src/Mobs/Behaviors/BehaviorChaser.h b/src/Mobs/Behaviors/BehaviorChaser.h
index b71d503b3..d0910e11e 100644
--- a/src/Mobs/Behaviors/BehaviorChaser.h
+++ b/src/Mobs/Behaviors/BehaviorChaser.h
@@ -20,10 +20,10 @@ public:
cBehaviorChaser(cMonster * a_Parent);
// Functions our host Monster should invoke:
- bool IsControlDesired() override;
- void Tick() override;
+ bool IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
void Destroyed() override;
- void PostTick() override;
+ void PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
void DoTakeDamage(TakeDamageInfo & a_TDI) override;
// Our host monster will call these once it loads its config file
diff --git a/src/Mobs/Behaviors/BehaviorCoward.h b/src/Mobs/Behaviors/BehaviorCoward.h
index 13deece61..048101d5d 100644
--- a/src/Mobs/Behaviors/BehaviorCoward.h
+++ b/src/Mobs/Behaviors/BehaviorCoward.h
@@ -16,8 +16,8 @@ public:
cBehaviorCoward(cMonster * a_Parent);
// Functions our host Monster should invoke:
- bool IsControlDesired() override;
- void Tick() override;
+ bool IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
void DoTakeDamage(TakeDamageInfo & a_TDI) override;
diff --git a/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp b/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
index 062d60bae..81307f36a 100644
--- a/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
+++ b/src/Mobs/Behaviors/BehaviorDayLightBurner.cpp
@@ -12,8 +12,9 @@ cBehaviorDayLightBurner::cBehaviorDayLightBurner(cMonster * a_Parent) : m_Parent
ASSERT(m_Parent != nullptr);
}
-void cBehaviorDayLightBurner::PostTick(cChunk & a_Chunk, bool WouldBurn)
+void cBehaviorDayLightBurner::PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
+ // mobTodo WouldBurn
int RelY = static_cast<int>(m_Parent->GetPosY());
if ((RelY < 0) || (RelY >= cChunkDef::Height))
{
diff --git a/src/Mobs/Behaviors/BehaviorDayLightBurner.h b/src/Mobs/Behaviors/BehaviorDayLightBurner.h
index f059965c5..77fcce281 100644
--- a/src/Mobs/Behaviors/BehaviorDayLightBurner.h
+++ b/src/Mobs/Behaviors/BehaviorDayLightBurner.h
@@ -1,6 +1,7 @@
#pragma once
// mobTodo I just need vector3d
+#include "Behavior.h"
#include "../../World.h"
// fwds
@@ -8,16 +9,16 @@ class cMonster;
class cEntity;
class cChunk;
-class cBehaviorDayLightBurner
+class cBehaviorDayLightBurner : cBehavior
{
public:
cBehaviorDayLightBurner(cMonster * a_Parent);
- void PostTick(cChunk & a_Chunk, bool WouldBurn);
+ void PostTick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk);
// Functions our host Monster should invoke:
- void Tick();
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
private:
cMonster * m_Parent; // Our Parent
diff --git a/src/Mobs/Behaviors/BehaviorItemFollower.h b/src/Mobs/Behaviors/BehaviorItemFollower.h
index ab33de65f..94f8bda15 100644
--- a/src/Mobs/Behaviors/BehaviorItemFollower.h
+++ b/src/Mobs/Behaviors/BehaviorItemFollower.h
@@ -17,8 +17,8 @@ public:
void GetBreedingItems(cItems & a_Items);
// Functions our host Monster should invoke:
- bool IsControlDesired() override;
- void Tick() override;
+ bool IsControlDesired(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
+ void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
private:
diff --git a/src/Mobs/Behaviors/BehaviorWanderer.h b/src/Mobs/Behaviors/BehaviorWanderer.h
index 23d86f0d2..258bf5f59 100644
--- a/src/Mobs/Behaviors/BehaviorWanderer.h
+++ b/src/Mobs/Behaviors/BehaviorWanderer.h
@@ -1,6 +1,7 @@
#pragma once
// The mob will wander around
+#include <chrono>
class cMonster;
class cEntity;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 246b433bd..7a33f3ce5 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -114,6 +114,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
, m_CanBeLeashed(GetMobFamily() == eFamily::mfPassive)
, m_Target(nullptr)
, m_CurrentTickControllingBehavior(nullptr)
+ , m_NewTickControllingBehavior(nullptr)
{
if (!a_ConfigName.empty())
{
@@ -300,17 +301,86 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
return;
}
- if ((GetTarget() != nullptr))
+ // All behaviors can execute PostTick and PreTick.
+ // These are for bookkeeping or passive actions like laying eggs.
+ // They MUST NOT control mob movement or interefere with the main Tick.
+ for (cBehavior * Behavior : PreTickBehaviors)
{
- ASSERT(GetTarget()->IsTicking());
+ Behavior->PreTick();
+ }
+
+ // Note 1: Each monster tick, at most one Behavior executes its Tick method.
+ // Note 2: Each monster tick, exactly one of these is executed:
+ // ControlStarting, Tick, ControlEnding
- if (GetTarget()->IsPlayer())
+ // If we're in a regular tick cycle
+ if (m_TickControllingBehaviorState == Normal)
+ {
+ // ask the behaviors sequentially if they are interested in controlling this mob
+ // Stop at the first one that says yes.
+ for (cBehavior * Behavior : TickBehaviors)
{
- if (!static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
+ if (Behavior->IsControlDesired())
{
- SetTarget(nullptr);
+ m_NewTickControllingBehavior = Behavior;
+ break;
}
}
+ ASSERT(m_NewTickControllingBehavior != nullptr); // it's not OK if no one asks for control
+ if (m_CurrentTickControllingBehavior == m_NewTickControllingBehavior)
+ {
+ // The Behavior asking for control is the same as the behavior from last tick.
+ // Nothing special, just tick it.
+ m_CurrentTickControllingBehavior->Tick();
+ }
+ else
+ {
+ // The behavior asking for control is not the same as the behavior from last tick.
+ // Begin the control swapping process.
+ m_TickControllingBehaviorState = OldControlEnding;
+ }
+
+ }
+
+ // Make the current controlling behavior clean up
+ if (m_TickControllingBehaviorState == OldControlEnding)
+ {
+ if (m_CurrentTickControllingBehavior->ControlEnding())
+ {
+ // The current behavior told us it is ready for letting go of control
+ m_TickControllingBehaviorState = NewControlStarting;
+ }
+ else
+ {
+ // The current behavior is not ready for releasing control. We'll execute ControlEnding
+ // next tick too.
+ m_TickControllingBehaviorState = OldControlEnding;
+ }
+ }
+ // Make the new controlling behavior set up
+ else if (m_TickControllingBehaviorState == NewControlStarting)
+ {
+ if (m_NewTickControllingBehavior->ControlStarting())
+ {
+ // The new behavior told us it is ready for taking control
+ // The new behavior is now the current behavior. Next tick it will execute its Tick.
+ m_TickControllingBehaviorState = Normal;
+ m_CurrentTickControllingBehavior = m_NewTickControllingBehavior;
+ }
+ else
+ {
+ // The new behavior is not ready for taking control.
+ // We'll execute ControlStarting next tick too.
+ m_TickControllingBehaviorState = NewControlStarting;
+ }
+ }
+
+ // All behaviors can execute PostTick and PreTick.
+ // These are for bookkeeping or passive actions like laying eggs.
+ // They MUST NOT control mob movement or interefere with the main Tick.
+ for (cBehavior * Behavior : PostTickBehaviors)
+ {
+ Behavior->PostTick();
}
bool a_IsFollowingPath = false;
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 11737b5bf..652b0a49f 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -329,11 +329,14 @@ private:
/** Leash calculations inside Tick function */
void CalcLeashActions();
+ std::vector<cBehavior*> PreTickBehaviors;
std::vector<cBehavior*> TickBehaviors;
+ std::vector<cBehavior*> PostTickBehaviors;
std::vector<cBehavior*> OnDestroyBehaviors;
std::vector<cBehavior*> OnRightClickBehaviors;
cBehavior * m_CurrentTickControllingBehavior;
- enum TickState{ControlStarting, ControlEnding, Normal} m_TickControllingBehaviorState;
+ cBehavior * m_NewTickControllingBehavior;
+ enum TickState{NewControlStarting, OldControlEnding, Normal} m_TickControllingBehaviorState;
} ; // tolua_export