From b8aa38b18d7f7ab78766d2be94e8738e503bacca Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 17:23:07 +0300 Subject: (duplicate) AI - Livestock escape fixed, water jumping fixed --- src/Mobs/Monster.cpp | 78 ++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 9 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 37774b08f..df9c1f390 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -156,6 +156,11 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk) if (m_Path == nullptr) { + if (!EnsureProperDestination(a_Chunk)) + { + StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement. + return false; + } m_PathFinderDestination = m_FinalDestination; m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20); } @@ -199,10 +204,12 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) { if (m_JumpCoolDown == 0) { - // We're not moving (or barely moving), and waypoint is above us, it means we are hitting something and we should jump. - if ((GetSpeedX() < 0.1) && (GetSpeedZ() < 0.1) && DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) + if (DoesPosYRequireJump(FloorC(m_NextWayPointPosition.y))) { - if (IsOnGround() || IsSwimming()) + if ( + (IsOnGround() && (GetSpeedX() == 0) && (GetSpeedY() == 0)) || + (IsSwimming() && (m_GiveUpCounter < 15)) + ) { m_bOnGround = false; m_JumpCoolDown = 20; @@ -252,6 +259,63 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) +bool cMonster::EnsureProperDestination(cChunk & a_Chunk) +{ + cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + if ((Chunk == nullptr) || !Chunk->IsValid()) + { + return false; + } + + // If destination in the air, go down to the lowest air block. + while (m_FinalDestination.y > 0) + { + Chunk->GetBlockTypeMeta(RelX, 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. + bool InWater = false; + while (m_FinalDestination.y < cChunkDef::Height) + { + Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y, RelZ, BlockType, BlockMeta); + if (BlockType == E_BLOCK_STATIONARY_WATER) + { + InWater = true; + } + else if (cBlockInfo::IsSolid(BlockType)) + { + InWater = false; + } + else + { + break; + } + m_FinalDestination.y += 1; + } + if (InWater) + { + m_FinalDestination.y -= 1; + } + + + return true; +} + + + + + void cMonster::MoveToPosition(const Vector3d & a_Position) { m_FinalDestination = a_Position; @@ -292,7 +356,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) if (m_Health <= 0) { - // The mob is dead, but we're still animating the "puff" they leave when they die + // The mob is dead, but we're still animating the "puff" they leave when they die. m_DestroyTimer += a_Dt; if (m_DestroyTimer > std::chrono::seconds(1)) { @@ -310,7 +374,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) m_Target = nullptr; } - // Process the undead burning in daylight + // Process the undead burning in daylight. HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk)); if (TickPathFinding(*Chunk)) { @@ -1121,7 +1185,3 @@ cMonster::eFamily cMonster::GetMobFamily(void) const { return FamilyFromType(m_MobType); } - - - - -- cgit v1.2.3 From 753dfb950a6ec880af47ac7c1b0d6d142a138eac Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 16:52:37 +0300 Subject: AI - Better shade cover --- src/Mobs/Monster.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index df9c1f390..c799e9394 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -378,7 +378,15 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk)); if (TickPathFinding(*Chunk)) { - if (m_BurnsInDaylight && WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && !IsOnFire() && (m_TicksSinceLastDamaged == 100)) + /* If I burn in daylight, and I won't burn where I'm standing, and I'll burn in my next position, and at least one of those is true: + 1. I am idle + 2. I was not hurt by a player recently. + Then STOP. */ + if ( + m_BurnsInDaylight && ((m_TicksSinceLastDamaged == 100) || (m_EMState == IDLE)) && + WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && + !WouldBurnAt(GetPosition(), *Chunk->GetNeighborChunk(FloorC(GetPosition().x), FloorC(GetPosition().z))) + ) { // 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(); -- cgit v1.2.3 From 40af96b100e88faaad451028856c46b0ba15de11 Mon Sep 17 00:00:00 2001 From: wiseoldman95 Date: Wed, 6 May 2015 17:02:50 +0300 Subject: AI - Safer WouldBurnAt() --- src/Mobs/Monster.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index c799e9394..84f58ff85 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -383,9 +383,9 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) 2. I was not hurt by a player recently. Then STOP. */ if ( - m_BurnsInDaylight && ((m_TicksSinceLastDamaged == 100) || (m_EMState == IDLE)) && - WouldBurnAt(m_NextWayPointPosition, *Chunk->GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z))) && - !WouldBurnAt(GetPosition(), *Chunk->GetNeighborChunk(FloorC(GetPosition().x), FloorC(GetPosition().z))) + m_BurnsInDaylight && ((m_TicksSinceLastDamaged >= 100) || (m_EMState == IDLE)) && + WouldBurnAt(m_NextWayPointPosition, *Chunk) && + !WouldBurnAt(GetPosition(), *Chunk) ) { // 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: @@ -1170,6 +1170,11 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn) bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk) { + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z)); + if ((Chunk == nullptr) || (!Chunk->IsValid())) + { + return false; + } int RelX = FloorC(a_Location.x) - a_Chunk.GetPosX() * cChunkDef::Width; int RelY = FloorC(a_Location.y); int RelZ = FloorC(a_Location.z) - a_Chunk.GetPosZ() * cChunkDef::Width; -- cgit v1.2.3 From 9f6192687f84fc97c5f854c778f3b393965794ef Mon Sep 17 00:00:00 2001 From: Tri125 Date: Wed, 6 May 2015 23:29:36 -0400 Subject: Big Magma Cube can now spawn Following the same method as the Slime, Magma Cube can now spawn with the size of 1, 2 or 4. --- src/Mobs/Monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 37774b08f..e86570c77 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -886,7 +886,7 @@ cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType) { case mtMagmaCube: { - toReturn = new cMagmaCube(Random.NextInt(2) + 1); + toReturn = new cMagmaCube(1 << Random.NextInt(3)); // Size 1, 2 or 4 break; } case mtSlime: -- cgit v1.2.3 From 1cef39cb73f5a9130d2cb9d497ca44350fb401d8 Mon Sep 17 00:00:00 2001 From: worktycho Date: Fri, 8 May 2015 23:20:22 +0100 Subject: Move chunk position accesses after the chunk validity checks --- src/Mobs/Monster.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 84f58ff85..9df5bd930 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -264,12 +264,14 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; } + + int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; // If destination in the air, go down to the lowest air block. while (m_FinalDestination.y > 0) -- cgit v1.2.3 From 218010cd96a3e887e7fbd8e18e1b74b7dc481036 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Fri, 8 May 2015 23:32:02 +0100 Subject: Fixed some Visual Studio warnings --- src/Mobs/Monster.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index 84f58ff85..dc950ff7d 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -261,11 +261,11 @@ void cMonster::MoveToWayPoint(cChunk & a_Chunk) bool cMonster::EnsureProperDestination(cChunk & a_Chunk) { - cChunk * Chunk = a_Chunk.GetNeighborChunk(m_FinalDestination.x, m_FinalDestination.z); + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x), FloorC(m_FinalDestination.z)); BLOCKTYPE BlockType; NIBBLETYPE BlockMeta; - int RelX = m_FinalDestination.x - Chunk->GetPosX() * cChunkDef::Width; - int RelZ = m_FinalDestination.z - Chunk->GetPosZ() * cChunkDef::Width; + int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width; + int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width; if ((Chunk == nullptr) || !Chunk->IsValid()) { return false; @@ -274,7 +274,7 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) // If destination in the air, go down to the lowest air block. while (m_FinalDestination.y > 0) { - Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y - 1, RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta); if (cBlockInfo::IsSolid(BlockType)) { break; @@ -288,7 +288,7 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk) bool InWater = false; while (m_FinalDestination.y < cChunkDef::Height) { - Chunk->GetBlockTypeMeta(RelX, m_FinalDestination.y, RelZ, BlockType, BlockMeta); + Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y), RelZ, BlockType, BlockMeta); if (BlockType == E_BLOCK_STATIONARY_WATER) { InWater = true; -- cgit v1.2.3 From 11ef1fd24a48f8982ecf9c798047b0465ca839a2 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sat, 9 May 2015 01:51:25 +0100 Subject: Fixed some warnings and logic errors in Monster.cpp --- src/Mobs/Monster.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index dc950ff7d..1cc6e7391 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -1170,17 +1170,19 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk, bool WouldBurn) bool cMonster::WouldBurnAt(Vector3d a_Location, cChunk & a_Chunk) { - cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(m_NextWayPointPosition.x), FloorC(m_NextWayPointPosition.z)); + cChunk * Chunk = a_Chunk.GetNeighborChunk(FloorC(a_Location.x), FloorC(a_Location.z)); if ((Chunk == nullptr) || (!Chunk->IsValid())) { return false; } - int RelX = FloorC(a_Location.x) - a_Chunk.GetPosX() * cChunkDef::Width; + + int RelX = FloorC(a_Location.x) - Chunk->GetPosX() * cChunkDef::Width; int RelY = FloorC(a_Location.y); - int RelZ = FloorC(a_Location.z) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelZ = FloorC(a_Location.z) - Chunk->GetPosZ() * cChunkDef::Width; + if ( - (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight - (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand + (Chunk->GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight + (Chunk->GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand (GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime GetWorld()->IsWeatherSunnyAt(POSX_TOINT, POSZ_TOINT) // Not raining ) -- cgit v1.2.3 From 29e31c5be95abd6a7122a525f53d80f4576e49b2 Mon Sep 17 00:00:00 2001 From: SafwatHalaby Date: Sat, 16 May 2015 14:05:33 +0300 Subject: Pathfinder - approximated paths when original destination unreachable --- src/Mobs/Monster.cpp | 121 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 94 insertions(+), 27 deletions(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index f3f8c6b24..a29d67d15 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) @@ -147,10 +147,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,12 +166,21 @@ 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); } switch (m_Path->Step(a_Chunk)) { + case ePathFinderStatus::NEARBY_FOUND: + { + m_NoPathToTarget = true; + m_Path->AcceptNearbyPath(); + break; + } + case ePathFinderStatus::PATH_NOT_FOUND: { StopMovingToPosition(); // Give up pathfinding to that destination. @@ -179,15 +193,22 @@ 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. 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 = 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. + } + } + 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 +290,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. @@ -447,21 +506,29 @@ void cMonster::SetPitchAndYawFromDestination() } } + + + Vector3d BodyDistance = m_NextWayPointPosition - GetPosition(); + double BodyRotation, BodyPitch; + BodyDistance.Normalize(); + VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch); + SetYaw(BodyRotation); + Vector3d Distance = FinalDestination - GetPosition(); { - double Rotation, Pitch; + double HeadRotation, HeadPitch; Distance.Normalize(); - VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch); - SetHeadYaw(Rotation); - SetPitch(-Pitch); - } - - { - Vector3d BodyDistance = m_NextWayPointPosition - GetPosition(); - double Rotation, Pitch; - BodyDistance.Normalize(); - VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch); - SetYaw(Rotation); + VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); + if (abs(BodyRotation - HeadRotation) < 120) + { + 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); + } } } -- cgit v1.2.3 From d852209f8db9129a3d135a4f7034878d1438a57b Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Tue, 19 May 2015 09:29:27 +0100 Subject: Manual merge of #2066 --- src/Mobs/Monster.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Mobs/Monster.cpp') diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp index a29d67d15..2b00f6959 100644 --- a/src/Mobs/Monster.cpp +++ b/src/Mobs/Monster.cpp @@ -519,7 +519,7 @@ void cMonster::SetPitchAndYawFromDestination() double HeadRotation, HeadPitch; Distance.Normalize(); VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch); - if (abs(BodyRotation - HeadRotation) < 120) + if (std::abs(BodyRotation - HeadRotation) < 120) { SetHeadYaw(HeadRotation); SetPitch(-HeadPitch); -- cgit v1.2.3