summaryrefslogtreecommitdiffstats
path: root/src/Mobs/Monster.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs/Monster.cpp')
-rw-r--r--src/Mobs/Monster.cpp157
1 files changed, 121 insertions, 36 deletions
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index f3f8c6b24..4befe307d 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -89,7 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
, m_SoundDeath(a_SoundDeath)
, m_AttackRate(3)
, m_AttackDamage(1)
- , m_AttackRange(2)
+ , m_AttackRange(1)
, m_AttackInterval(0)
, m_SightDistance(25)
, m_DropChanceWeapon(0.085f)
@@ -101,6 +101,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
, m_TicksSinceLastDamaged(100)
, m_BurnsInDaylight(false)
, m_RelativeWalkSpeed(1)
+ , m_Age(1)
{
if (!a_ConfigName.empty())
{
@@ -147,10 +148,15 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
(Recalculate lots when close, calculate rarely when far) */
if (
((GetPosition() - m_PathFinderDestination).Length() < 0.25) ||
- ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.15 * (m_FinalDestination - GetPosition()).SqrLength())))
+ ((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - GetPosition()).SqrLength())))
)
{
- ResetPathFinding();
+ /* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating.
+ This is a workaround till we get better path recalculation. */
+ if (!m_NoPathToTarget)
+ {
+ ResetPathFinding();
+ }
}
}
@@ -161,15 +167,25 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement.
return false;
}
+ m_NoPathToTarget = false;
+ m_NoMoreWayPoints = false;
m_PathFinderDestination = m_FinalDestination;
- m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20);
+ m_Path = new cPath(a_Chunk, GetPosition(), m_PathFinderDestination, 20, GetWidth(), GetHeight());
}
switch (m_Path->Step(a_Chunk))
{
+ case ePathFinderStatus::NEARBY_FOUND:
+ {
+ m_NoPathToTarget = true;
+ m_PathFinderDestination = m_Path->AcceptNearbyPath();
+ break;
+ }
+
case ePathFinderStatus::PATH_NOT_FOUND:
{
- StopMovingToPosition(); // Give up pathfinding to that destination.
+ StopMovingToPosition(); // Try to calculate a path again.
+ // Note that the next time may succeed, e.g. if a player breaks a barrier.
break;
}
case ePathFinderStatus::CALCULATING:
@@ -179,15 +195,30 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
}
case ePathFinderStatus::PATH_FOUND:
{
- if (--m_GiveUpCounter == 0)
+ if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0))
{
- ResetPathFinding(); // Try to calculate a path again.
+ if (m_EMState == ATTACKING)
+ {
+ ResetPathFinding(); // Try to calculate a path again.
+ // This results in mobs hanging around an unreachable target (player).
+ }
+ else
+ {
+ StopMovingToPosition(); // Find a different place to go to.
+ }
return false;
}
- else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedNextWaypoint())) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?
+ else if (!m_Path->IsLastPoint()) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?
+ {
+ if ((m_Path->IsFirstPoint() || ReachedNextWaypoint()))
+ {
+ m_NextWayPointPosition = m_Path->GetNextPoint();
+ m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.
+ }
+ }
+ else
{
- m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint();
- m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.
+ m_NoMoreWayPoints = true;
}
return true;
}
@@ -269,21 +300,59 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk)
{
return false;
}
-
+
int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width;
int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width;
- // If destination in the air, go down to the lowest air block.
- while (m_FinalDestination.y > 0)
+ // If destination in the air, first try to go 1 block north, or east, or west.
+ // This fixes the player leaning issue.
+ // If that failed, we instead go down to the lowest air block.
+ Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
+ if (!cBlockInfo::IsSolid(BlockType))
{
- Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
- if (cBlockInfo::IsSolid(BlockType))
+ bool InTheAir = true;
+ int x, z;
+ for (z = -1; z <= 1; ++z)
{
- break;
+ for (x = -1; x <= 1; ++x)
+ {
+ if ((x==0) && (z==0))
+ {
+ continue;
+ }
+ Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x+x), FloorC(m_FinalDestination.z+z));
+ if ((Chunk == nullptr) || !Chunk->IsValid())
+ {
+ return false;
+ }
+ RelX = FloorC(m_FinalDestination.x+x) - Chunk->GetPosX() * cChunkDef::Width;
+ RelZ = FloorC(m_FinalDestination.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
+ Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
+ if (cBlockInfo::IsSolid(BlockType))
+ {
+ m_FinalDestination.x += x;
+ m_FinalDestination.z += z;
+ InTheAir = false;
+ goto breakBothLoops;
+ }
+ }
}
- m_FinalDestination.y -= 1;
- }
+ breakBothLoops:
+ // Go down to the lowest air block.
+ if (InTheAir)
+ {
+ while (m_FinalDestination.y > 0)
+ {
+ Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
+ if (cBlockInfo::IsSolid(BlockType))
+ {
+ break;
+ }
+ m_FinalDestination.y -= 1;
+ }
+ }
+ }
// If destination in water, go up to the highest water block.
// If destination in solid, go up to first air block.
@@ -331,6 +400,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
void cMonster::StopMovingToPosition()
{
m_IsFollowingPath = false;
+ ResetPathFinding();
}
@@ -447,21 +517,36 @@ void cMonster::SetPitchAndYawFromDestination()
}
}
- Vector3d Distance = FinalDestination - GetPosition();
+
+ Vector3d BodyDistance;
+ if (!m_IsFollowingPath && (m_Target != nullptr))
{
- double Rotation, Pitch;
- Distance.Normalize();
- VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
- SetHeadYaw(Rotation);
- SetPitch(-Pitch);
+ BodyDistance = m_Target->GetPosition() - GetPosition();
}
+ else
+ {
+ BodyDistance = m_NextWayPointPosition - GetPosition();
+ }
+ double BodyRotation, BodyPitch;
+ BodyDistance.Normalize();
+ VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch);
+ SetYaw(BodyRotation);
+ Vector3d Distance = FinalDestination - GetPosition();
{
- Vector3d BodyDistance = m_NextWayPointPosition - GetPosition();
- double Rotation, Pitch;
- BodyDistance.Normalize();
- VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
- SetYaw(Rotation);
+ double HeadRotation, HeadPitch;
+ Distance.Normalize();
+ VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch);
+ if (std::abs(BodyRotation - HeadRotation) < 90)
+ {
+ SetHeadYaw(HeadRotation);
+ SetPitch(-HeadPitch);
+ }
+ else // We're not an owl. If it's more than 120, don't look behind and instead look at where you're walking.
+ {
+ SetHeadYaw(BodyRotation);
+ SetPitch(-BodyPitch);
+ }
}
}
@@ -989,9 +1074,9 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
case mtHorse:
{
// Horses take a type (species), a colour, and a style (dots, stripes, etc.)
- int HorseType = Random.NextInt(7);
- int HorseColor = Random.NextInt(6);
- int HorseStyle = Random.NextInt(6);
+ int HorseType = Random.NextInt(8);
+ int HorseColor = Random.NextInt(7);
+ int HorseStyle = Random.NextInt(5);
int HorseTameTimes = Random.NextInt(6) + 1;
if ((HorseType == 5) || (HorseType == 6) || (HorseType == 7))
@@ -1070,10 +1155,10 @@ void cMonster::AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short
-void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel)
+void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, unsigned int a_LootingLevel)
{
MTRand r1;
- int Count = r1.randInt() % 200;
+ unsigned int Count = r1.randInt() % 200;
if (Count < (5 + a_LootingLevel))
{
int Rare = r1.randInt() % a_Items.Size();
@@ -1085,7 +1170,7 @@ void cMonster::AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a
-void cMonster::AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel)
+void cMonster::AddRandomArmorDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
{
MTRand r1;
if (r1.randInt() % 200 < ((m_DropChanceHelmet * 200) + (a_LootingLevel * 2)))
@@ -1125,7 +1210,7 @@ void cMonster::AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel)
-void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel)
+void cMonster::AddRandomWeaponDropItem(cItems & a_Drops, unsigned int a_LootingLevel)
{
MTRand r1;
if (r1.randInt() % 200 < ((m_DropChanceWeapon * 200) + (a_LootingLevel * 2)))