summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@outlook.com>2020-12-18 21:48:32 +0100
committerTiger Wang <ziwei.tiger@outlook.com>2020-12-21 14:52:23 +0100
commit47c0b48bfd5df90cf889574c5634542d2aaa8873 (patch)
treea45252c6fa1add902671ea07eebf2bd49f0bec85
parentChunk: use FAST_FLOOR_DIV (diff)
downloadcuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar.gz
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar.bz2
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar.lz
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar.xz
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.tar.zst
cuberite-47c0b48bfd5df90cf889574c5634542d2aaa8873.zip
-rw-r--r--src/Mobs/AggressiveMonster.cpp25
-rw-r--r--src/Mobs/Enderman.cpp20
-rw-r--r--src/Mobs/Enderman.h1
-rw-r--r--src/Mobs/Monster.cpp97
-rw-r--r--src/Mobs/Monster.h3
-rw-r--r--src/Mobs/PassiveAggressiveMonster.cpp2
-rw-r--r--src/Mobs/PassiveMonster.cpp2
-rw-r--r--src/Mobs/Spider.cpp5
8 files changed, 92 insertions, 63 deletions
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index a904ac2da..17912a090 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -38,11 +38,6 @@ void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt, cChunk &
void cAggressiveMonster::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
{
- if (!a_Player->CanMobsTarget())
- {
- return;
- }
-
Super::EventSeePlayer(a_Player, a_Chunk);
m_EMState = CHASING;
}
@@ -60,27 +55,25 @@ void cAggressiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
return;
}
+ // Set or clear m_Target depending on rules for this Monster:
if (m_EMState == CHASING)
{
- CheckEventLostPlayer();
+ CheckEventLostPlayer(a_Dt);
}
else
{
CheckEventSeePlayer(a_Chunk);
}
- auto target = GetTarget();
- if (target == nullptr)
- {
- return;
- }
-
- // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
- Vector3d MyHeadPosition = GetPosition() + Vector3d(0, GetHeight(), 0);
- Vector3d TargetPosition = target->GetPosition() + Vector3d(0, target->GetHeight(), 0);
if (
+ (GetTarget() != nullptr) &&
TargetIsInRange() &&
- cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetPosition, cLineBlockTracer::losAirWaterLava) &&
+ cLineBlockTracer::LineOfSightTrace(
+ *GetWorld(),
+ GetPosition().addedY(GetHeight()),
+ GetTarget()->GetPosition().addedY(GetTarget()->GetHeight()),
+ cLineBlockTracer::losAirWaterLava // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
+ ) &&
(GetHealth() > 0.0)
)
{
diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp
index 3b8cd77e5..302593183 100644
--- a/src/Mobs/Enderman.cpp
+++ b/src/Mobs/Enderman.cpp
@@ -113,14 +113,8 @@ void cEnderman::CheckEventSeePlayer(cChunk & a_Chunk)
ASSERT(Callback.GetPlayer() != nullptr);
- if (!Callback.GetPlayer()->CanMobsTarget())
- {
- return;
- }
-
- // Target the player
- cMonster::EventSeePlayer(Callback.GetPlayer(), a_Chunk);
- m_EMState = CHASING;
+ // Target the player:
+ cAggressiveMonster::EventSeePlayer(Callback.GetPlayer(), a_Chunk);
m_bIsScreaming = true;
GetWorld()->BroadcastEntityMetadata(*this);
}
@@ -129,16 +123,6 @@ void cEnderman::CheckEventSeePlayer(cChunk & a_Chunk)
-void cEnderman::CheckEventLostPlayer(void)
-{
- Super::CheckEventLostPlayer();
- EventLosePlayer();
-}
-
-
-
-
-
void cEnderman::EventLosePlayer()
{
Super::EventLosePlayer();
diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h
index fa3b0d06b..a4864a7f1 100644
--- a/src/Mobs/Enderman.h
+++ b/src/Mobs/Enderman.h
@@ -20,7 +20,6 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual void CheckEventSeePlayer(cChunk & a_Chunk) override;
- virtual void CheckEventLostPlayer(void) override;
virtual void EventLosePlayer(void) override;
virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index b1975368d..048393e67 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -2,6 +2,7 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "IncludeAllMonsters.h"
+#include "LineBlockTracer.h"
#include "../BlockInfo.h"
#include "../Root.h"
#include "../Server.h"
@@ -306,19 +307,6 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{
++m_TicksSinceLastDamaged;
}
- if ((GetTarget() != nullptr))
- {
- ASSERT(GetTarget()->IsTicking());
-
- if (GetTarget()->IsPlayer())
- {
- if (!static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
- {
- SetTarget(nullptr);
- m_EMState = IDLE;
- }
- }
- }
// Process the undead burning in daylight.
HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk));
@@ -764,29 +752,94 @@ void cMonster::OnRightClicked(cPlayer & a_Player)
// monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(cChunk & a_Chunk)
{
- m_World->DoWithNearestPlayer(GetPosition(), static_cast<float>(m_SightDistance), [&](cPlayer & a_Player) -> bool
+ if (GetTarget() != nullptr)
{
- EventSeePlayer(&a_Player, a_Chunk);
- return true;
- }, true);
+ return;
+ }
+
+ cPlayer * TargetPlayer = nullptr;
+ double ClosestDistance = m_SightDistance * m_SightDistance;
+ const auto MyHeadPosition = GetPosition().addedY(GetHeight());
+
+ // Enumerate all players within sight:
+ m_World->ForEachEntityInBox({ GetPosition(), m_SightDistance * 2.0 }, [this, &TargetPlayer, &ClosestDistance, MyHeadPosition](cEntity & a_Entity)
+ {
+ if (!a_Entity.IsPlayer())
+ {
+ // Continue iteration:
+ return false;
+ }
+
+ const auto Player = static_cast<cPlayer *>(&a_Entity);
+
+ if (!Player->CanMobsTarget())
+ {
+ return false;
+ }
+
+ const auto TargetHeadPosition = a_Entity.GetPosition().addedY(a_Entity.GetHeight());
+ const auto TargetDistance = (TargetHeadPosition - MyHeadPosition).SqrLength();
+
+ // TODO: Currently all mobs see through lava, but only Nether-native mobs should be able to.
+ if (
+ (TargetDistance < ClosestDistance) &&
+ cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava)
+ )
+ {
+ TargetPlayer = Player;
+ ClosestDistance = TargetDistance;
+ }
+
+ return false;
+ });
+
+ // Target him if suitable player found:
+ if (TargetPlayer != nullptr)
+ {
+ EventSeePlayer(TargetPlayer, a_Chunk);
+ }
}
-void cMonster::CheckEventLostPlayer(void)
+void cMonster::CheckEventLostPlayer(const std::chrono::milliseconds a_Dt)
{
- if (GetTarget() != nullptr)
+ const auto Target = GetTarget();
+
+ if (Target == nullptr)
+ {
+ return;
+ }
+
+ // Check if the player died, is in creative mode, etc:
+ if (Target->IsPlayer() && !static_cast<cPlayer *>(Target)->CanMobsTarget())
{
- if ((GetTarget()->GetPosition() - GetPosition()).Length() > m_SightDistance)
+ EventLosePlayer();
+ return;
+ }
+
+ // Check if the target is too far away:
+ if (!Target->GetBoundingBox().DoesIntersect({ GetPosition(), m_SightDistance * 2.0 }))
+ {
+ EventLosePlayer();
+ return;
+ }
+
+ const auto MyHeadPosition = GetPosition().addedY(GetHeight());
+ const auto TargetHeadPosition = Target->GetPosition().addedY(Target->GetHeight());
+ if (!cLineBlockTracer::LineOfSightTrace(*GetWorld(), MyHeadPosition, TargetHeadPosition, cLineBlockTracer::losAirWaterLava))
+ {
+ if ((m_LoseSightAbandonTargetTimer += a_Dt) > std::chrono::seconds(4))
{
EventLosePlayer();
}
}
else
{
- EventLosePlayer();
+ // Subtract the amount of time we "handled" instead of setting to zero, so we don't ignore a large a_Dt of say, 8s:
+ m_LoseSightAbandonTargetTimer -= std::min(std::chrono::milliseconds(4000), m_LoseSightAbandonTargetTimer);
}
}
@@ -809,7 +862,9 @@ void cMonster::EventSeePlayer(cPlayer * a_SeenPlayer, cChunk & a_Chunk)
void cMonster::EventLosePlayer(void)
{
SetTarget(nullptr);
+
m_EMState = IDLE;
+ m_LoseSightAbandonTargetTimer = std::chrono::seconds::zero();
}
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index edd0a96c3..aeb8a3bf9 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -117,7 +117,7 @@ public:
virtual bool IsUndead(void);
virtual void EventLosePlayer(void);
- virtual void CheckEventLostPlayer(void);
+ virtual void CheckEventLostPlayer(std::chrono::milliseconds a_Dt);
virtual void InStateIdle (std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
virtual void InStateChasing (std::chrono::milliseconds a_Dt, cChunk & a_Chunk);
@@ -313,6 +313,7 @@ protected:
double m_AttackRange;
int m_AttackCoolDownTicksLeft;
int m_SightDistance;
+ std::chrono::milliseconds m_LoseSightAbandonTargetTimer;
float m_DropChanceWeapon;
float m_DropChanceHelmet;
diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp
index bf4a3167c..d96b87566 100644
--- a/src/Mobs/PassiveAggressiveMonster.cpp
+++ b/src/Mobs/PassiveAggressiveMonster.cpp
@@ -26,7 +26,7 @@ bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
return false;
}
- if ((GetTarget() != nullptr) && (GetTarget()->IsPlayer()))
+ if ((GetTarget() != nullptr) && GetTarget()->IsPlayer())
{
if (static_cast<cPlayer *>(GetTarget())->CanMobsTarget())
{
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
index 1843ceb73..e9c4070db 100644
--- a/src/Mobs/PassiveMonster.cpp
+++ b/src/Mobs/PassiveMonster.cpp
@@ -57,7 +57,7 @@ void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
if (m_EMState == ESCAPING)
{
- CheckEventLostPlayer();
+ CheckEventLostPlayer(a_Dt);
}
cMonster::LoveTick();
diff --git a/src/Mobs/Spider.cpp b/src/Mobs/Spider.cpp
index be8196cea..3677411f6 100644
--- a/src/Mobs/Spider.cpp
+++ b/src/Mobs/Spider.cpp
@@ -48,10 +48,7 @@ void cSpider::EventSeePlayer(cPlayer * a_Player, cChunk & a_Chunk)
return;
}
- if (
- a_Player->CanMobsTarget() &&
- !((Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) > 11) || (Chunk->GetBlockLight(Rel.x, Rel.y, Rel.z) > 11))
- )
+ if ((Chunk->GetSkyLightAltered(Rel.x, Rel.y, Rel.z) <= 11) && (Chunk->GetBlockLight(Rel.x, Rel.y, Rel.z) <= 11))
{
Super::EventSeePlayer(a_Player, a_Chunk);
}