summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/MobSpawner.cpp10
-rw-r--r--src/Mobs/Blaze.cpp59
-rw-r--r--src/Mobs/Blaze.h9
-rw-r--r--src/Mobs/Ghast.cpp80
-rw-r--r--src/Mobs/Ghast.h15
-rw-r--r--src/Mobs/Monster.cpp2
6 files changed, 149 insertions, 26 deletions
diff --git a/src/MobSpawner.cpp b/src/MobSpawner.cpp
index 5cb8f0d33..0869e7282 100644
--- a/src/MobSpawner.cpp
+++ b/src/MobSpawner.cpp
@@ -123,7 +123,6 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
}
case mtBlaze:
- case mtGhast:
{
return (
(targetBlock == E_BLOCK_AIR) &&
@@ -194,6 +193,15 @@ bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, Vector3i a_RelPos, eMonsterType
break;
}
+ case mtGhast:
+ {
+ return (
+ (targetBlock == E_BLOCK_AIR) &&
+ (blockAbove == E_BLOCK_AIR) &&
+ (random.RandBool())
+ );
+ }
+
case mtGuardian:
{
return (
diff --git a/src/Mobs/Blaze.cpp b/src/Mobs/Blaze.cpp
index 80a887b03..1c48a88d2 100644
--- a/src/Mobs/Blaze.cpp
+++ b/src/Mobs/Blaze.cpp
@@ -9,7 +9,9 @@
cBlaze::cBlaze(void) :
- super("Blaze", mtBlaze, "entity.blaze.hurt", "entity.blaze.death", "entity.blaze.ambient", 0.6, 1.8)
+ super("Blaze", mtBlaze, "entity.blaze.hurt", "entity.blaze.death", "entity.blaze.ambient", 0.6, 1.8),
+ m_IsCharging(false),
+ m_ChargeTimer(0)
{
SetGravity(-8.0f);
SetAirDrag(0.05f);
@@ -34,23 +36,54 @@ void cBlaze::GetDrops(cItems & a_Drops, cEntity * a_Killer)
bool cBlaze::Attack(std::chrono::milliseconds a_Dt)
{
- if ((GetTarget() != nullptr) && (m_AttackCoolDownTicksLeft == 0))
+ if ((GetTarget() != nullptr) && (m_AttackCoolDownTicksLeft == 0) && (!m_IsCharging))
{
- // Setting this higher gives us more wiggle room for attackrate
- Vector3d Speed = GetLookVector() * 20;
- Speed.y = Speed.y + 1;
+ m_IsCharging = true;
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+void cBlaze::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ if (!IsTicking())
+ {
+ // The base class tick destroyed us
+ return;
+ }
- auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosition().addedY(1), Speed);
- auto FireChargePtr = FireCharge.get();
- if (!FireChargePtr->Initialize(std::move(FireCharge), *m_World))
+ if (m_IsCharging)
+ {
+ m_ChargeTimer++;
+ if (
+ (m_ChargeTimer == 5) ||
+ (m_ChargeTimer == 10) ||
+ (m_ChargeTimer == 15)
+ )
{
- return false;
+ Vector3d Speed = GetLookVector() * 20;
+ Speed.y = Speed.y + 1;
+
+ auto FireCharge = cpp14::make_unique<cFireChargeEntity>(this, GetPosition().addedY(1), Speed);
+ auto FireChargePtr = FireCharge.get();
+ FireChargePtr->Initialize(std::move(FireCharge), *m_World);
+
+ m_World->BroadcastSoundEffect("entity.ghast.shoot", GetPosition(), 4.0f, 1.0f);
}
+ }
+ if ((m_IsCharging) && (m_ChargeTimer > 15))
+ {
+ m_ChargeTimer = 0;
+ m_IsCharging = false;
ResetAttackCooldown();
- // ToDo: Shoot 3 fireballs instead of 1.
-
- return true;
}
- return false;
}
+
+
+
diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h
index ca755b626..3e6726efa 100644
--- a/src/Mobs/Blaze.h
+++ b/src/Mobs/Blaze.h
@@ -17,6 +17,15 @@ public:
CLASS_PROTODEF(cBlaze)
+ virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual bool Attack(std::chrono::milliseconds a_Dt) override;
+
+private:
+ /** Specifies whether or not the blaze has started shooting fireballs. */
+ bool m_IsCharging;
+
+ /** Number of ticks since the blaze started charging.
+ Used to create 3 successive projectiles. */
+ int m_ChargeTimer;
} ;
diff --git a/src/Mobs/Ghast.cpp b/src/Mobs/Ghast.cpp
index 2f1f2cf8b..40a7bdf0f 100644
--- a/src/Mobs/Ghast.cpp
+++ b/src/Mobs/Ghast.cpp
@@ -9,8 +9,13 @@
cGhast::cGhast(void) :
- super("Ghast", mtGhast, "entity.ghast.hurt", "entity.ghast.death", "entity.ghast.ambient", 4, 4)
+ super("Ghast", mtGhast, "entity.ghast.hurt", "entity.ghast.death", "entity.ghast.ambient", 4, 4),
+ m_IsCharging(false),
+ m_FlightCooldown(5),
+ m_TicksUntilShot(10)
{
+ SetGravity(0);
+ SetAirDrag(0);
}
@@ -34,24 +39,79 @@ void cGhast::GetDrops(cItems & a_Drops, cEntity * a_Killer)
bool cGhast::Attack(std::chrono::milliseconds a_Dt)
{
- if ((GetTarget() != nullptr) && (m_AttackCoolDownTicksLeft == 0))
+ if ((GetTarget() != nullptr) && (m_AttackCoolDownTicksLeft == 0) && (!m_IsCharging))
{
- // Setting this higher gives us more wiggle room for attackrate
+ auto & Random = GetRandomProvider();
+ auto SoundPitchMultiplier = 1.0f + (Random.RandReal(1.0f) - Random.RandReal(1.0f)) * 0.2f;
+
+ m_World->BroadcastSoundEffect("entity.ghast.warn", GetPosition(), 4.0f, SoundPitchMultiplier * 0.9f);
+ m_IsCharging = true;
+ m_World->BroadcastEntityMetadata(*this);
+ return true;
+ }
+ return false;
+}
+
+
+
+
+
+bool cGhast::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ // No fall damage
+ if (a_TDI.DamageType == dtFalling)
+ {
+ return false;
+ }
+
+ return super::DoTakeDamage(a_TDI);
+}
+
+
+
+
+
+void cGhast::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+ if (!IsTicking())
+ {
+ // The base class tick destroyed us
+ return;
+ }
+
+ if ((m_IsCharging) && (m_TicksUntilShot-- == 0))
+ {
+ m_TicksUntilShot = 10;
+ m_IsCharging = false;
+ m_World->BroadcastEntityMetadata(*this);
+
Vector3d Speed = GetLookVector() * 20;
Speed.y = Speed.y + 1;
- auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosition().addedY(1), Speed);
+ auto GhastBall = cpp14::make_unique<cGhastFireballEntity>(this, GetPosition(), Speed);
auto GhastBallPtr = GhastBall.get();
- if (!GhastBallPtr->Initialize(std::move(GhastBall), *m_World))
+ GhastBallPtr->Initialize(std::move(GhastBall), *m_World);
+
+ m_World->BroadcastSoundEffect("entity.ghast.shoot", GetPosition(), 4.0f, 1.0f);
+
+ ResetAttackCooldown();
+ }
+
+ // TODO: Better flying
+ if (m_FlightCooldown-- == 0)
+ {
+ m_FlightCooldown = 5;
+ auto & Random = GetRandomProvider();
+ auto SpeedVector = Vector3d(Random.RandReal(-0.3, 0.3), Random.RandReal(-0.4, 0.4), Random.RandReal(-0.3, 0.3));
+
+ if (GetPosY() > 120)
{
- return false;
+ SpeedVector = Vector3d(Random.RandReal(-0.4, 0.4), Random.RandReal(-0.45, 0.4), Random.RandReal(-0.4, 0.4));
}
- ResetAttackCooldown();
- return true;
+ AddSpeed(SpeedVector);
}
- return false;
}
-
diff --git a/src/Mobs/Ghast.h b/src/Mobs/Ghast.h
index a41a72ddc..7312b25c9 100644
--- a/src/Mobs/Ghast.h
+++ b/src/Mobs/Ghast.h
@@ -17,10 +17,23 @@ public:
CLASS_PROTODEF(cGhast)
+ virtual void Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = nullptr) override;
virtual bool Attack(std::chrono::milliseconds a_Dt) override;
+ virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
- bool IsCharging(void) const {return false; }
+ bool IsCharging(void) const { return m_IsCharging; }
+
+private:
+ /** Specifies whether or not the ghast has started shooting a fireball. */
+ bool m_IsCharging;
+
+ /** Number of ticks until the ghast tries to fly to another position. */
+ int m_FlightCooldown;
+
+ /** Number of ticks until a projectile is created.
+ Only used while m_IsCharging is true. */
+ int m_TicksUntilShot;
} ;
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 9a826ed21..7c57e4f2d 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -313,7 +313,7 @@ void cMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
HandleDaylightBurning(*Chunk, WouldBurnAt(GetPosition(), *Chunk));
bool a_IsFollowingPath = false;
- if (m_PathfinderActivated)
+ if (m_PathfinderActivated && (GetMobType() != mtGhast)) // Pathfinder is currently disabled for ghasts, which have their own flying mechanism
{
if (ReachedFinalDestination() || (m_LeashToPos != nullptr))
{