summaryrefslogtreecommitdiffstats
path: root/src/Mobs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs')
-rw-r--r--src/Mobs/Monster.cpp32
-rw-r--r--src/Mobs/Monster.h6
-rw-r--r--src/Mobs/Path.cpp67
-rw-r--r--src/Mobs/Path.h27
-rw-r--r--src/Mobs/Skeleton.cpp20
-rw-r--r--src/Mobs/Skeleton.h5
-rw-r--r--src/Mobs/Zombie.cpp24
-rw-r--r--src/Mobs/Zombie.h8
8 files changed, 60 insertions, 129 deletions
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index e225ff9b1..9b9bec51e 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -121,7 +121,7 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
-void cMonster::TickPathFinding()
+void cMonster::TickPathFinding(cChunk & a_Chunk)
{
if (m_Path == nullptr)
@@ -131,18 +131,18 @@ void cMonster::TickPathFinding()
// Can someone explain why are these two NOT THE SAME???
// m_Path = new cPath(GetWorld(), GetPosition(), m_FinalDestination, 30);
- m_Path = new cPath(GetWorld(), Vector3d(floor(position.x), floor(position.y), floor(position.z)), Vector3d(floor(Dest.x), floor(Dest.y), floor(Dest.z)), 20);
+ m_Path = new cPath(&a_Chunk, Vector3d(floor(position.x), floor(position.y), floor(position.z)), Vector3d(floor(Dest.x), floor(Dest.y), floor(Dest.z)), 20);
m_IsFollowingPath = false;
}
- m_PathStatus = m_Path->Step();
+ m_PathStatus = m_Path->Step(&a_Chunk);
switch (m_PathStatus)
{
case ePathFinderStatus::PATH_NOT_FOUND:
{
- FinishPathFinding();
+ ResetPathFinding();
break;
}
@@ -164,7 +164,7 @@ void cMonster::TickPathFinding()
}
if (m_Path->IsLastPoint())
{
- FinishPathFinding();
+ ResetPathFinding();
}
break;
@@ -191,7 +191,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
void cMonster::StopMovingToPosition()
{
m_bMovingToDestination = false;
- FinishPathFinding();
+ ResetPathFinding();
}
@@ -209,7 +209,7 @@ bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
/* No one should call this except the pathfinder orthe monster tick or StopMovingToPosition.
Resets the pathfinder, usually starting a brand new path, unless called from StopMovingToPosition. */
-void cMonster::FinishPathFinding(void)
+void cMonster::ResetPathFinding(void)
{
if (m_Path != nullptr)
{
@@ -254,6 +254,7 @@ bool cMonster::ReachedFinalDestination()
void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
+ GET_AND_VERIFY_CURRENT_CHUNK(Chunk, POSX_TOINT, POSZ_TOINT);
if (m_Health <= 0)
{
@@ -276,7 +277,8 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
}
// Burning in daylight
- HandleDaylightBurning(a_Chunk);
+ bool WouldBurnRightNow = WouldBurnAt(GetPosition(), *Chunk); // cached so that we use it twice, spares some cycles.
+ HandleDaylightBurning(*Chunk, WouldBurnRightNow);
@@ -293,14 +295,19 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
}
}
- TickPathFinding();
+ TickPathFinding(a_Chunk);
Vector3d Distance = m_Destination - GetPosition();
if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
if (--m_GiveUpCounter == 0)
{
- FinishPathFinding();
+ ResetPathFinding(); // Not to be confused with StopMovingToPosition, this just discards the current path and calculates another.
+ }
+ else if (m_BurnsInDaylight && WouldBurnAt(m_Destination, *Chunk) && !WouldBurnRightNow && (m_TicksSinceLastDamaged == 100))
+ {
+ // If we burn in daylight, and we would burn at the next step, and we won't burn where we are right now, and we weren't provoked recently:
+ StopMovingToPosition();
}
else
{
@@ -1091,7 +1098,7 @@ void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel)
-void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
+void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn)
{
if (!m_BurnsInDaylight)
{
@@ -1110,7 +1117,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
return;
}
- if (WouldBurnAt(GetPosition(), a_Chunk))
+ if (!IsOnFire() && WouldBurn)
{
// Burn for 100 ticks, then decide again
StartBurning(100);
@@ -1129,7 +1136,6 @@ bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk)
(a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
- !IsOnFire() && // Not already burning
GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining
)
{
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 43861e021..9699e74ad 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -206,9 +206,9 @@ protected:
/** 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);
+ void TickPathFinding(cChunk & a_Chunk);
/** Finishes a pathfinding task, be it due to failure or something else */
- void FinishPathFinding(void);
+ void ResetPathFinding(void);
/** Sets the body yaw and head yaw/pitch based on next/ultimate destinations */
void SetPitchAndYawFromDestination(void);
@@ -244,7 +244,7 @@ protected:
bool m_CanPickUpLoot;
int m_TicksSinceLastDamaged; // How many ticks ago we were last damaged by a player?
- void HandleDaylightBurning(cChunk & a_Chunk);
+ void HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn);
bool WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk);
bool m_BurnsInDaylight;
double m_RelativeWalkSpeed;
diff --git a/src/Mobs/Path.cpp b/src/Mobs/Path.cpp
index 0cb03c925..32eff9d2b 100644
--- a/src/Mobs/Path.cpp
+++ b/src/Mobs/Path.cpp
@@ -1,12 +1,9 @@
#include "Globals.h"
-#ifndef COMPILING_PATHFIND_DEBUGGER
- /* MCServer headers */
- #include "../World.h"
- #include "../Chunk.h"
-#endif
#include <cmath>
+
#include "Path.h"
+#include "../Chunk.h"
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
@@ -38,18 +35,17 @@ bool compareHeuristics::operator()(cPathCell * & a_Cell1, cPathCell * & a_Cell2)
/* cPath implementation */
cPath::cPath(
- cWorld * a_World,
+ cChunk * a_Chunk,
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
double a_BoundingBoxWidth, double a_BoundingBoxHeight,
int a_MaxUp, int a_MaxDown
)
{
+ ASSERT(m_Chunk != nullptr);
// TODO: if src not walkable OR dest not walkable, then abort.
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
- m_World = a_World;
- // m_World = cRoot::Get()->GetDefaultWorld();
-
+ m_Chunk = a_Chunk;
m_Source = a_StartingPoint.Floor();
m_Destination = a_EndingPoint.Floor();
@@ -65,6 +61,7 @@ cPath::cPath(
m_PointCount = 0;
ProcessCell(GetCell(a_StartingPoint), nullptr, 0);
+ m_Chunk = nullptr;
}
@@ -83,8 +80,10 @@ cPath::~cPath()
-ePathFinderStatus cPath::Step()
+ePathFinderStatus cPath::Step(cChunk * a_Chunk)
{
+ m_Chunk = a_Chunk;
+ ASSERT(m_Chunk != nullptr);
if (m_Status != ePathFinderStatus::CALCULATING)
{
return m_Status;
@@ -106,6 +105,7 @@ ePathFinderStatus cPath::Step()
}
}
}
+ m_Chunk = nullptr;
return m_Status;
}
@@ -113,15 +113,25 @@ ePathFinderStatus cPath::Step()
-#ifndef COMPILING_PATHFIND_DEBUGGER
bool cPath::IsSolid(const Vector3d & a_Location)
{
- int ChunkX, ChunkZ;
- m_Item_CurrentBlock = a_Location;
- cChunkDef::BlockToChunk(a_Location.x, a_Location.z, ChunkX, ChunkZ);
- return !m_World->DoWithChunk(ChunkX, ChunkZ, * this);
+ ASSERT(m_Chunk != nullptr);
+ m_Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
+ if (!m_Chunk->IsValid())
+ {
+ return true;
+ }
+ BLOCKTYPE BlockType;
+ NIBBLETYPE BlockMeta;
+ int RelX = a_Location.x - m_Chunk->GetPosX() * cChunkDef::Width;
+ int RelZ = a_Location.z - m_Chunk->GetPosZ() * cChunkDef::Width;
+ m_Chunk->GetBlockTypeMeta(RelX, a_Location.y, RelZ, BlockType, BlockMeta);
+ if ((BlockType == E_BLOCK_FENCE) || (BlockType == E_BLOCK_FENCE_GATE))
+ {
+ GetCell(a_Location + Vector3d(0, 1, 0))->m_IsSolid = true; // Mobs will always think that the fence is 2 blocks high and therefore won't jump over.
+ }
+ return cBlockInfo::IsSolid(BlockType);
}
-#endif
@@ -352,28 +362,3 @@ void cPath::AddPoint(Vector3d a_Vector)
m_PathPoints.push_back(a_Vector);
++m_PointCount;
}
-
-
-
-
-
-#ifndef COMPILING_PATHFIND_DEBUGGER
-bool cPath::Item(cChunk * a_Chunk) // returns FALSE if there's a solid or if we failed.
-{
- int RelX = m_Item_CurrentBlock.x - a_Chunk->GetPosX() * cChunkDef::Width;
- int RelZ = m_Item_CurrentBlock.z - a_Chunk->GetPosZ() * cChunkDef::Width;
-
- if (!a_Chunk->IsValid())
- {
- return false;
- }
- BLOCKTYPE BlockType;
- NIBBLETYPE BlockMeta;
- a_Chunk->GetBlockTypeMeta(RelX, m_Item_CurrentBlock.y, RelZ, BlockType, BlockMeta);
- return (!cBlockInfo::IsSolid(BlockType));
-
- // TODO Maybe I should queue several blocks and call item() at once for all of them for better performance?
- // I think Worktycho said each item() call needs 2 locks.
-
-}
-#endif
diff --git a/src/Mobs/Path.h b/src/Mobs/Path.h
index 05fd59155..9927d0a34 100644
--- a/src/Mobs/Path.h
+++ b/src/Mobs/Path.h
@@ -18,12 +18,8 @@ Put this in your .cpp:
#include <unordered_map>
-/* MCServer forward declarations */
-#ifndef COMPILING_PATHFIND_DEBUGGER
-
-// fwd: cChunkMap.h
-typedef cItemCallback<cChunk> cChunkCallback;
-#endif
+//fwd: ../Chunk.h
+class cChunk;
/* Various little structs and classes */
enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND};
@@ -35,9 +31,6 @@ public:
};
class cPath
-#ifndef COMPILING_PATHFIND_DEBUGGER
-: public cChunkCallback
-#endif
{
public:
/** Creates a pathfinder instance. A Mob will probably need a single pathfinder instance for its entire life.
@@ -59,7 +52,7 @@ public:
@param a_EndingPoint "The block where the Zombie's knees want to be".
@param a_MaxSteps The maximum steps before giving up. */
cPath(
- cWorld * a_World,
+ cChunk * a_Chunk,
const Vector3d & a_StartingPoint, const Vector3d & a_EndingPoint, int a_MaxSteps,
double a_BoundingBoxWidth = 1, double a_BoundingBoxHeight = 2,
int a_MaxUp = 1, int a_MaxDown = 1
@@ -69,7 +62,7 @@ public:
~cPath();
/** Performs part of the path calculation and returns true if the path computation has finished. */
- ePathFinderStatus Step();
+ ePathFinderStatus Step(cChunk * a_Chunk);
/* Point retrieval functions, inlined for performance. */
/** Returns the next point in the path. */
@@ -147,15 +140,9 @@ private:
std::vector<Vector3d> m_PathPoints;
void AddPoint(Vector3d a_Vector);
- /* Interfacing with MCServer's world */
- cWorld * m_World;
- #ifndef COMPILING_PATHFIND_DEBUGGER
- Vector3d m_Item_CurrentBlock; // Read by Item();, it's the only way to "pass it" parameters
-protected:
- virtual bool Item(cChunk * a_Chunk) override;
-
- /* Interfacing with Irrlicht, has nothing to do with MCServer*/
- #else
+ /* Interfacing with the world */
+ cChunk * m_Chunk; // Only valid inside Step()!
+ #ifdef COMPILING_PATHFIND_DEBUGGER
#include "../path_irrlicht.cpp"
#endif
};
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index ef049f8d4..f99404669 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -48,26 +48,6 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cSkeleton::MoveToPosition(const Vector3d & a_Position)
-{
- // Todo use WouldBurnAt(), not sure how to obtain a chunk though...
- super::MoveToPosition(a_Position); // Look at the player and update m_Destination to hit them if they're close
-
- // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire AND we weren't attacked recently then block the movement
- if (
- !IsOnFire() &&
- (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8) &&
- m_TicksSinceLastDamaged == 100
- )
- {
- StopMovingToPosition();
- }
-}
-
-
-
-
-
void cSkeleton::Attack(std::chrono::milliseconds a_Dt)
{
m_AttackInterval += (static_cast<float>(a_Dt.count()) / 1000) * m_AttackRate;
diff --git a/src/Mobs/Skeleton.h b/src/Mobs/Skeleton.h
index 9c49c52fb..1b6ce4bf2 100644
--- a/src/Mobs/Skeleton.h
+++ b/src/Mobs/Skeleton.h
@@ -11,19 +11,18 @@ class cSkeleton :
public cAggressiveMonster
{
typedef cAggressiveMonster super;
-
+
public:
cSkeleton(bool IsWither);
CLASS_PROTODEF(cSkeleton)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
- virtual void MoveToPosition(const Vector3d & a_Position) override;
virtual void Attack(std::chrono::milliseconds a_Dt) override;
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual bool IsUndead(void) override { return true; }
-
+
bool IsWither(void) const { return m_bIsWither; }
private:
diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp
index b2738050e..fa4ac855d 100644
--- a/src/Mobs/Zombie.cpp
+++ b/src/Mobs/Zombie.cpp
@@ -37,27 +37,3 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
AddRandomArmorDropItem(a_Drops, LootingLevel);
AddRandomWeaponDropItem(a_Drops, LootingLevel);
}
-
-
-
-
-
-void cZombie::MoveToPosition(const Vector3d & a_Position)
-{
- // Todo use WouldBurnAt(), not sure how to obtain a chunk though...
- super::MoveToPosition(a_Position); // Look at the player and update m_Destination to hit them if they're close
-
- // If the destination is sufficiently skylight challenged AND the skeleton isn't on fire AND we weren't attacked recently then block the movement
- if (
- !IsOnFire() &&
- (m_World->GetBlockSkyLight((int)floor(a_Position.x), (int)floor(a_Position.y), (int)floor(a_Position.z)) - m_World->GetSkyDarkness() > 8) &&
- m_TicksSinceLastDamaged == 100
- )
- {
- StopMovingToPosition();
- }
-}
-
-
-
-
diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h
index 809c2a6fe..47a9f1904 100644
--- a/src/Mobs/Zombie.h
+++ b/src/Mobs/Zombie.h
@@ -10,17 +10,15 @@ class cZombie :
public cAggressiveMonster
{
typedef cAggressiveMonster super;
-
+
public:
cZombie(bool a_IsVillagerZombie);
CLASS_PROTODEF(cZombie)
-
- virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
- virtual void MoveToPosition(const Vector3d & a_Position) override;
+ virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual bool IsUndead(void) override { return true; }
-
+
bool IsVillagerZombie(void) const { return m_IsVillagerZombie; }
bool IsConverting (void) const { return m_IsConverting; }