summaryrefslogtreecommitdiffstats
path: root/src/Mobs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs')
-rw-r--r--src/Mobs/AggressiveMonster.cpp12
-rw-r--r--src/Mobs/Bat.h2
-rw-r--r--src/Mobs/Blaze.h2
-rw-r--r--src/Mobs/CMakeLists.txt76
-rw-r--r--src/Mobs/CaveSpider.cpp15
-rw-r--r--src/Mobs/CaveSpider.h3
-rw-r--r--src/Mobs/Chicken.h2
-rw-r--r--src/Mobs/Cow.h2
-rw-r--r--src/Mobs/Creeper.cpp8
-rw-r--r--src/Mobs/Creeper.h2
-rw-r--r--src/Mobs/EnderDragon.h2
-rw-r--r--src/Mobs/Enderman.cpp149
-rw-r--r--src/Mobs/Enderman.h8
-rw-r--r--src/Mobs/Ghast.h2
-rw-r--r--src/Mobs/Giant.h2
-rw-r--r--src/Mobs/Horse.cpp2
-rw-r--r--src/Mobs/Horse.h2
-rw-r--r--src/Mobs/IronGolem.h4
-rw-r--r--src/Mobs/MagmaCube.h2
-rw-r--r--src/Mobs/Monster.cpp110
-rw-r--r--src/Mobs/Monster.h39
-rw-r--r--src/Mobs/Mooshroom.h2
-rw-r--r--src/Mobs/Ocelot.h2
-rw-r--r--src/Mobs/Pig.h2
-rw-r--r--src/Mobs/Sheep.cpp59
-rw-r--r--src/Mobs/Sheep.h21
-rw-r--r--src/Mobs/Silverfish.h2
-rw-r--r--src/Mobs/Skeleton.cpp17
-rw-r--r--src/Mobs/Skeleton.h10
-rw-r--r--src/Mobs/Slime.cpp76
-rw-r--r--src/Mobs/Slime.h15
-rw-r--r--src/Mobs/SnowGolem.cpp2
-rw-r--r--src/Mobs/SnowGolem.h2
-rw-r--r--src/Mobs/Spider.h2
-rw-r--r--src/Mobs/Squid.h2
-rw-r--r--src/Mobs/Villager.cpp6
-rw-r--r--src/Mobs/Villager.h7
-rw-r--r--src/Mobs/Witch.h2
-rw-r--r--src/Mobs/Wither.cpp4
-rw-r--r--src/Mobs/Wither.h6
-rw-r--r--src/Mobs/Wolf.cpp14
-rw-r--r--src/Mobs/Wolf.h12
-rw-r--r--src/Mobs/Zombie.cpp2
-rw-r--r--src/Mobs/Zombie.h10
-rw-r--r--src/Mobs/ZombiePigman.cpp6
-rw-r--r--src/Mobs/ZombiePigman.h6
46 files changed, 567 insertions, 168 deletions
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 85b122034..5f5b1853d 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -42,7 +42,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt)
MoveToPosition(m_Target->GetPosition());
}
}
-}
+}
@@ -95,12 +95,14 @@ void cAggressiveMonster::Attack(float a_Dt)
{
m_AttackInterval += a_Dt * m_AttackRate;
- if ((m_Target != NULL) && (m_AttackInterval > 3.0))
+ if ((m_Target == NULL) || (m_AttackInterval < 3.0))
{
- // Setting this higher gives us more wiggle room for attackrate
- m_AttackInterval = 0.0;
- m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
+ return;
}
+
+ // Setting this higher gives us more wiggle room for attackrate
+ m_AttackInterval = 0.0;
+ m_Target->TakeDamage(dtMobAttack, this, m_AttackDamage, 0);
}
diff --git a/src/Mobs/Bat.h b/src/Mobs/Bat.h
index e878d0ee8..6b06aeb4f 100644
--- a/src/Mobs/Bat.h
+++ b/src/Mobs/Bat.h
@@ -15,7 +15,7 @@ class cBat :
public:
cBat(void);
- CLASS_PROTODEF(cBat);
+ CLASS_PROTODEF(cBat)
bool IsHanging(void) const {return false; }
} ;
diff --git a/src/Mobs/Blaze.h b/src/Mobs/Blaze.h
index 5970451c7..f283b1070 100644
--- a/src/Mobs/Blaze.h
+++ b/src/Mobs/Blaze.h
@@ -15,7 +15,7 @@ class cBlaze :
public:
cBlaze(void);
- CLASS_PROTODEF(cBlaze);
+ CLASS_PROTODEF(cBlaze)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Attack(float a_Dt) override;
diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt
index 90294631e..23bcadaa6 100644
--- a/src/Mobs/CMakeLists.txt
+++ b/src/Mobs/CMakeLists.txt
@@ -4,10 +4,76 @@ project (MCServer)
include_directories ("${PROJECT_SOURCE_DIR}/../")
-file(GLOB SOURCE
- "*.cpp"
- "*.h"
-)
+SET (SRCS
+ AggressiveMonster.cpp
+ Bat.cpp
+ Blaze.cpp
+ CaveSpider.cpp
+ Chicken.cpp
+ Cow.cpp
+ Creeper.cpp
+ EnderDragon.cpp
+ Enderman.cpp
+ Ghast.cpp
+ Giant.cpp
+ Horse.cpp
+ IronGolem.cpp
+ MagmaCube.cpp
+ Monster.cpp
+ Mooshroom.cpp
+ PassiveAggressiveMonster.cpp
+ PassiveMonster.cpp
+ Pig.cpp
+ Sheep.cpp
+ Skeleton.cpp
+ Slime.cpp
+ SnowGolem.cpp
+ Spider.cpp
+ Squid.cpp
+ Villager.cpp
+ Witch.cpp
+ Wither.cpp
+ Wolf.cpp
+ Zombie.cpp
+ ZombiePigman.cpp)
+
+SET (HDRS
+ AggressiveMonster.h
+ Bat.h
+ Blaze.h
+ CaveSpider.h
+ Chicken.h
+ Cow.h
+ Creeper.h
+ EnderDragon.h
+ Enderman.h
+ Ghast.h
+ Giant.h
+ Horse.h
+ IncludeAllMonsters.h
+ IronGolem.h
+ MagmaCube.h
+ Monster.h
+ Mooshroom.h
+ Ocelot.h
+ PassiveAggressiveMonster.h
+ PassiveMonster.h
+ Pig.h
+ Sheep.h
+ Silverfish.h
+ Skeleton.h
+ Slime.h
+ SnowGolem.h
+ Spider.h
+ Squid.h
+ Villager.h
+ Witch.h
+ Wither.h
+ Wolf.h
+ Zombie.h
+ ZombiePigman.h)
-add_library(Mobs ${SOURCE})
+if(NOT MSVC)
+ add_library(Mobs ${SRCS} ${HDRS})
+endif()
add_subdirectory(Components)
diff --git a/src/Mobs/CaveSpider.cpp b/src/Mobs/CaveSpider.cpp
index 1157b81f9..118a6e93b 100644
--- a/src/Mobs/CaveSpider.cpp
+++ b/src/Mobs/CaveSpider.cpp
@@ -27,6 +27,21 @@ void cCaveSpider::Tick(float a_Dt, cChunk & a_Chunk)
+void cCaveSpider::Attack(float a_Dt)
+{
+ super::Attack(a_Dt);
+
+ if (m_Target->IsPawn())
+ {
+ // TODO: Easy = no poison, Medium = 7 seconds, Hard = 15 seconds
+ ((cPawn *) m_Target)->AddEntityEffect(cEntityEffect::effPoison, 7 * 20, 0);
+ }
+}
+
+
+
+
+
void cCaveSpider::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
int LootingLevel = 0;
diff --git a/src/Mobs/CaveSpider.h b/src/Mobs/CaveSpider.h
index be9f174f9..f9ed10e1b 100644
--- a/src/Mobs/CaveSpider.h
+++ b/src/Mobs/CaveSpider.h
@@ -14,9 +14,10 @@ class cCaveSpider :
public:
cCaveSpider(void);
- CLASS_PROTODEF(cCaveSpider);
+ CLASS_PROTODEF(cCaveSpider)
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void Attack(float a_Dt) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;
diff --git a/src/Mobs/Chicken.h b/src/Mobs/Chicken.h
index a4c1d6b9e..b1a50b61c 100644
--- a/src/Mobs/Chicken.h
+++ b/src/Mobs/Chicken.h
@@ -14,7 +14,7 @@ class cChicken :
public:
cChicken(void);
- CLASS_PROTODEF(cChicken);
+ CLASS_PROTODEF(cChicken)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Cow.h b/src/Mobs/Cow.h
index 973171ab5..8814b7e09 100644
--- a/src/Mobs/Cow.h
+++ b/src/Mobs/Cow.h
@@ -15,7 +15,7 @@ class cCow :
public:
cCow();
- CLASS_PROTODEF(cCow);
+ CLASS_PROTODEF(cCow)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
diff --git a/src/Mobs/Creeper.cpp b/src/Mobs/Creeper.cpp
index b9041bd5a..02718edf8 100644
--- a/src/Mobs/Creeper.cpp
+++ b/src/Mobs/Creeper.cpp
@@ -37,13 +37,13 @@ void cCreeper::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_bIsBlowing)
{
- m_ExplodingTimer += 1;
+ m_ExplodingTimer += 1;
}
if (m_ExplodingTimer == 30)
{
m_World->DoExplosionAt((m_bIsCharged ? 5 : 3), GetPosX(), GetPosY(), GetPosZ(), false, esMonster, this);
- Destroy(); // Just in case we aren't killed by the explosion
+ Destroy(); // Just in case we aren't killed by the explosion
}
}
}
@@ -125,7 +125,7 @@ void cCreeper::Attack(float a_Dt)
if (!m_bIsBlowing)
{
- m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
}
@@ -143,7 +143,7 @@ void cCreeper::OnRightClicked(cPlayer & a_Player)
{
a_Player.UseEquippedItem();
}
- m_World->BroadcastSoundEffect("game.tnt.primed", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+ m_World->BroadcastSoundEffect("game.tnt.primed", GetPosX(), GetPosY(), GetPosZ(), 1.f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
m_bIsBlowing = true;
m_World->BroadcastEntityMetadata(*this);
m_BurnedWithFlintAndSteel = true;
diff --git a/src/Mobs/Creeper.h b/src/Mobs/Creeper.h
index fc7db6716..747daca09 100644
--- a/src/Mobs/Creeper.h
+++ b/src/Mobs/Creeper.h
@@ -15,7 +15,7 @@ class cCreeper :
public:
cCreeper(void);
- CLASS_PROTODEF(cCreeper);
+ CLASS_PROTODEF(cCreeper)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
diff --git a/src/Mobs/EnderDragon.h b/src/Mobs/EnderDragon.h
index 77177edfe..1d4cd657c 100644
--- a/src/Mobs/EnderDragon.h
+++ b/src/Mobs/EnderDragon.h
@@ -15,7 +15,7 @@ class cEnderDragon :
public:
cEnderDragon(void);
- CLASS_PROTODEF(cEnderDragon);
+ CLASS_PROTODEF(cEnderDragon)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;
diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp
index becc99a86..51255beb3 100644
--- a/src/Mobs/Enderman.cpp
+++ b/src/Mobs/Enderman.cpp
@@ -2,6 +2,76 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Enderman.h"
+#include "../Entities/Player.h"
+#include "../Tracer.h"
+
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// cPlayerLookCheck
+class cPlayerLookCheck :
+ public cPlayerListCallback
+{
+public:
+ cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
+ m_Player(NULL),
+ m_EndermanPos(a_EndermanPos),
+ m_SightDistance(a_SightDistance)
+ {
+ }
+
+ virtual bool Item(cPlayer * a_Player) override
+ {
+ // Don't check players who are in creative gamemode
+ if (a_Player->IsGameModeCreative())
+ {
+ return false;
+ }
+
+ Vector3d Direction = m_EndermanPos - a_Player->GetPosition();
+
+ // Don't check players who are more then SightDistance (64) blocks away
+ if (Direction.Length() > m_SightDistance)
+ {
+ return false;
+ }
+
+ // Don't check if the player has a pumpkin on his head
+ if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
+ {
+ return false;
+ }
+
+
+ Vector3d LookVector = a_Player->GetLookVector();
+ double dot = Direction.Dot(LookVector);
+
+ // 0.09 rad ~ 5 degrees
+ // If the player's crosshair is within 5 degrees of the enderman, it counts as looking
+ if (dot <= cos(0.09))
+ {
+ return false;
+ }
+
+ cTracer LineOfSight(a_Player->GetWorld());
+ if (LineOfSight.Trace(m_EndermanPos, Direction, (int)Direction.Length()))
+ {
+ // No direct line of sight
+ return false;
+ }
+
+ m_Player = a_Player;
+ return true;
+ }
+
+ cPlayer * GetPlayer(void) const { return m_Player; }
+
+protected:
+ cPlayer * m_Player;
+ Vector3d m_EndermanPos;
+ int m_SightDistance;
+} ;
@@ -32,3 +102,82 @@ void cEnderman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+void cEnderman::CheckEventSeePlayer()
+{
+ if (m_Target != NULL)
+ {
+ return;
+ }
+
+ cPlayerLookCheck Callback(GetPosition(), m_SightDistance);
+ if (m_World->ForEachPlayer(Callback))
+ {
+ return;
+ }
+
+ ASSERT(Callback.GetPlayer() != NULL);
+
+ if (!CheckLight())
+ {
+ // Insufficient light for enderman to become aggravated
+ // TODO: Teleport to a suitable location
+ return;
+ }
+
+ if (!Callback.GetPlayer()->IsGameModeCreative())
+ {
+ super::EventSeePlayer(Callback.GetPlayer());
+ m_EMState = CHASING;
+ m_bIsScreaming = true;
+ GetWorld()->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cEnderman::CheckEventLostPlayer(void)
+{
+ super::CheckEventLostPlayer();
+ if (!CheckLight())
+ {
+ EventLosePlayer();
+ }
+}
+
+
+
+
+
+void cEnderman::EventLosePlayer()
+{
+ super::EventLosePlayer();
+ m_bIsScreaming = false;
+ GetWorld()->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+bool cEnderman::CheckLight()
+{
+ int ChunkX, ChunkZ;
+ cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
+
+ // Check if the chunk the enderman is in is lit
+ if (!m_World->IsChunkLighted(ChunkX, ChunkZ))
+ {
+ m_World->QueueLightChunk(ChunkX, ChunkZ);
+ return true;
+ }
+
+ // Enderman only attack if the skylight is lower or equal to 8
+ if (m_World->GetBlockSkyLight(POSX_TOINT, POSY_TOINT, POSZ_TOINT) - GetWorld()->GetSkyDarkness() > 8)
+ {
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h
index 32e40e70b..4583746e7 100644
--- a/src/Mobs/Enderman.h
+++ b/src/Mobs/Enderman.h
@@ -15,14 +15,20 @@ class cEnderman :
public:
cEnderman(void);
- CLASS_PROTODEF(cEnderman);
+ CLASS_PROTODEF(cEnderman)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void CheckEventSeePlayer(void) override;
+ virtual void CheckEventLostPlayer(void) override;
+ virtual void EventLosePlayer(void) override;
bool IsScreaming(void) const {return m_bIsScreaming; }
BLOCKTYPE GetCarriedBlock(void) const {return CarriedBlock; }
NIBBLETYPE GetCarriedMeta(void) const {return CarriedMeta; }
+ /** Returns if the current sky light level is sufficient for the enderman to become aggravated */
+ bool CheckLight(void);
+
private:
bool m_bIsScreaming;
diff --git a/src/Mobs/Ghast.h b/src/Mobs/Ghast.h
index 43e8bedb6..1d4e6b94a 100644
--- a/src/Mobs/Ghast.h
+++ b/src/Mobs/Ghast.h
@@ -15,7 +15,7 @@ class cGhast :
public:
cGhast(void);
- CLASS_PROTODEF(cGhast);
+ CLASS_PROTODEF(cGhast)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Attack(float a_Dt) override;
diff --git a/src/Mobs/Giant.h b/src/Mobs/Giant.h
index 356dd4352..7c04c9b4f 100644
--- a/src/Mobs/Giant.h
+++ b/src/Mobs/Giant.h
@@ -15,7 +15,7 @@ class cGiant :
public:
cGiant(void);
- CLASS_PROTODEF(cGiant);
+ CLASS_PROTODEF(cGiant)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;
diff --git a/src/Mobs/Horse.cpp b/src/Mobs/Horse.cpp
index 9d130301f..67a09d4ab 100644
--- a/src/Mobs/Horse.cpp
+++ b/src/Mobs/Horse.cpp
@@ -63,7 +63,7 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk)
m_Attachee->Detach();
m_bIsRearing = true;
}
- }
+ }
else
{
m_bIsTame = true;
diff --git a/src/Mobs/Horse.h b/src/Mobs/Horse.h
index be0c23f9b..47189b3b0 100644
--- a/src/Mobs/Horse.h
+++ b/src/Mobs/Horse.h
@@ -15,7 +15,7 @@ class cHorse :
public:
cHorse(int Type, int Color, int Style, int TameTimes);
- CLASS_PROTODEF(cHorse);
+ CLASS_PROTODEF(cHorse)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/IronGolem.h b/src/Mobs/IronGolem.h
index 41c60438c..c5341ed76 100644
--- a/src/Mobs/IronGolem.h
+++ b/src/Mobs/IronGolem.h
@@ -15,11 +15,11 @@ class cIronGolem :
public:
cIronGolem(void);
- CLASS_PROTODEF(cIronGolem);
+ CLASS_PROTODEF(cIronGolem)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- // Iron golems do not drown
+ // Iron golems do not drown nor float
virtual void HandleAir(void) override {}
virtual void SetSwimState(cChunk & a_Chunk) override {}
} ;
diff --git a/src/Mobs/MagmaCube.h b/src/Mobs/MagmaCube.h
index 43065cae5..bfe63fa2e 100644
--- a/src/Mobs/MagmaCube.h
+++ b/src/Mobs/MagmaCube.h
@@ -15,7 +15,7 @@ public:
/// Creates a MagmaCube of the specified size; size is 1 .. 3, with 1 being the smallest
cMagmaCube(int a_Size);
- CLASS_PROTODEF(cMagmaCube);
+ CLASS_PROTODEF(cMagmaCube)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
int GetSize(void) const { return m_Size; }
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index aaef7580d..fe8a7346f 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -62,7 +62,7 @@ static const struct
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
// cMonster:
cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
@@ -115,12 +115,10 @@ void cMonster::TickPathFinding()
const int PosY = POSY_TOINT;
const int PosZ = POSZ_TOINT;
- m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
-
std::vector<Vector3d> m_PotentialCoordinates;
m_TraversedCoordinates.push_back(Vector3i(PosX, PosY, PosZ));
- static const struct // Define which directions to try to move to
+ static const struct // Define which directions to try to move to
{
int x, z;
} gCrossCoords[] =
@@ -128,7 +126,7 @@ void cMonster::TickPathFinding()
{ 1, 0},
{-1, 0},
{ 0, 1},
- { 0,-1},
+ { 0, -1},
} ;
if ((PosY - 1 < 0) || (PosY + 2 > cChunkDef::Height) /* PosY + 1 will never be true if PosY + 2 is not */)
@@ -201,19 +199,6 @@ void cMonster::TickPathFinding()
-void cMonster::MoveToPosition(const Vector3f & a_Position)
-{
- FinishPathFinding();
-
- m_FinalDestination = a_Position;
- m_bMovingToDestination = true;
- TickPathFinding();
-}
-
-
-
-
-
void cMonster::MoveToPosition(const Vector3d & a_Position)
{
FinishPathFinding();
@@ -227,15 +212,7 @@ void cMonster::MoveToPosition(const Vector3d & a_Position)
bool cMonster::IsCoordinateInTraversedList(Vector3i a_Coords)
{
- for (std::vector<Vector3i>::const_iterator itr = m_TraversedCoordinates.begin(); itr != m_TraversedCoordinates.end(); ++itr)
- {
- if (itr->Equals(a_Coords))
- {
- return true;
- }
- }
-
- return false;
+ return (std::find(m_TraversedCoordinates.begin(), m_TraversedCoordinates.end(), a_Coords) != m_TraversedCoordinates.end());
}
@@ -296,49 +273,57 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
{
if (m_bOnGround)
{
- m_Destination.y = FindFirstNonAirBlockPosition(m_Destination.x, m_Destination.z);
-
if (DoesPosYRequireJump((int)floor(m_Destination.y)))
{
m_bOnGround = false;
- AddSpeedY(5.2); // Jump!!
+
+ // TODO: Change to AddSpeedY once collision detection is fixed - currently, mobs will go into blocks attempting to jump without a teleport
+ AddPosY(1.2); // Jump!!
}
}
Vector3f Distance = m_Destination - GetPosition();
- if(!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
+ if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
Distance.Normalize();
if (m_bOnGround)
{
- Distance *= 2.5;
+ Distance *= 2.5f;
+ }
+ else if (IsSwimming())
+ {
+ Distance *= 1.3f;
}
else
{
// Don't let the mob move too much if he's falling.
- Distance *= 0.25;
+ Distance *= 0.25f;
}
AddSpeedX(Distance.x);
AddSpeedZ(Distance.z);
+ // It's too buggy!
+ /*
if (m_EMState == ESCAPING)
- { //Runs Faster when escaping :D otherwise they just walk away
+ {
+ // Runs Faster when escaping :D otherwise they just walk away
SetSpeedX (GetSpeedX() * 2.f);
SetSpeedZ (GetSpeedZ() * 2.f);
}
+ */
}
else
{
- if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate
+ if (ReachedFinalDestination()) // If we have reached the ultimate, final destination, stop pathfinding and attack if appropriate
{
FinishPathFinding();
}
else
{
- TickPathFinding(); // We have reached the next point in our path, calculate another point
+ TickPathFinding(); // We have reached the next point in our path, calculate another point
}
}
}
@@ -353,13 +338,13 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
// If enemy passive we ignore checks for player visibility
InStateIdle(a_Dt);
break;
- }
+ }
case CHASING:
{
// If we do not see a player anymore skip chasing action
InStateChasing(a_Dt);
break;
- }
+ }
case ESCAPING:
{
InStateEscaping(a_Dt);
@@ -435,14 +420,11 @@ void cMonster::HandleFalling()
+
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
{
int PosY = POSY_TOINT;
-
- if (PosY < 0)
- PosY = 0;
- else if (PosY > cChunkDef::Height)
- PosY = cChunkDef::Height;
+ PosY = Clamp(PosY, 0, cChunkDef::Height);
if (!cBlockInfo::IsSolid(m_World->GetBlock((int)floor(a_PosX), PosY, (int)floor(a_PosZ))))
{
@@ -478,7 +460,7 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
if (!m_SoundHurt.empty() && (m_Health > 0))
{
- m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+ m_World->BroadcastSoundEffect(m_SoundHurt, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
if (a_TDI.Attacker != NULL)
@@ -492,12 +474,12 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
-void cMonster::KilledBy(cEntity * a_Killer)
+void cMonster::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
if (m_SoundHurt != "")
{
- m_World->BroadcastSoundEffect(m_SoundDeath, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
+ m_World->BroadcastSoundEffect(m_SoundDeath, GetPosX(), GetPosY(), GetPosZ(), 1.0f, 0.8f);
}
int Reward;
switch (m_MobType)
@@ -558,7 +540,7 @@ void cMonster::KilledBy(cEntity * a_Killer)
break;
}
}
- if ((a_Killer != NULL) && (!IsBaby()))
+ if ((a_TDI.Attacker != NULL) && (!IsBaby()))
{
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), Reward);
}
@@ -569,8 +551,8 @@ void cMonster::KilledBy(cEntity * a_Killer)
-//Checks to see if EventSeePlayer should be fired
-//monster sez: Do I see the player
+// Checks to see if EventSeePlayer should be fired
+// monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(void)
{
// TODO: Rewrite this to use cWorld's DoWithPlayers()
@@ -587,7 +569,7 @@ void cMonster::CheckEventSeePlayer(void)
void cMonster::CheckEventLostPlayer(void)
-{
+{
if (m_Target != NULL)
{
if ((m_Target->GetPosition() - GetPosition()).Length() > m_SightDistance)
@@ -630,7 +612,7 @@ void cMonster::InStateIdle(float a_Dt)
{
if (m_bMovingToDestination)
{
- return; // Still getting there
+ return; // Still getting there
}
m_IdleInterval += a_Dt;
@@ -639,7 +621,7 @@ void cMonster::InStateIdle(float a_Dt)
{
// At this interval the results are predictable
int rem = m_World->GetTickRandomNumber(6) + 1;
- m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
+ m_IdleInterval -= 1; // So nothing gets dropped when the server hangs for a few seconds
Vector3d Dist;
Dist.x = (double)m_World->GetTickRandomNumber(10) - 5;
@@ -706,6 +688,15 @@ void cMonster::GetMonsterConfig(const AString & a_Name)
+bool cMonster::IsUndead(void)
+{
+ return false;
+}
+
+
+
+
+
AString cMonster::MobTypeToString(cMonster::eType a_MobType)
{
// Mob types aren't sorted, so we need to search linearly:
@@ -727,8 +718,7 @@ AString cMonster::MobTypeToString(cMonster::eType a_MobType)
cMonster::eType cMonster::StringToMobType(const AString & a_Name)
{
- AString lcName(a_Name);
- StrToLower(lcName);
+ AString lcName = StrToLower(a_Name);
// Binary-search for the lowercase name:
int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1;
@@ -847,13 +837,13 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
}
case mtSlime:
{
- toReturn = new cSlime(Random.NextInt(2) + 1);
+ toReturn = new cSlime(1 << Random.NextInt(3)); // Size 1, 2 or 4
break;
}
case mtSkeleton:
{
// TODO: Actual detection of spawning in Nether
- toReturn = new cSkeleton(Random.NextInt(1) == 0 ? false : true);
+ toReturn = new cSkeleton((Random.NextInt(1) == 0) ? false : true);
break;
}
case mtVillager:
@@ -900,7 +890,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtMooshroom: toReturn = new cMooshroom(); break;
case mtOcelot: toReturn = new cOcelot(); break;
case mtPig: toReturn = new cPig(); break;
- case mtSheep: toReturn = new cSheep (Random.NextInt(15)); break; // Colour parameter
+ case mtSheep: toReturn = new cSheep(); break;
case mtSilverfish: toReturn = new cSilverfish(); break;
case mtSnowGolem: toReturn = new cSnowGolem(); break;
case mtSpider: toReturn = new cSpider(); break;
@@ -908,7 +898,7 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
case mtWitch: toReturn = new cWitch(); break;
case mtWither: toReturn = new cWither(); break;
case mtWolf: toReturn = new cWolf(); break;
- case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
+ case mtZombie: toReturn = new cZombie(false); break; // TODO: Infected zombie parameter
case mtZombiePigman: toReturn = new cZombiePigman(); break;
default:
{
@@ -1034,7 +1024,7 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
(a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand
(GetWorld()->GetTimeOfDay() < (12000 + 1000)) && // It is nighttime
!IsOnFire() && // Not already burning
- (GetWorld()->GetWeather() != eWeather_Rain) // Not raining
+ GetWorld()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining
)
{
// Burn for 100 ticks, then decide again
diff --git a/src/Mobs/Monster.h b/src/Mobs/Monster.h
index 7d7e90eb2..cdbd26c09 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -61,28 +61,28 @@ public:
enum eFamily
{
- mfHostile = 0, // Spider, Zombies ...
- mfPassive = 1, // Cows, Pigs
- mfAmbient = 2, // Bats
- mfWater = 3, // Squid
+ mfHostile = 0, // Spider, Zombies ...
+ mfPassive = 1, // Cows, Pigs
+ mfAmbient = 2, // Bats
+ mfWater = 3, // Squid
mfNoSpawn,
- mfUnhandled, // Nothing. Be sure this is the last and the others are in order
+ mfUnhandled, // Nothing. Be sure this is the last and the others are in order
} ;
// tolua_end
enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
- enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality;
+ enum MPersonality{PASSIVE, AGGRESSIVE, COWARDLY} m_EMPersonality;
/** Creates the mob object.
- * If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig()
- * a_MobType is the type of the mob (also used in the protocol ( http://wiki.vg/Entities#Mobs , 2012_12_22))
- * a_SoundHurt and a_SoundDeath are assigned into m_SoundHurt and m_SoundDeath, respectively
+ If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig()
+ a_MobType is the type of the mob (also used in the protocol ( http://wiki.vg/Entities#Mobs 2012_12_22))
+ a_SoundHurt and a_SoundDeath are assigned into m_SoundHurt and m_SoundDeath, respectively
*/
cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
- CLASS_PROTODEF(cMonster);
+ CLASS_PROTODEF(cMonster)
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
@@ -90,10 +90,9 @@ public:
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
- virtual void MoveToPosition(const Vector3f & a_Position);
- virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
+ virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
virtual bool ReachedDestination(void);
// tolua_begin
@@ -107,6 +106,9 @@ public:
/// Reads the monster configuration for the specified monster name and assigns it to this object.
void GetMonsterConfig(const AString & a_Name);
+ /** Returns whether this mob is undead (skeleton, zombie, etc.) */
+ virtual bool IsUndead(void);
+
virtual void EventLosePlayer(void);
virtual void CheckEventLostPlayer(void);
@@ -178,6 +180,7 @@ protected:
/** Stores if mobile is currently moving towards the ultimate, final destination */
bool m_bMovingToDestination;
+
/** Finds the first non-air block position (not the highest, as cWorld::GetHeight does)
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
If current Y is solid, goes up to find first nonsolid block, and returns that */
@@ -229,7 +232,7 @@ protected:
AString m_SoundHurt;
AString m_SoundDeath;
- float m_AttackRate;
+ float m_AttackRate;
int m_AttackDamage;
int m_AttackRange;
float m_AttackInterval;
@@ -246,13 +249,13 @@ protected:
bool m_BurnsInDaylight;
/** Adds a random number of a_Item between a_Min and a_Max to itemdrops a_Drops*/
- void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
+ void AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth = 0);
/** Adds a item a_Item with the chance of a_Chance (in percent) to itemdrops a_Drops*/
- void AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth = 0);
+ void AddRandomUncommonDropItem(cItems & a_Drops, float a_Chance, short a_Item, short a_ItemHealth = 0);
/** Adds one rare item out of the list of rare items a_Items modified by the looting level a_LootingLevel(I-III or custom) to the itemdrop a_Drops*/
- void AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel);
+ void AddRandomRareDropItem(cItems & a_Drops, cItems & a_Items, short a_LootingLevel);
/** Adds armor that is equipped with the chance saved in m_DropChance[...] (this will be greter than 1 if piccked up or 0.085 + (0.01 per LootingLevel) if born with) to the drop*/
void AddRandomArmorDropItem(cItems & a_Drops, short a_LootingLevel);
@@ -261,7 +264,7 @@ protected:
void AddRandomWeaponDropItem(cItems & a_Drops, short a_LootingLevel);
-} ; // tolua_export
+} ; // tolua_export
diff --git a/src/Mobs/Mooshroom.h b/src/Mobs/Mooshroom.h
index 16f6c8248..fb002c2bf 100644
--- a/src/Mobs/Mooshroom.h
+++ b/src/Mobs/Mooshroom.h
@@ -15,7 +15,7 @@ class cMooshroom :
public:
cMooshroom(void);
- CLASS_PROTODEF(cMooshroom);
+ CLASS_PROTODEF(cMooshroom)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
diff --git a/src/Mobs/Ocelot.h b/src/Mobs/Ocelot.h
index adb7a1f75..f2727d354 100644
--- a/src/Mobs/Ocelot.h
+++ b/src/Mobs/Ocelot.h
@@ -18,7 +18,7 @@ public:
{
}
- CLASS_PROTODEF(cOcelot);
+ CLASS_PROTODEF(cOcelot)
} ;
diff --git a/src/Mobs/Pig.h b/src/Mobs/Pig.h
index 313af2f44..534a0ca6f 100644
--- a/src/Mobs/Pig.h
+++ b/src/Mobs/Pig.h
@@ -15,7 +15,7 @@ class cPig :
public:
cPig(void);
- CLASS_PROTODEF(cPig);
+ CLASS_PROTODEF(cPig)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 5a6b760af..9fb47201d 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -5,6 +5,7 @@
#include "../BlockID.h"
#include "../Entities/Player.h"
#include "../World.h"
+#include "FastRandom.h"
@@ -16,6 +17,16 @@ cSheep::cSheep(int a_Color) :
m_WoolColor(a_Color),
m_TimeToStopEating(-1)
{
+ // Generate random wool color.
+ if (m_WoolColor == -1)
+ {
+ m_WoolColor = GenerateNaturalRandomColor();
+ }
+
+ if ((m_WoolColor < 0) || (m_WoolColor > 15))
+ {
+ m_WoolColor = 0;
+ }
}
@@ -37,20 +48,17 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
const cItem & EquippedItem = a_Player.GetEquippedItem();
- if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
+ if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{
m_IsSheared = true;
m_World->BroadcastEntityMetadata(*this);
-
- if (!a_Player.IsGameModeCreative())
- {
- a_Player.UseEquippedItem();
- }
+ a_Player.UseEquippedItem();
cItems Drops;
int NumDrops = m_World->GetTickRandomNumber(2) + 1;
Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ m_World->BroadcastSoundEffect("mob.sheep.shear", GetPosX(), GetPosY(), GetPosZ(), 1.0f, 1.0f);
}
else if ((EquippedItem.m_ItemType == E_ITEM_DYE) && (m_WoolColor != 15 - EquippedItem.m_ItemDamage))
{
@@ -81,12 +89,12 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
if (m_TimeToStopEating > 0)
{
- m_bMovingToDestination = false; // The sheep should not move when he's eating
+ m_bMovingToDestination = false; // The sheep should not move when he's eating
m_TimeToStopEating--;
if (m_TimeToStopEating == 0)
{
- if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
+ if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) // Make sure grass hasn't been destroyed in the meantime
{
// The sheep ate the grass so we change it to dirt
m_World->SetBlock(PosX, PosY, PosZ, E_BLOCK_DIRT, 0);
@@ -109,3 +117,38 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
}
}
+
+
+
+
+NIBBLETYPE cSheep::GenerateNaturalRandomColor(void)
+{
+ cFastRandom Random;
+ int Chance = Random.NextInt(101);
+
+ if (Chance <= 81)
+ {
+ return E_META_WOOL_WHITE;
+ }
+ else if (Chance <= 86)
+ {
+ return E_META_WOOL_BLACK;
+ }
+ else if (Chance <= 91)
+ {
+ return E_META_WOOL_GRAY;
+ }
+ else if (Chance <= 96)
+ {
+ return E_META_WOOL_LIGHTGRAY;
+ }
+ else if (Chance <= 99)
+ {
+ return E_META_WOOL_BROWN;
+ }
+ else
+ {
+ return E_META_WOOL_PINK;
+ }
+}
+
diff --git a/src/Mobs/Sheep.h b/src/Mobs/Sheep.h
index 402e8e61c..28e1c7254 100644
--- a/src/Mobs/Sheep.h
+++ b/src/Mobs/Sheep.h
@@ -13,21 +13,32 @@ class cSheep :
typedef cPassiveMonster super;
public:
- cSheep(int a_Color);
-
- CLASS_PROTODEF(cSheep);
-
+
+ /** The number is the color of the sheep.
+ Use E_META_WOOL_* constants for the wool color.
+ If you type -1, the server will generate a random color
+ with the GenerateNaturalRandomColor() function. */
+ cSheep(int a_Color = -1);
+
+ CLASS_PROTODEF(cSheep)
+
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual const cItem GetFollowedItem(void) const override { return cItem(E_ITEM_WHEAT); }
+ /** Generates a random color for the sheep like the vanilla server.
+ The percent's where used are from the wiki: http://minecraft.gamepedia.com/Sheep#Breeding */
+ static NIBBLETYPE GenerateNaturalRandomColor(void);
+
bool IsSheared(void) const { return m_IsSheared; }
+ void SetSheared(bool a_IsSheared) { m_IsSheared = a_IsSheared; }
+
int GetFurColor(void) const { return m_WoolColor; }
+ void SetFurColor(int a_WoolColor) { m_WoolColor = a_WoolColor; }
private:
-
bool m_IsSheared;
int m_WoolColor;
int m_TimeToStopEating;
diff --git a/src/Mobs/Silverfish.h b/src/Mobs/Silverfish.h
index a6e11c49d..2df333dbc 100644
--- a/src/Mobs/Silverfish.h
+++ b/src/Mobs/Silverfish.h
@@ -18,7 +18,7 @@ public:
{
}
- CLASS_PROTODEF(cSilverfish);
+ CLASS_PROTODEF(cSilverfish)
} ;
diff --git a/src/Mobs/Skeleton.cpp b/src/Mobs/Skeleton.cpp
index 0641a3d57..cd707f4bb 100644
--- a/src/Mobs/Skeleton.cpp
+++ b/src/Mobs/Skeleton.cpp
@@ -4,6 +4,7 @@
#include "Skeleton.h"
#include "../World.h"
#include "../Entities/ArrowEntity.h"
+#include "ClientHandle.h"
@@ -47,7 +48,7 @@ void cSkeleton::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cSkeleton::MoveToPosition(const Vector3f & a_Position)
+void cSkeleton::MoveToPosition(const Vector3d & a_Position)
{
// If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
if (
@@ -90,3 +91,17 @@ void cSkeleton::Attack(float a_Dt)
m_AttackInterval = 0.0;
}
}
+
+
+
+
+
+void cSkeleton::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ super::SpawnOn(a_ClientHandle);
+ a_ClientHandle.SendEntityEquipment(*this, 0, cItem(E_ITEM_BOW));
+}
+
+
+
+
diff --git a/src/Mobs/Skeleton.h b/src/Mobs/Skeleton.h
index 8f31b42e1..577588b32 100644
--- a/src/Mobs/Skeleton.h
+++ b/src/Mobs/Skeleton.h
@@ -15,12 +15,16 @@ class cSkeleton :
public:
cSkeleton(bool IsWither);
- CLASS_PROTODEF(cSkeleton);
+ CLASS_PROTODEF(cSkeleton)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void MoveToPosition(const Vector3f & a_Position) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
virtual void Attack(float a_Dt) override;
- bool IsWither(void) const { return m_bIsWither; };
+ 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/Slime.cpp b/src/Mobs/Slime.cpp
index 52a52bb39..b709ec664 100644
--- a/src/Mobs/Slime.cpp
+++ b/src/Mobs/Slime.cpp
@@ -2,16 +2,25 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Slime.h"
+#include "FastRandom.h"
+#include "World.h"
-/// Creates a slime of the specified size; size is 1 .. 3, with 1 being the smallest
cSlime::cSlime(int a_Size) :
- super("Slime", mtSlime, "mob.slime.attack", "mob.slime.attack", 0.6 * a_Size, 0.6 * a_Size),
+ super("Slime",
+ mtSlime,
+ Printf("mob.slime.%s", GetSizeName(a_Size).c_str()),
+ Printf("mob.slime.%s", GetSizeName(a_Size).c_str()),
+ 0.6 * a_Size,
+ 0.6 * a_Size
+ ),
m_Size(a_Size)
{
+ SetMaxHealth(a_Size * a_Size);
+ SetAttackDamage(a_Size);
}
@@ -25,7 +34,9 @@ void cSlime::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
}
- if (GetSize() == 1)
+
+ // Only slimes with the size 1 can drop slimeballs.
+ if (m_Size == 1)
{
AddRandomDropItem(a_Drops, 0, 2 + LootingLevel, E_ITEM_SLIMEBALL);
}
@@ -34,3 +45,62 @@ void cSlime::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+
+void cSlime::Attack(float a_Dt)
+{
+ if (m_Size > 1)
+ {
+ // Only slimes larger than size 1 attack a player.
+ super::Attack(a_Dt);
+ }
+}
+
+
+
+
+
+void cSlime::KilledBy(TakeDamageInfo & a_TDI)
+{
+ if (GetHealth() > 0)
+ {
+ return;
+ }
+
+ if (m_Size != 1)
+ {
+ cFastRandom Random;
+ int SpawnAmount = 2 + Random.NextInt(3);
+
+ for (int i = 0; i < SpawnAmount; ++i)
+ {
+ double AddX = (i % 2 - 0.5) * m_Size / 4.0;
+ double AddZ = (i / 2 - 0.5) * m_Size / 4.0;
+
+ cSlime * NewSlime = new cSlime(m_Size / 2);
+ NewSlime->SetPosition(GetPosX() + AddX, GetPosY() + 0.5, GetPosZ() + AddZ);
+ NewSlime->SetYaw(Random.NextFloat(1.0f) * 360.0f);
+ m_World->SpawnMobFinalize(NewSlime);
+ }
+ }
+ super::KilledBy(a_TDI);
+}
+
+
+
+
+
+const AString cSlime::GetSizeName(int a_Size) const
+{
+ if (a_Size > 1)
+ {
+ return "big";
+ }
+ else
+ {
+ return "small";
+ }
+}
+
+
+
+
diff --git a/src/Mobs/Slime.h b/src/Mobs/Slime.h
index 782c3113f..f0b800f94 100644
--- a/src/Mobs/Slime.h
+++ b/src/Mobs/Slime.h
@@ -13,17 +13,26 @@ class cSlime :
typedef cAggressiveMonster super;
public:
- /// Creates a slime of the specified size; size is 1 .. 3, with 1 being the smallest
+ /** Creates a slime of the specified size; size can be 1, 2 or 4, with 1 is the smallest and 4 is the tallest. */
cSlime(int a_Size);
- CLASS_PROTODEF(cSlime);
+ CLASS_PROTODEF(cSlime)
+ // cAggressiveMonster overrides:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Attack(float a_Dt) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
int GetSize(void) const { return m_Size; }
+ /** Returns the text describing the slime's size, as used by the client's resource subsystem for sounds.
+ Returns either "big" or "small". */
+ const AString GetSizeName(int a_Size) const;
+
protected:
- /// Size of the slime, 1 .. 3, with 1 being the smallest
+ /** Size of the slime, with 1 being the smallest.
+ Vanilla uses sizes 1, 2 and 4 only. */
int m_Size;
} ;
diff --git a/src/Mobs/SnowGolem.cpp b/src/Mobs/SnowGolem.cpp
index c1979a495..76334d970 100644
--- a/src/Mobs/SnowGolem.cpp
+++ b/src/Mobs/SnowGolem.cpp
@@ -30,7 +30,7 @@ void cSnowGolem::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSnowGolem::Tick(float a_Dt, cChunk & a_Chunk)
{
super::Tick(a_Dt, a_Chunk);
- if (IsBiomeNoDownfall(m_World->GetBiomeAt((int) floor(GetPosX()), (int) floor(GetPosZ())) ))
+ if (IsBiomeNoDownfall(m_World->GetBiomeAt((int) floor(GetPosX()), (int) floor(GetPosZ()))))
{
TakeDamage(*this);
}
diff --git a/src/Mobs/SnowGolem.h b/src/Mobs/SnowGolem.h
index ff5e90da8..aba89e52d 100644
--- a/src/Mobs/SnowGolem.h
+++ b/src/Mobs/SnowGolem.h
@@ -15,7 +15,7 @@ class cSnowGolem :
public:
cSnowGolem(void);
- CLASS_PROTODEF(cSnowGolem);
+ CLASS_PROTODEF(cSnowGolem)
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
diff --git a/src/Mobs/Spider.h b/src/Mobs/Spider.h
index 51e65d028..813d2e266 100644
--- a/src/Mobs/Spider.h
+++ b/src/Mobs/Spider.h
@@ -15,7 +15,7 @@ class cSpider :
public:
cSpider(void);
- CLASS_PROTODEF(cSpider);
+ CLASS_PROTODEF(cSpider)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
} ;
diff --git a/src/Mobs/Squid.h b/src/Mobs/Squid.h
index a9dba8b70..b57340427 100644
--- a/src/Mobs/Squid.h
+++ b/src/Mobs/Squid.h
@@ -17,7 +17,7 @@ public:
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
- CLASS_PROTODEF(cSquid);
+ CLASS_PROTODEF(cSquid)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 41283acf4..1cdac7c74 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -55,7 +55,7 @@ void cVillager::Tick(float a_Dt, cChunk & a_Chunk)
{
switch (m_Type)
{
- case vtFarmer:
+ case vtFarmer:
{
HandleFarmerPlaceCrops();
}
@@ -138,8 +138,8 @@ void cVillager::HandleFarmerPrepareFarmCrops()
m_CropsPos = Vector3i((int) GetPosX() + X - 5, (int) GetPosY() + Y - 3, (int) GetPosZ() + Z - 5);
MoveToPosition(Vector3f((float) (m_CropsPos.x + 0.5), (float) m_CropsPos.y, (float) (m_CropsPos.z + 0.5)));
return;
- } // for Y loop.
- } // Repeat the procces 5 times.
+ } // for Y loop.
+ } // Repeat the procces 5 times.
}
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index abde48407..aa81f0790 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -27,7 +27,7 @@ public:
cVillager(eVillagerType VillagerType);
- CLASS_PROTODEF(cVillager);
+ CLASS_PROTODEF(cVillager)
// cEntity overrides
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
@@ -37,9 +37,8 @@ public:
/** return true if the given blocktype are: crops, potatoes or carrots.*/
bool IsBlockFarmable(BLOCKTYPE a_BlockType);
- //////////////////////////////////////////////////////////////////
// Farmer functions
- /** It searches in a 11x7x11 area for crops. If it found some it will navigate to them.*/
+ /** Searches in a 11x7x11 area for crops. If it found some it will navigate to them.*/
void HandleFarmerPrepareFarmCrops();
/** Looks if the farmer has reached it's destination, and if it's still crops and the destination is closer then 2 blocks it will harvest them.*/
@@ -49,7 +48,7 @@ public:
void HandleFarmerPlaceCrops();
// Get and set functions.
- int GetVilType(void) const { return m_Type; }
+ int GetVilType(void) const { return m_Type; }
Vector3i GetCropsPos(void) const { return m_CropsPos; }
bool DoesHaveActionActivated(void) const { return m_VillagerAction; }
diff --git a/src/Mobs/Witch.h b/src/Mobs/Witch.h
index 51c63322a..bd059f61d 100644
--- a/src/Mobs/Witch.h
+++ b/src/Mobs/Witch.h
@@ -16,7 +16,7 @@ class cWitch :
public:
cWitch();
- CLASS_PROTODEF(cWitch);
+ CLASS_PROTODEF(cWitch)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
diff --git a/src/Mobs/Wither.cpp b/src/Mobs/Wither.cpp
index da4cc7765..578b47995 100644
--- a/src/Mobs/Wither.cpp
+++ b/src/Mobs/Wither.cpp
@@ -103,9 +103,9 @@ void cWither::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cWither::KilledBy(cEntity * a_Killer)
+void cWither::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
class cPlayerCallback : public cPlayerListCallback
{
diff --git a/src/Mobs/Wither.h b/src/Mobs/Wither.h
index 03a320788..2403823ed 100644
--- a/src/Mobs/Wither.h
+++ b/src/Mobs/Wither.h
@@ -15,7 +15,7 @@ class cWither :
public:
cWither(void);
- CLASS_PROTODEF(cWither);
+ CLASS_PROTODEF(cWither)
unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; }
@@ -29,7 +29,9 @@ public:
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ virtual bool IsUndead(void) override { return true; }
private:
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index e6268abc7..4fe1ff1d6 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -36,7 +36,7 @@ bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
{
m_IsAngry = true;
}
- m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
+ m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
return true;
}
@@ -68,6 +68,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
{
if (!IsTame() && !IsAngry())
{
+ // If the player is holding a bone, try to tame the wolf:
if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE)
{
if (!a_Player.IsGameModeCreative())
@@ -77,14 +78,16 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
if (m_World->GetTickRandomNumber(7) == 0)
{
+ // Taming succeeded
SetMaxHealth(20);
SetIsTame(true);
- SetOwner(a_Player.GetName());
+ SetOwner(a_Player.GetName(), a_Player.GetUUID());
m_World->BroadcastEntityStatus(*this, esWolfTamed);
m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
}
else
{
+ // Taming failed
m_World->BroadcastEntityStatus(*this, esWolfTaming);
m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
}
@@ -92,6 +95,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
}
else if (IsTame())
{
+ // Feed the wolf, restoring its health, or dye its collar:
switch (a_Player.GetEquippedItem().m_ItemType)
{
case E_ITEM_RAW_BEEF:
@@ -114,7 +118,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
}
case E_ITEM_DYE:
{
- if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
{
SetCollarColor(15 - a_Player.GetEquippedItem().m_ItemDamage);
if (!a_Player.IsGameModeCreative())
@@ -126,7 +130,7 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
}
default:
{
- if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
+ if (a_Player.GetName() == m_OwnerName) // Is the player the owner of the dog?
{
SetIsSitting(!IsSitting());
}
@@ -172,7 +176,7 @@ void cWolf::Tick(float a_Dt, cChunk & a_Chunk)
m_World->BroadcastEntityMetadata(*this);
}
- m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food
+ m_FinalDestination = a_Closest_Player->GetPosition(); // So that we will look at a player holding food
// Don't move to the player if the wolf is sitting.
if (!IsSitting())
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index fb8a7c995..7500854f8 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -16,7 +16,7 @@ class cWolf :
public:
cWolf(void);
- CLASS_PROTODEF(cWolf);
+ CLASS_PROTODEF(cWolf)
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
virtual void OnRightClicked(cPlayer & a_Player) override;
@@ -29,7 +29,8 @@ public:
bool IsTame (void) const { return m_IsTame; }
bool IsBegging (void) const { return m_IsBegging; }
bool IsAngry (void) const { return m_IsAngry; }
- AString GetOwner (void) const { return m_OwnerName; }
+ AString GetOwnerName (void) const { return m_OwnerName; }
+ AString GetOwnerUUID (void) const { return m_OwnerUUID; }
int GetCollarColor(void) const { return m_CollarColor; }
// Set functions
@@ -37,8 +38,12 @@ public:
void SetIsTame (bool a_IsTame) { m_IsTame = a_IsTame; }
void SetIsBegging (bool a_IsBegging) { m_IsBegging = a_IsBegging; }
void SetIsAngry (bool a_IsAngry) { m_IsAngry = a_IsAngry; }
- void SetOwner (const AString & a_NewOwner) { m_OwnerName = a_NewOwner; }
void SetCollarColor(int a_CollarColor) { m_CollarColor = a_CollarColor; }
+ void SetOwner (const AString & a_NewOwnerName, const AString & a_NewOwnerUUID)
+ {
+ m_OwnerName = a_NewOwnerName;
+ m_OwnerUUID = a_NewOwnerUUID;
+ }
protected:
@@ -47,6 +52,7 @@ protected:
bool m_IsBegging;
bool m_IsAngry;
AString m_OwnerName;
+ AString m_OwnerUUID;
int m_CollarColor;
} ;
diff --git a/src/Mobs/Zombie.cpp b/src/Mobs/Zombie.cpp
index 725790ed9..30225c32d 100644
--- a/src/Mobs/Zombie.cpp
+++ b/src/Mobs/Zombie.cpp
@@ -42,7 +42,7 @@ void cZombie::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cZombie::MoveToPosition(const Vector3f & a_Position)
+void cZombie::MoveToPosition(const Vector3d & a_Position)
{
// If the destination is sufficiently skylight challenged AND the skeleton isn't on fire then block the movement
if (
diff --git a/src/Mobs/Zombie.h b/src/Mobs/Zombie.h
index 1ba368f9c..118b6e6e7 100644
--- a/src/Mobs/Zombie.h
+++ b/src/Mobs/Zombie.h
@@ -14,13 +14,15 @@ class cZombie :
public:
cZombie(bool a_IsVillagerZombie);
- CLASS_PROTODEF(cZombie);
+ CLASS_PROTODEF(cZombie)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void MoveToPosition(const Vector3f & a_Position) override;
+ virtual void MoveToPosition(const Vector3d & a_Position) override;
- bool IsVillagerZombie(void) const {return m_IsVillagerZombie; }
- bool IsConverting (void) const {return m_IsConverting; }
+ virtual bool IsUndead(void) override { return true; }
+
+ bool IsVillagerZombie(void) const { return m_IsVillagerZombie; }
+ bool IsConverting (void) const { return m_IsConverting; }
private:
diff --git a/src/Mobs/ZombiePigman.cpp b/src/Mobs/ZombiePigman.cpp
index c9d94face..05350f877 100644
--- a/src/Mobs/ZombiePigman.cpp
+++ b/src/Mobs/ZombiePigman.cpp
@@ -37,11 +37,11 @@ void cZombiePigman::GetDrops(cItems & a_Drops, cEntity * a_Killer)
-void cZombiePigman::KilledBy(cEntity * a_Killer)
+void cZombiePigman::KilledBy(TakeDamageInfo & a_TDI)
{
- super::KilledBy(a_Killer);
+ super::KilledBy(a_TDI);
- if ((a_Killer != NULL) && (a_Killer->IsPlayer()))
+ if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
{
// TODO: Anger all nearby zombie pigmen
// TODO: In vanilla, if one player angers ZPs, do they attack any nearby player, or only that one attacker?
diff --git a/src/Mobs/ZombiePigman.h b/src/Mobs/ZombiePigman.h
index ab3cebf6d..bae0115eb 100644
--- a/src/Mobs/ZombiePigman.h
+++ b/src/Mobs/ZombiePigman.h
@@ -14,10 +14,12 @@ class cZombiePigman :
public:
cZombiePigman(void);
- CLASS_PROTODEF(cZombiePigman);
+ CLASS_PROTODEF(cZombiePigman)
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
- virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+
+ virtual bool IsUndead(void) override { return true; }
} ;