diff options
Diffstat (limited to 'src/Mobs/Components')
-rw-r--r-- | src/Mobs/Components/AIAggressiveComponent.cpp | 17 | ||||
-rw-r--r-- | src/Mobs/Components/AIAggressiveComponent.h | 12 | ||||
-rw-r--r-- | src/Mobs/Components/AIComponent.cpp | 367 | ||||
-rw-r--r-- | src/Mobs/Components/AIComponent.h | 61 | ||||
-rw-r--r-- | src/Mobs/Components/AIPassiveAgressiveComponent.cpp | 17 | ||||
-rw-r--r-- | src/Mobs/Components/AIPassiveAgressiveComponent.h | 12 | ||||
-rw-r--r-- | src/Mobs/Components/AIPassiveComponent.cpp | 17 | ||||
-rw-r--r-- | src/Mobs/Components/AIPassiveComponent.h | 12 | ||||
-rw-r--r-- | src/Mobs/Components/AllComponents.h | 8 | ||||
-rw-r--r-- | src/Mobs/Components/AttackComponent.cpp | 5 | ||||
-rw-r--r-- | src/Mobs/Components/AttackComponent.h | 32 | ||||
-rw-r--r-- | src/Mobs/Components/CMakeLists.txt | 22 | ||||
-rw-r--r-- | src/Mobs/Components/EnvironmentComponent.cpp | 58 | ||||
-rw-r--r-- | src/Mobs/Components/EnvironmentComponent.h | 33 | ||||
-rw-r--r-- | src/Mobs/Components/MovementComponent.cpp | 50 | ||||
-rw-r--r-- | src/Mobs/Components/MovementComponent.h | 25 |
16 files changed, 748 insertions, 0 deletions
diff --git a/src/Mobs/Components/AIAggressiveComponent.cpp b/src/Mobs/Components/AIAggressiveComponent.cpp new file mode 100644 index 000000000..2963da7f0 --- /dev/null +++ b/src/Mobs/Components/AIAggressiveComponent.cpp @@ -0,0 +1,17 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "AIAggressiveComponent.h" + + + + + +cAIAggressiveComponent::cAIAggressiveComponent(cMonster * a_Monster) : cAIComponent(a_Monster){} + + + + + +void cAIAggressiveComponent::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); +} diff --git a/src/Mobs/Components/AIAggressiveComponent.h b/src/Mobs/Components/AIAggressiveComponent.h new file mode 100644 index 000000000..2cea452c5 --- /dev/null +++ b/src/Mobs/Components/AIAggressiveComponent.h @@ -0,0 +1,12 @@ +#pragma once +#include "AIComponent.h" + +class cEntity; + +class cAIAggressiveComponent : public cAIComponent { + typedef cAIComponent super; +protected: +public: + cAIAggressiveComponent(cMonster * a_Monster); + virtual void Tick(float a_Dt, cChunk & a_Chunk) /*override*/; +}; diff --git a/src/Mobs/Components/AIComponent.cpp b/src/Mobs/Components/AIComponent.cpp new file mode 100644 index 000000000..12a89c201 --- /dev/null +++ b/src/Mobs/Components/AIComponent.cpp @@ -0,0 +1,367 @@ +#include "Globals.h" +#include "AIComponent.h" +#include "../Monster.h" + +#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 new file mode 100644 index 000000000..c4cf15d14 --- /dev/null +++ b/src/Mobs/Components/AIComponent.h @@ -0,0 +1,61 @@ +#pragma once + +class cMonster; +class cEntity; +class cChunk; + +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); +}; diff --git a/src/Mobs/Components/AIPassiveAgressiveComponent.cpp b/src/Mobs/Components/AIPassiveAgressiveComponent.cpp new file mode 100644 index 000000000..efa88a8fa --- /dev/null +++ b/src/Mobs/Components/AIPassiveAgressiveComponent.cpp @@ -0,0 +1,17 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "cAIPassiveAggressiveComponent.h" + + + + + +cAIPassiveAggressiveComponent::cAIPassiveAggressiveComponent(cMonster * a_Monster) : cAIComponent(a_Monster){} + + + + + +void cAIPassiveAggressiveComponent::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); +} diff --git a/src/Mobs/Components/AIPassiveAgressiveComponent.h b/src/Mobs/Components/AIPassiveAgressiveComponent.h new file mode 100644 index 000000000..bd35251d0 --- /dev/null +++ b/src/Mobs/Components/AIPassiveAgressiveComponent.h @@ -0,0 +1,12 @@ +#pragma once +#include "AIComponent.h" + +class cEntity; + +class cAIPassiveAggressiveComponent : public cAIComponent { + typedef cAIComponent super; +protected: +public: + cAIPassiveAggressiveComponent(cMonster * a_Monster); + virtual void Tick(float a_Dt, cChunk & a_Chunk) /*override*/; +}; diff --git a/src/Mobs/Components/AIPassiveComponent.cpp b/src/Mobs/Components/AIPassiveComponent.cpp new file mode 100644 index 000000000..ba3fe7ec7 --- /dev/null +++ b/src/Mobs/Components/AIPassiveComponent.cpp @@ -0,0 +1,17 @@ +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules +#include "AIPassiveComponent.h" + + + + + +cAIPassiveComponent::cAIPassiveComponent(cMonster * a_Monster) : cAIComponent(a_Monster){} + + + + + +void cAIPassiveComponent::Tick(float a_Dt, cChunk & a_Chunk) +{ + super::Tick(a_Dt, a_Chunk); +}
\ No newline at end of file diff --git a/src/Mobs/Components/AIPassiveComponent.h b/src/Mobs/Components/AIPassiveComponent.h new file mode 100644 index 000000000..ab2e5afdb --- /dev/null +++ b/src/Mobs/Components/AIPassiveComponent.h @@ -0,0 +1,12 @@ +#pragma once +#include "AIComponent.h" + +class cEntity; + +class cAIPassiveComponent : public cAIComponent { + typedef cAIComponent super; +protected: +public: + cAIPassiveComponent(cMonster * a_Monster); + virtual void Tick(float a_Dt, cChunk & a_Chunk) /*override*/; +}; diff --git a/src/Mobs/Components/AllComponents.h b/src/Mobs/Components/AllComponents.h new file mode 100644 index 000000000..e99d08cc4 --- /dev/null +++ b/src/Mobs/Components/AllComponents.h @@ -0,0 +1,8 @@ +#pragma once + +#include "AIComponent.h" +#include "AttackComponent.h" +#include "EnvironmentComponent.h" +#include "MovementComponent.h" + +#include "AIAggressiveComponent.h" diff --git a/src/Mobs/Components/AttackComponent.cpp b/src/Mobs/Components/AttackComponent.cpp new file mode 100644 index 000000000..ae721f00b --- /dev/null +++ b/src/Mobs/Components/AttackComponent.cpp @@ -0,0 +1,5 @@ +#include "Globals.h" +#include "AttackComponent.h" +#include "../Monster.h" + +cAttackComponent::cAttackComponent(cMonster * a_Entity) : m_Self(a_Entity){} diff --git a/src/Mobs/Components/AttackComponent.h b/src/Mobs/Components/AttackComponent.h new file mode 100644 index 000000000..6a6932bd3 --- /dev/null +++ b/src/Mobs/Components/AttackComponent.h @@ -0,0 +1,32 @@ +#pragma once + +class cMonster; +class cEntity; +class cChunk; + +class cAttackComponent +{ +protected: + cMonster * m_Self; + float m_AttackRate; + int m_AttackDamage; + int m_AttackRange; + float m_AttackInterval; +public: + cAttackComponent(cMonster * a_Entity); + virtual ~cAttackComponent(){} + + virtual void Tick(float a_Dt, cChunk & a_Chunk){} + + // Get Functions + int GetAttackRate() { return (int)m_AttackRate; } + int GetAttackRange() { return m_AttackRange; } + int GetAttackDamage() { return m_AttackDamage; } + float GetAttackInterval() { return m_AttackInterval; } + + // Set Functions + void SetAttackRate(float a_AttackRate) { m_AttackRate = a_AttackRate; } + void SetAttackRange(int a_AttackRange) { m_AttackRange = a_AttackRange; } + void SetAttackDamage(int a_AttackDamage) { m_AttackDamage = a_AttackDamage; } + void SetAttackInterval(float a_AttackInterval) { m_AttackInterval = a_AttackInterval; } +}; diff --git a/src/Mobs/Components/CMakeLists.txt b/src/Mobs/Components/CMakeLists.txt new file mode 100644 index 000000000..a933dc9e0 --- /dev/null +++ b/src/Mobs/Components/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required (VERSION 2.6) +project (MCServer) + +include_directories ("${PROJECT_SOURCE_DIR}/../") + +SET (SRCS + AIComponent.cpp + AIAggressiveComponent.cpp + AttackComponent.cpp + EnvironmentComponent.cpp + MovementComponent.cpp) + +SET (HDRS + AIComponent.h + AIAggressiveComponent.h + AttackComponent.h + EnvironmentComponent.h + MovementComponent.h) + +if(NOT MSVC) + add_library(Components ${SRCS} ${HDRS}) +endif()
\ No newline at end of file diff --git a/src/Mobs/Components/EnvironmentComponent.cpp b/src/Mobs/Components/EnvironmentComponent.cpp new file mode 100644 index 000000000..b44542683 --- /dev/null +++ b/src/Mobs/Components/EnvironmentComponent.cpp @@ -0,0 +1,58 @@ +#include "Globals.h" +#include "EnvironmentComponent.h" +#include "../Monster.h" +#include "../../World.h" +#include "../../Chunk.h" + +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 new file mode 100644 index 000000000..078e81501 --- /dev/null +++ b/src/Mobs/Components/EnvironmentComponent.h @@ -0,0 +1,33 @@ +#pragma once + +class cMonster; +class cEntity; +class cChunk; + +class cEnvironmentComponent +{ +protected: + cMonster * m_Self; + int m_SightDistance; + bool m_OnGround; + + bool m_BurnsInDaylight; +public: + cEnvironmentComponent(cMonster * a_Entity, int a_SightDistance); + virtual ~cEnvironmentComponent(){} + + 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 new file mode 100644 index 000000000..e808e2948 --- /dev/null +++ b/src/Mobs/Components/MovementComponent.cpp @@ -0,0 +1,50 @@ +#include "Globals.h" +#include "MovementComponent.h" +#include "../Monster.h" + +#include "../../World.h" + +cMovementComponent::cMovementComponent(cMonster * a_Entity) : m_Self(a_Entity){} + + +int cMovementComponent::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ) +{ + int PosY = (int)floor(m_Self->GetPosY()); + PosY = Clamp(PosY, 0, cChunkDef::Height); + + if (!cBlockInfo::IsSolid(m_Self->GetWorld()->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ)))) + { + while (!cBlockInfo::IsSolid(m_Self->GetWorld()->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY > 0)) + { + PosY--; + } + + return PosY + 1; + } + else + { + while (cBlockInfo::IsSolid(m_Self->GetWorld()->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))) && (PosY < cChunkDef::Height)) + { + PosY++; + } + + 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 new file mode 100644 index 000000000..ffb840f76 --- /dev/null +++ b/src/Mobs/Components/MovementComponent.h @@ -0,0 +1,25 @@ +#pragma once + +class cMonster; +class cEntity; +class cChunk; + +class cMovementComponent +{ +protected: + cMonster * m_Self; +public: + cMovementComponent(cMonster * a_Entity); + virtual ~cMovementComponent(){} + + virtual void Tick(float a_Dt, cChunk & a_Chunk){} + + /** Finds the first non-air block position (not the highest, as cWorld::GetHeight does) + 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); +}; |