summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSamuel Barney <samjbarney@gmail.com>2014-08-26 19:59:09 +0200
committerSamuel Barney <samjbarney@gmail.com>2014-08-26 19:59:09 +0200
commitb64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98 (patch)
tree006d193d64bce89c7311d92704ea955b02cbaf6d
parentDunno why, but git said this needed to be pushed. (diff)
downloadcuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar.gz
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar.bz2
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar.lz
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar.xz
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.tar.zst
cuberite-b64df2ad5f119c2d8d9abb5760c2cf8fcf57ea98.zip
-rw-r--r--src/Mobs/Components/AIAggressiveComponent.cpp257
-rw-r--r--src/Mobs/Components/AIAggressiveComponent.h39
-rw-r--r--src/Mobs/Components/AIComponent.cpp364
-rw-r--r--src/Mobs/Components/AIComponent.h47
-rw-r--r--src/Mobs/Components/EnvironmentComponent.cpp55
-rw-r--r--src/Mobs/Components/EnvironmentComponent.h14
-rw-r--r--src/Mobs/Components/MovementComponent.cpp17
-rw-r--r--src/Mobs/Components/MovementComponent.h4
-rw-r--r--src/Mobs/Monster.cpp26
-rw-r--r--src/Mobs/Monster.h6
10 files changed, 528 insertions, 301 deletions
diff --git a/src/Mobs/Components/AIAggressiveComponent.cpp b/src/Mobs/Components/AIAggressiveComponent.cpp
index a1b22af59..a89d157fe 100644
--- a/src/Mobs/Components/AIAggressiveComponent.cpp
+++ b/src/Mobs/Components/AIAggressiveComponent.cpp
@@ -3,19 +3,11 @@
#include "AIAggressiveComponent.h"
#include <iostream>
-#include "../Monster.h"
-#include "../../World.h"
-#include "../../Entities/Player.h"
-#include "../../Tracer.h"
-
-
-cAIAggressiveComponent::cAIAggressiveComponent(cMonster * a_Monster) : cAIComponent(a_Monster), m_Target(NULL){
- m_EMPersonality = AGGRESSIVE;
-}
+cAIAggressiveComponent::cAIAggressiveComponent(cMonster * a_Monster) : cAIComponent(a_Monster){}
@@ -23,250 +15,5 @@ cAIAggressiveComponent::cAIAggressiveComponent(cMonster * a_Monster) : cAICompon
void cAIAggressiveComponent::Tick(float a_Dt, cChunk & a_Chunk)
{
- if (m_EMState == CHASING)
- {
- CheckEventLostPlayer();
- }
- else
- {
- CheckEventSeePlayer();
- }
-
- if (m_Target == NULL)
- return;
-
- cTracer LineOfSight(m_Self->GetWorld());
- Vector3d AttackDirection(m_Target->GetPosition() - m_Self->GetPosition());
-
- if (ReachedFinalDestination() && !LineOfSight.Trace(m_Self->GetPosition(), AttackDirection, (int)AttackDirection.Length()))
- {
- // 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 / 1000);
- }
-}
-
-
-
-
-
-void cAIAggressiveComponent::Attack(float a_Dt)
-{
-}
-
-
-
-
-
-void cAIAggressiveComponent::EventSeePlayer(cEntity * a_Entity)
-{
- if (!((cPlayer *)a_Entity)->IsGameModeCreative())
- {
- m_Target = a_Entity;
- m_EMState = CHASING;
- }
-}
-
-
-
-
-// What to do if in Chasing State
-void cAIAggressiveComponent::InStateChasing(float a_Dt)
-{
- if (m_Target != NULL)
- {
- if (m_Target->IsPlayer())
- {
- if (((cPlayer *)m_Target)->IsGameModeCreative())
- {
- m_EMState = IDLE;
- return;
- }
- }
-
- if (!IsMovingToTargetPosition())
- {
- MoveToPosition(m_Target->GetPosition());
- }
- }
-}
-
-
-
-
-bool cAIAggressiveComponent::ReachedFinalDestination()
-{
- if ((m_Self->GetPosition() - m_FinalDestination).Length() <= m_Self->GetAttackComponent().GetAttackRange())
- {
- return true;
- }
-
- return false;
-}
-
-
-
-
-
-void cAIAggressiveComponent::MoveToPosition(const Vector3d & a_Position)
-{
- FinishPathFinding();
-
- m_FinalDestination = a_Position;
- m_bMovingToDestination = true;
- TickPathFinding();
-}
-
-
-
-
-
-void cAIAggressiveComponent::TickPathFinding()
-{
- const int PosX = (int)floor(m_Self->GetPosX());
- const int PosY = (int)floor(m_Self->GetPosY());
- const int PosZ = (int)floor(m_Self->GetPosZ());
-
- std::vector<Vector3d> m_PotentialCoordinates;
- m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
-
- static const struct // Define which directions to try to move to
- {
- int x, z;
- } gCrossCoords[] =
- {
- { 1, 0},
- {-1, 0},
- { 0, 1},
- { 0, -1},
- } ;
-
- if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
- {
- // Too low/high, can't really do anything
- FinishPathFinding();
- return;
- }
-
- for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
- {
- if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
- {
- continue;
- }
-
- BLOCKTYPE BlockAtY = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
- BLOCKTYPE BlockAtYP = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
- BLOCKTYPE BlockAtYPP = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
- int LowestY = m_Self->GetMovementComponent().FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
- BLOCKTYPE BlockAtLowestY = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
-
- if (
- (!cBlockInfo::IsSolid(BlockAtY)) &&
- (!cBlockInfo::IsSolid(BlockAtYP)) &&
- (!IsBlockLava(BlockAtLowestY)) &&
- (BlockAtLowestY != E_BLOCK_CACTUS) &&
- (PosY - LowestY < 4)
- )
- {
- m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
- }
- else if (
- (cBlockInfo::IsSolid(BlockAtY)) &&
- (BlockAtY != E_BLOCK_CACTUS) &&
- (!cBlockInfo::IsSolid(BlockAtYP)) &&
- (!cBlockInfo::IsSolid(BlockAtYPP)) &&
- (BlockAtY != E_BLOCK_FENCE) &&
- (BlockAtY != E_BLOCK_FENCE_GATE)
- )
- {
- m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
- }
- }
-
- if (!m_PotentialCoordinates.empty())
- {
- Vector3f ShortestCoords = m_PotentialCoordinates.front();
- for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr)
- {
- Vector3f Distance = m_FinalDestination - ShortestCoords;
- Vector3f Distance2 = m_FinalDestination - *itr;
- if (Distance.SqrLength() > Distance2.SqrLength())
- {
- ShortestCoords = *itr;
- }
- }
-
- m_Destination = ShortestCoords;
- m_Destination.z += 0.5f;
- m_Destination.x += 0.5f;
- }
- else
- {
- FinishPathFinding();
- }
-}
-
-
-
-
-
-bool cAIAggressiveComponent::IsMovingToTargetPosition()
-{
- // Difference between destination x and target x is negligible (to 10^-12 precision)
- if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon())
- {
- return false;
- }
- // Difference between destination z and target z is negligible (to 10^-12 precision)
- else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon())
- {
- return false;
- }
- return true;
-}
-
-
-
-
-
-// Checks to see if EventSeePlayer should be fired
-// monster sez: Do I see the player
-void cAIAggressiveComponent::CheckEventSeePlayer(void)
-{
- // TODO: Rewrite this to use cWorld's DoWithPlayers()
- cPlayer * Closest = m_Self->GetWorld()->FindClosestPlayer(m_Self->GetPosition(), (float)m_Self->GetEnvironmentComponent().GetSightDistance(), false);
-
- if (Closest != NULL)
- {
- EventSeePlayer(Closest);
- }
-}
-
-
-
-
-
-void cAIAggressiveComponent::CheckEventLostPlayer(void)
-{
- if (m_Target != NULL)
- {
- if ((m_Target->GetPosition() - m_Self->GetPosition()).Length() > m_Self->GetEnvironmentComponent().GetSightDistance())
- {
- EventLosePlayer();
- }
- }
- else
- {
- EventLosePlayer();
- }
-}
-
-
-
-
-
-void cAIAggressiveComponent::EventLosePlayer(void)
-{
- m_Target = NULL;
- m_EMState = IDLE;
+ super::Tick(a_Dt, a_Chunk);
}
diff --git a/src/Mobs/Components/AIAggressiveComponent.h b/src/Mobs/Components/AIAggressiveComponent.h
index 373861ffd..2cea452c5 100644
--- a/src/Mobs/Components/AIAggressiveComponent.h
+++ b/src/Mobs/Components/AIAggressiveComponent.h
@@ -5,47 +5,8 @@ class cEntity;
class cAIAggressiveComponent : public cAIComponent {
typedef cAIComponent super;
- void EventSeePlayer(cEntity * a_Entity);
- void EventLosePlayer(void);
protected:
- void InStateChasing(float a_Dt);
-
- enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
- enum MPersonality{PASSIVE, AGGRESSIVE, COWARDLY} m_EMPersonality;
-
- cEntity * m_Target;
- /** Coordinates of the next position that should be reached */
- Vector3d m_Destination;
- /** Coordinates for the ultimate, final destination. */
- Vector3d m_FinalDestination;
- /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
- std::vector<Vector3i> m_TraversedCoordinates;
-
- /** Stores if mobile is currently moving towards the ultimate, final destination */
- bool m_bMovingToDestination;
-
- inline void FinishPathFinding(void)
- {
- m_TraversedCoordinates.clear();
- m_bMovingToDestination = false;
- }
- /** Finds the next place to go
- This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */
- void TickPathFinding(void);
-
- inline bool IsCoordinateInTraversedList(Vector3i a_Coords)
- {
- return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
- }
- bool IsMovingToTargetPosition();
- bool ReachedFinalDestination();
- void CheckEventSeePlayer(void);
- void CheckEventLostPlayer(void);
public:
cAIAggressiveComponent(cMonster * a_Monster);
-
virtual void Tick(float a_Dt, cChunk & a_Chunk) /*override*/;
-
- virtual void Attack(float a_Dt);
- void MoveToPosition(const Vector3d & a_Position);
};
diff --git a/src/Mobs/Components/AIComponent.cpp b/src/Mobs/Components/AIComponent.cpp
index b747bffd8..1c33dcaca 100644
--- a/src/Mobs/Components/AIComponent.cpp
+++ b/src/Mobs/Components/AIComponent.cpp
@@ -2,4 +2,366 @@
#include "AIComponent.h"
#include "../Monster.h"
-cAIComponent::cAIComponent(cMonster * a_Entity) : m_Self(a_Entity){}
+#include "../../World.h"
+#include "../../Entities/Player.h"
+#include "../../Tracer.h"
+
+cAIComponent::cAIComponent(cMonster * a_Entity) : m_Self(a_Entity), m_Target(NULL), m_IdleInterval(0.0f), m_EMState(IDLE), m_bMovingToDestination(false)
+{
+
+}
+
+void cAIComponent::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ if ((m_Target != NULL) && m_Target->IsDestroyed())
+ m_Target = NULL;
+
+
+ a_Dt /= 1000;
+
+ if (m_bMovingToDestination)
+ {
+ if (m_Self->GetEnvironmentComponent().GetOnGround() && m_Self->GetMovementComponent().DoesPosYRequireJump((int)floor(m_Destination.y)))
+ {
+ m_Self->GetEnvironmentComponent().SetOnGround(false);
+
+ // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
+ m_Self->AddPosY(1.2); // Jump!!
+ }
+
+ Vector3f Distance = m_Destination - m_Self->GetPosition();
+ if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
+ {
+ Distance.y = 0;
+ Distance.Normalize();
+
+ if (m_Self->GetEnvironmentComponent().GetOnGround())
+ {
+ Distance *= 2.5f;
+ }
+ else if (m_Self->IsSwimming())
+ {
+ Distance *= 1.3f;
+ }
+ else
+ {
+ // Don't let the mob move too much if he's falling.
+ Distance *= 0.25f;
+ }
+
+ m_Self->AddSpeedX(Distance.x);
+ m_Self->AddSpeedZ(Distance.z);
+
+ // It's too buggy!
+ /*
+ if (m_EMState == ESCAPING)
+ {
+ // Runs Faster when escaping :D otherwise they just walk away
+ SetSpeedX (GetSpeedX() * 2.f);
+ SetSpeedZ (GetSpeedZ() * 2.f);
+ }
+ */
+ }
+ else
+ {
+ if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate
+ {
+ FinishPathFinding();
+ }
+ else
+ {
+ TickPathFinding(); // We have reached the next point in our path, calculate another point
+ }
+ }
+ }
+
+ SetPitchAndYawFromDestination();
+ // HandleFalling();
+
+ switch (m_EMState)
+ {
+ case IDLE:
+ {
+ // If enemy passive we ignore checks for player visibility
+ InStateIdle(a_Dt);
+ break;
+ }
+ case CHASING:
+ {
+ // If we do not see a player anymore skip chasing action
+ InStateChasing(a_Dt);
+ break;
+ }
+ case ESCAPING:
+ {
+ InStateEscaping(a_Dt);
+ break;
+ }
+
+ case ATTACKING: break;
+ } // switch (m_EMState)
+
+ m_Self->BroadcastMovementUpdate();
+}
+
+
+
+
+
+void cAIComponent::SetPitchAndYawFromDestination()
+{
+ Vector3d FinalDestination = m_FinalDestination;
+ if (m_Target != NULL)
+ {
+ if (m_Target->IsPlayer())
+ {
+ FinalDestination.y = ((cPlayer *)m_Target)->GetStance();
+ }
+ else
+ {
+ FinalDestination.y = m_Self->GetHeight();
+ }
+ }
+
+ Vector3d Distance = FinalDestination - m_Self->GetPosition();
+ if (Distance.SqrLength() > 0.1f)
+ {
+ {
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
+ m_Self->SetHeadYaw(Rotation);
+ m_Self->SetPitch(-Pitch);
+ }
+
+ {
+ Vector3d BodyDistance = m_Destination - m_Self->GetPosition();
+ double Rotation, Pitch;
+ Distance.Normalize();
+ VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
+ m_Self->SetYaw(Rotation);
+ }
+ }
+}
+
+
+
+
+
+void cAIComponent::TickPathFinding()
+{
+ const int PosX = (int)floor(m_Self->GetPosX());
+ const int PosY = (int)floor(m_Self->GetPosY());
+ const int PosZ = (int)floor(m_Self->GetPosZ());
+
+ std::vector<Vector3d> m_PotentialCoordinates;
+ m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
+
+ static const struct // Define which directions to try to move to
+ {
+ int x, z;
+ } gCrossCoords[] =
+ {
+ { 1, 0},
+ {-1, 0},
+ { 0, 1},
+ { 0, -1},
+ } ;
+
+ if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
+ {
+ // Too low/high, can't really do anything
+ FinishPathFinding();
+ return;
+ }
+
+ for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
+ {
+ if (IsCoordinateInTraversedList(Vector3i(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ)))
+ {
+ continue;
+ }
+
+ BLOCKTYPE BlockAtY = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYP = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtYPP = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
+ int LowestY = m_Self->GetMovementComponent().FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
+ BLOCKTYPE BlockAtLowestY = m_Self->GetWorld()->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
+
+ if (
+ (!cBlockInfo::IsSolid(BlockAtY)) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!IsBlockLava(BlockAtLowestY)) &&
+ (BlockAtLowestY != E_BLOCK_CACTUS) &&
+ (PosY - LowestY < 4)
+ )
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
+ }
+ else if (
+ (cBlockInfo::IsSolid(BlockAtY)) &&
+ (BlockAtY != E_BLOCK_CACTUS) &&
+ (!cBlockInfo::IsSolid(BlockAtYP)) &&
+ (!cBlockInfo::IsSolid(BlockAtYPP)) &&
+ (BlockAtY != E_BLOCK_FENCE) &&
+ (BlockAtY != E_BLOCK_FENCE_GATE)
+ )
+ {
+ m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
+ }
+ }
+
+ if (!m_PotentialCoordinates.empty())
+ {
+ Vector3f ShortestCoords = m_PotentialCoordinates.front();
+ for (std::vector<Vector3d>::const_iterator itr = m_PotentialCoordinates.begin(); itr != m_PotentialCoordinates.end(); ++itr)
+ {
+ Vector3f Distance = m_FinalDestination - ShortestCoords;
+ Vector3f Distance2 = m_FinalDestination - *itr;
+ if (Distance.SqrLength() > Distance2.SqrLength())
+ {
+ ShortestCoords = *itr;
+ }
+ }
+
+ m_Destination = ShortestCoords;
+ m_Destination.z += 0.5f;
+ m_Destination.x += 0.5f;
+ }
+ else
+ {
+ FinishPathFinding();
+ }
+}
+
+
+
+
+
+bool cAIComponent::IsMovingToTargetPosition()
+{
+ // Difference between destination x and target x is negligible (to 10^-12 precision)
+ if (fabsf((float)m_FinalDestination.x - (float)m_Target->GetPosX()) < std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ // Difference between destination z and target z is negligible (to 10^-12 precision)
+ else if (fabsf((float)m_FinalDestination.z - (float)m_Target->GetPosZ()) > std::numeric_limits<float>::epsilon())
+ {
+ return false;
+ }
+ return true;
+}
+
+
+
+
+
+bool cAIComponent::ReachedFinalDestination()
+{
+ if ((m_Self->GetPosition() - m_FinalDestination).Length() <= m_Self->GetAttackComponent().GetAttackRange())
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
+bool cAIComponent::ReachedDestination()
+{
+ if ((m_Destination - m_Self->GetPosition()).Length() < 0.5f)
+ {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
+void cAIComponent::MoveToPosition(const Vector3d & a_Position)
+{
+ FinishPathFinding();
+
+ m_FinalDestination = a_Position;
+ m_bMovingToDestination = true;
+ TickPathFinding();
+}
+
+
+
+
+
+void cAIComponent::InStateIdle(float a_Dt)
+{
+ if (m_bMovingToDestination)
+ {
+ return; // Still getting there
+ }
+
+ m_IdleInterval += a_Dt;
+
+ if (m_IdleInterval > 1)
+ {
+ // At this interval the results are predictable
+ int rem = m_Self->GetWorld()->GetTickRandomNumber(6) + 1;
+ m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
+
+ Vector3d Dist;
+ Dist.x = (double)m_Self->GetWorld()->GetTickRandomNumber(10) - 5;
+ Dist.z = (double)m_Self->GetWorld()->GetTickRandomNumber(10) - 5;
+
+ if ((Dist.SqrLength() > 2) && (rem >= 3))
+ {
+ Vector3d Destination(m_Self->GetPosX() + Dist.x, 0, m_Self->GetPosZ() + Dist.z);
+
+ int NextHeight = m_Self->GetMovementComponent().FindFirstNonAirBlockPosition(Destination.x, Destination.z);
+
+ if (m_Self->GetMovementComponent().IsNextYPosReachable(NextHeight))
+ {
+ Destination.y = NextHeight;
+ MoveToPosition(Destination);
+ }
+ }
+ }
+}
+
+
+
+
+
+// What to do if in Chasing State
+// This state should always be defined in each child class
+void cAIComponent::InStateChasing(float a_Dt)
+{
+ UNUSED(a_Dt);
+}
+
+
+
+
+
+// What to do if in Escaping State
+void cAIComponent::InStateEscaping(float a_Dt)
+{
+ UNUSED(a_Dt);
+
+ if (m_Target != NULL)
+ {
+ int sight_distance = m_Self->GetEnvironmentComponent().GetSightDistance();
+ Vector3d newloc = m_Self->GetPosition();
+ newloc.x = (m_Target->GetPosition().x < newloc.x)? (newloc.x + sight_distance): (newloc.x - sight_distance);
+ newloc.z = (m_Target->GetPosition().z < newloc.z)? (newloc.z + sight_distance): (newloc.z - sight_distance);
+ MoveToPosition(newloc);
+ }
+ else
+ {
+ m_EMState = IDLE; // This shouldnt be required but just to be safe
+ }
+}
diff --git a/src/Mobs/Components/AIComponent.h b/src/Mobs/Components/AIComponent.h
index d8bfe7900..c4cf15d14 100644
--- a/src/Mobs/Components/AIComponent.h
+++ b/src/Mobs/Components/AIComponent.h
@@ -8,9 +8,54 @@ class cAIComponent
{
protected:
cMonster * m_Self;
+ cEntity * m_Target;
+ float m_IdleInterval;
+
+ enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
+
+ /** Coordinates of the next position that should be reached */
+ Vector3d m_Destination;
+ /** Coordinates for the ultimate, final destination. */
+ Vector3d m_FinalDestination;
+ /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
+ std::vector<Vector3i> m_TraversedCoordinates;
+
+ /** Stores if mobile is currently moving towards the ultimate, final destination */
+ bool m_bMovingToDestination;
+
+ /**********
+ * Pathfinding
+ **********/
+ inline void FinishPathFinding(void)
+ {
+ m_TraversedCoordinates.clear();
+ m_bMovingToDestination = false;
+ }
+ /** Finds the next place to go
+ This is based on the ultimate, final destination and the current position, as well as the traversed coordinates, and any environmental hazards */
+ void TickPathFinding(void);
+
+ inline bool IsCoordinateInTraversedList(Vector3i a_Coords)
+ {
+ return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
+ }
+ bool IsMovingToTargetPosition();
+ bool ReachedFinalDestination();
+ virtual bool ReachedDestination(void);
+ virtual void MoveToPosition(const Vector3d & a_Position);
+ void SetPitchAndYawFromDestination();
+
+ /**********
+ * Event Management
+ **********/
+ // void EventLosePlayer(void);
+ // virtual void EventSeePlayer(cEntity * a_Entity);
+ virtual void InStateIdle (float a_Dt);
+ virtual void InStateChasing (float a_Dt);
+ virtual void InStateEscaping(float a_Dt);
public:
cAIComponent(cMonster * a_Entity);
virtual ~cAIComponent(){}
- virtual void Tick(float a_Dt, cChunk & a_Chunk){}
+ virtual void Tick(float a_Dt, cChunk & a_Chunk);
};
diff --git a/src/Mobs/Components/EnvironmentComponent.cpp b/src/Mobs/Components/EnvironmentComponent.cpp
index f8cfc37ee..b44542683 100644
--- a/src/Mobs/Components/EnvironmentComponent.cpp
+++ b/src/Mobs/Components/EnvironmentComponent.cpp
@@ -1,5 +1,58 @@
#include "Globals.h"
#include "EnvironmentComponent.h"
#include "../Monster.h"
+#include "../../World.h"
+#include "../../Chunk.h"
-cEnvironmentComponent::cEnvironmentComponent(cMonster * a_Entity) : m_Self(a_Entity){}
+cEnvironmentComponent::cEnvironmentComponent(cMonster * a_Entity, int a_SightDistance) : m_Self(a_Entity), m_SightDistance(a_SightDistance){}
+
+
+
+
+
+void cEnvironmentComponent::Tick(float a_Dt, cChunk & a_Chunk) {
+
+ // Burning in daylight
+ HandleDaylightBurning(a_Chunk);
+}
+
+
+
+
+
+void cEnvironmentComponent::HandleDaylightBurning(cChunk & a_Chunk)
+{
+ if (!m_BurnsInDaylight)
+ {
+ return;
+ }
+
+ int RelY = (int)floor(m_Self->GetPosY());
+ if ((RelY < 0) || (RelY >= cChunkDef::Height))
+ {
+ // Outside the world
+ return;
+ }
+ int PosX = (int)floor(m_Self->GetPosX());
+ int PosZ = (int)floor(m_Self->GetPosX());
+ int RelX = PosX - m_Self->GetChunkX() * cChunkDef::Width;
+ int RelZ = PosZ - m_Self->GetChunkZ() * cChunkDef::Width;
+
+ if (!a_Chunk.IsLightValid())
+ {
+ m_Self->GetWorld()->QueueLightChunk(m_Self->GetChunkX(), m_Self->GetChunkZ());
+ return;
+ }
+
+ if (
+ (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
+ (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
+ (m_Self->GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
+ !m_Self->IsOnFire() && // Not already burning
+ m_Self->GetWorld()->IsWeatherWetAt(PosX, PosZ) // Not raining
+ )
+ {
+ // Burn for 100 ticks, then decide again
+ m_Self->StartBurning(100);
+ }
+}
diff --git a/src/Mobs/Components/EnvironmentComponent.h b/src/Mobs/Components/EnvironmentComponent.h
index cbf9e0784..078e81501 100644
--- a/src/Mobs/Components/EnvironmentComponent.h
+++ b/src/Mobs/Components/EnvironmentComponent.h
@@ -9,15 +9,25 @@ class cEnvironmentComponent
protected:
cMonster * m_Self;
int m_SightDistance;
+ bool m_OnGround;
+
+ bool m_BurnsInDaylight;
public:
- cEnvironmentComponent(cMonster * a_Entity);
+ cEnvironmentComponent(cMonster * a_Entity, int a_SightDistance);
virtual ~cEnvironmentComponent(){}
- virtual void Tick(float a_Dt, cChunk & a_Chunk){}
+ virtual void Tick(float a_Dt, cChunk & a_Chunk);
// Get Functions
int GetSightDistance() { return m_SightDistance ; }
+ bool GetOnGround() { return m_OnGround; }
+ bool GetBurnsInDaylight() { return m_BurnsInDaylight; }
// Set Functions
void SetSightDistance(int a_SightDistance) { m_SightDistance = a_SightDistance; }
+ void SetOnGround(bool a_Bool) { m_OnGround = a_Bool; }
+ void SetBurnsInDaylight(bool a_Bool) { m_BurnsInDaylight = a_Bool; }
+
+ // Handle functions
+ void HandleDaylightBurning(cChunk & a_Chunk);
};
diff --git a/src/Mobs/Components/MovementComponent.cpp b/src/Mobs/Components/MovementComponent.cpp
index f99e89103..e808e2948 100644
--- a/src/Mobs/Components/MovementComponent.cpp
+++ b/src/Mobs/Components/MovementComponent.cpp
@@ -31,3 +31,20 @@ int cMovementComponent::FindFirstNonAirBlockPosition(double a_PosX, double a_Pos
return PosY;
}
}
+
+
+
+
+
+bool cMovementComponent::IsNextYPosReachable(int a_PosY)
+{
+ return (
+ (a_PosY <= (int)floor(m_Self->GetPosY())) ||
+ DoesPosYRequireJump(a_PosY)
+ );
+}
+/** Returns if a monster can reach a given height by jumping */
+bool cMovementComponent::DoesPosYRequireJump(int a_PosY)
+{
+ return ((a_PosY > (int)floor(m_Self->GetPosY())) && (a_PosY == (int)floor(m_Self->GetPosY()) + 1));
+}
diff --git a/src/Mobs/Components/MovementComponent.h b/src/Mobs/Components/MovementComponent.h
index 9103a4842..ffb840f76 100644
--- a/src/Mobs/Components/MovementComponent.h
+++ b/src/Mobs/Components/MovementComponent.h
@@ -18,4 +18,8 @@ public:
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
If current Y is solid, goes up to find first nonsolid block, and returns that */
int FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ);
+ /** Returns if a monster can actually reach a given height by jumping or walking */
+ bool IsNextYPosReachable(int a_PosY);
+ /** Returns if a monster can reach a given height by jumping */
+ bool DoesPosYRequireJump(int a_PosY);
};
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index c272dc93a..1af44271b 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -58,10 +58,11 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_MobType(a_MobType)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
+ , m_DestroyTimer(0.0f)
{
- m_AI = new cAIComponent(this);
+ m_AI = new cAIAggressiveComponent(this);
m_Attack = new cAttackComponent(this);
- m_Environment = new cEnvironmentComponent(this);
+ m_Environment = new cEnvironmentComponent(this, 16);
m_Movement = new cMovementComponent(this);
// Temporary placement till I figure out where to put it
@@ -72,6 +73,27 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
m_DropChanceBoots = 0.0f;
}
+void cMonster::Tick(float a_Dt, cChunk & a_Chunk) {
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_Health <= 0)
+ {
+ // The mob is dead, but we're still animating the "puff" they leave when they die
+ m_DestroyTimer += a_Dt / 1000;
+ if (m_DestroyTimer > 1)
+ {
+ Destroy(true);
+ }
+ return;
+ }
+
+ LOG("Monster Tick...");
+ m_AI->Tick(a_Dt, a_Chunk);
+ m_Attack->Tick(a_Dt, a_Chunk);
+ m_Environment->Tick(a_Dt, a_Chunk);
+ m_Movement->Tick(a_Dt, a_Chunk);
+}
+
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 587c503e3..73ad5c6d3 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -76,8 +76,11 @@ protected:
cMovementComponent * m_Movement;
public:
cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+ ~cMonster() { delete m_AI; delete m_Attack; delete m_Environment; delete m_Movement;}
virtual void SpawnOn(cClientHandle & a_ClientHandle) /*override*/;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk);
+
// Type Function
virtual bool IsBaby (void) const { return false; }
virtual bool IsTame (void) const { return false; }
@@ -167,4 +170,7 @@ protected:
AString m_OwnerName;
AString m_OwnerUUID;
+
+
+ float m_DestroyTimer;
};