summaryrefslogtreecommitdiffstats
path: root/src/Mobs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Mobs')
-rw-r--r--src/Mobs/AggressiveMonster.cpp2
-rw-r--r--src/Mobs/AggressiveMonster.h2
-rw-r--r--src/Mobs/CMakeLists.txt1
-rw-r--r--src/Mobs/Enderman.cpp169
-rw-r--r--src/Mobs/Enderman.h7
-rw-r--r--src/Mobs/Monster.cpp209
-rw-r--r--src/Mobs/Monster.h78
-rw-r--r--src/Mobs/MonsterTypes.h54
-rw-r--r--src/Mobs/Mooshroom.cpp2
-rw-r--r--src/Mobs/PassiveAggressiveMonster.cpp2
-rw-r--r--src/Mobs/PassiveAggressiveMonster.h2
-rw-r--r--src/Mobs/PassiveMonster.cpp2
-rw-r--r--src/Mobs/PassiveMonster.h2
-rw-r--r--src/Mobs/Sheep.cpp9
-rw-r--r--src/Mobs/Villager.cpp6
-rw-r--r--src/Mobs/Villager.h2
-rw-r--r--src/Mobs/Wolf.cpp6
-rw-r--r--src/Mobs/Wolf.h10
18 files changed, 442 insertions, 123 deletions
diff --git a/src/Mobs/AggressiveMonster.cpp b/src/Mobs/AggressiveMonster.cpp
index 5f5b1853d..be2f71f7a 100644
--- a/src/Mobs/AggressiveMonster.cpp
+++ b/src/Mobs/AggressiveMonster.cpp
@@ -11,7 +11,7 @@
-cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = AGGRESSIVE;
diff --git a/src/Mobs/AggressiveMonster.h b/src/Mobs/AggressiveMonster.h
index d70ff04a3..2549ba2d3 100644
--- a/src/Mobs/AggressiveMonster.h
+++ b/src/Mobs/AggressiveMonster.h
@@ -14,7 +14,7 @@ class cAggressiveMonster :
public:
- cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+ cAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
virtual void InStateChasing(float a_Dt) override;
diff --git a/src/Mobs/CMakeLists.txt b/src/Mobs/CMakeLists.txt
index 2c092c15f..bbbb9287a 100644
--- a/src/Mobs/CMakeLists.txt
+++ b/src/Mobs/CMakeLists.txt
@@ -54,6 +54,7 @@ SET (HDRS
IronGolem.h
MagmaCube.h
Monster.h
+ MonsterTypes.h
Mooshroom.h
Ocelot.h
PassiveAggressiveMonster.h
diff --git a/src/Mobs/Enderman.cpp b/src/Mobs/Enderman.cpp
index becc99a86..567714382 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,102 @@ 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;
+}
+
+
+
+
+
+void cEnderman::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ // TODO take damage in rain
+
+ // Take damage when touching water, drowning damage seems to be most appropriate
+ if (IsSwimming())
+ {
+ EventLosePlayer();
+ TakeDamage(dtDrowning, NULL, 1, 0);
+ // TODO teleport to a safe location
+ }
+
+}
diff --git a/src/Mobs/Enderman.h b/src/Mobs/Enderman.h
index aa2eff682..947c32b96 100644
--- a/src/Mobs/Enderman.h
+++ b/src/Mobs/Enderman.h
@@ -18,11 +18,18 @@ public:
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;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) 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/Monster.cpp b/src/Mobs/Monster.cpp
index 622a67816..73dbcb3c3 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -24,48 +24,58 @@ The strings need to be lowercase (for more efficient comparisons in StringToMobT
*/
static const struct
{
- cMonster::eType m_Type;
+ eMonsterType m_Type;
const char * m_lcName;
} g_MobTypeNames[] =
{
- {cMonster::mtBat, "bat"},
- {cMonster::mtBlaze, "blaze"},
- {cMonster::mtCaveSpider, "cavespider"},
- {cMonster::mtChicken, "chicken"},
- {cMonster::mtCow, "cow"},
- {cMonster::mtCreeper, "creeper"},
- {cMonster::mtEnderman, "enderman"},
- {cMonster::mtEnderDragon, "enderdragon"},
- {cMonster::mtGhast, "ghast"},
- {cMonster::mtHorse, "horse"},
- {cMonster::mtIronGolem, "irongolem"},
- {cMonster::mtMagmaCube, "magmacube"},
- {cMonster::mtMooshroom, "mooshroom"},
- {cMonster::mtOcelot, "ocelot"},
- {cMonster::mtPig, "pig"},
- {cMonster::mtSheep, "sheep"},
- {cMonster::mtSilverfish, "silverfish"},
- {cMonster::mtSkeleton, "skeleton"},
- {cMonster::mtSlime, "slime"},
- {cMonster::mtSnowGolem, "snowgolem"},
- {cMonster::mtSpider, "spider"},
- {cMonster::mtSquid, "squid"},
- {cMonster::mtVillager, "villager"},
- {cMonster::mtWitch, "witch"},
- {cMonster::mtWither, "wither"},
- {cMonster::mtWolf, "wolf"},
- {cMonster::mtZombie, "zombie"},
- {cMonster::mtZombiePigman, "zombiepigman"},
+ {mtBat, "bat"},
+ {mtBlaze, "blaze"},
+ {mtCaveSpider, "cavespider"},
+ {mtChicken, "chicken"},
+ {mtCow, "cow"},
+ {mtCreeper, "creeper"},
+ {mtEnderman, "enderman"},
+ {mtEnderDragon, "enderdragon"},
+ {mtGhast, "ghast"},
+ {mtHorse, "horse"},
+ {mtIronGolem, "irongolem"},
+ {mtMagmaCube, "magmacube"},
+ {mtMooshroom, "mooshroom"},
+ {mtOcelot, "ocelot"},
+ {mtPig, "pig"},
+ {mtSheep, "sheep"},
+ {mtSilverfish, "silverfish"},
+ {mtSkeleton, "skeleton"},
+ {mtSlime, "slime"},
+ {mtSnowGolem, "snowgolem"},
+ {mtSpider, "spider"},
+ {mtSquid, "squid"},
+ {mtVillager, "villager"},
+ {mtWitch, "witch"},
+ {mtWither, "wither"},
+ {mtWolf, "wolf"},
+ {mtZombie, "zombie"},
+ {mtZombiePigman, "zombiepigman"},
} ;
+eMonsterType StringToMobType(const AString & a_MobString)
+{
+ LOGWARNING("%s: Function is obsolete, use cMonster::StringToMobType() instead", __FUNCTION__);
+ return cMonster::StringToMobType(a_MobString);
+}
+
+
+
+
+
////////////////////////////////////////////////////////////////////////////////
// cMonster:
-cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
+cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height)
: super(etMonster, a_Width, a_Height)
, m_EMState(IDLE)
, m_EMPersonality(AGGRESSIVE)
@@ -75,6 +85,8 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_IdleInterval(0)
, m_DestroyTimer(0)
, m_MobType(a_MobType)
+ , m_CustomName("")
+ , m_CustomNameAlwaysVisible(false)
, m_SoundHurt(a_SoundHurt)
, m_SoundDeath(a_SoundDeath)
, m_AttackRate(3)
@@ -89,6 +101,7 @@ cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString
, m_DropChanceBoots(0.085f)
, m_CanPickUpLoot(true)
, m_BurnsInDaylight(false)
+ , m_RelativeWalkSpeed(1.0)
{
if (!a_ConfigName.empty())
{
@@ -276,11 +289,13 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
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();
+ Vector3d Distance = m_Destination - GetPosition();
if (!ReachedDestination() && !ReachedFinalDestination()) // If we haven't reached any sort of destination, move
{
Distance.y = 0;
@@ -288,22 +303,33 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
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;
}
+ // Apply walk speed:
+ Distance *= m_RelativeWalkSpeed;
+
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
{
@@ -475,50 +501,50 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI)
switch (m_MobType)
{
// Animals
- case cMonster::mtChicken:
- case cMonster::mtCow:
- case cMonster::mtHorse:
- case cMonster::mtPig:
- case cMonster::mtSheep:
- case cMonster::mtSquid:
- case cMonster::mtMooshroom:
- case cMonster::mtOcelot:
- case cMonster::mtWolf:
+ case mtChicken:
+ case mtCow:
+ case mtHorse:
+ case mtPig:
+ case mtSheep:
+ case mtSquid:
+ case mtMooshroom:
+ case mtOcelot:
+ case mtWolf:
{
Reward = m_World->GetTickRandomNumber(2) + 1;
break;
}
// Monsters
- case cMonster::mtCaveSpider:
- case cMonster::mtCreeper:
- case cMonster::mtEnderman:
- case cMonster::mtGhast:
- case cMonster::mtSilverfish:
- case cMonster::mtSkeleton:
- case cMonster::mtSpider:
- case cMonster::mtWitch:
- case cMonster::mtZombie:
- case cMonster::mtZombiePigman:
- case cMonster::mtSlime:
- case cMonster::mtMagmaCube:
+ case mtCaveSpider:
+ case mtCreeper:
+ case mtEnderman:
+ case mtGhast:
+ case mtSilverfish:
+ case mtSkeleton:
+ case mtSpider:
+ case mtWitch:
+ case mtZombie:
+ case mtZombiePigman:
+ case mtSlime:
+ case mtMagmaCube:
{
Reward = 6 + (m_World->GetTickRandomNumber(2));
break;
}
- case cMonster::mtBlaze:
+ case mtBlaze:
{
Reward = 10;
break;
}
// Bosses
- case cMonster::mtEnderDragon:
+ case mtEnderDragon:
{
Reward = 12000;
break;
}
- case cMonster::mtWither:
+ case mtWither:
{
Reward = 50;
break;
@@ -541,6 +567,25 @@ void cMonster::KilledBy(TakeDamageInfo & a_TDI)
+void cMonster::OnRightClicked(cPlayer & a_Player)
+{
+ super::OnRightClicked(a_Player);
+
+ const cItem & EquippedItem = a_Player.GetEquippedItem();
+ if ((EquippedItem.m_ItemType == E_ITEM_NAME_TAG) && !EquippedItem.m_CustomName.empty())
+ {
+ SetCustomName(EquippedItem.m_CustomName);
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ }
+}
+
+
+
+
+
// Checks to see if EventSeePlayer should be fired
// monster sez: Do I see the player
void cMonster::CheckEventSeePlayer(void)
@@ -669,6 +714,39 @@ void cMonster::InStateEscaping(float a_Dt)
+void cMonster::SetCustomName(const AString & a_CustomName)
+{
+ m_CustomName = a_CustomName;
+
+ // The maximal length is 64
+ if (a_CustomName.length() > 64)
+ {
+ m_CustomName = a_CustomName.substr(0, 64);
+ }
+
+ if (m_World != NULL)
+ {
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
+void cMonster::SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible)
+{
+ m_CustomNameAlwaysVisible = a_CustomNameAlwaysVisible;
+ if (m_World != NULL)
+ {
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
void cMonster::GetMonsterConfig(const AString & a_Name)
{
cRoot::Get()->GetMonsterConfig()->AssignAttributes(this, a_Name);
@@ -687,7 +765,7 @@ bool cMonster::IsUndead(void)
-AString cMonster::MobTypeToString(cMonster::eType a_MobType)
+AString cMonster::MobTypeToString(eMonsterType a_MobType)
{
// Mob types aren't sorted, so we need to search linearly:
for (size_t i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++)
@@ -706,10 +784,9 @@ AString cMonster::MobTypeToString(cMonster::eType a_MobType)
-cMonster::eType cMonster::StringToMobType(const AString & a_Name)
+eMonsterType 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;
@@ -748,7 +825,7 @@ cMonster::eType cMonster::StringToMobType(const AString & a_Name)
-cMonster::eFamily cMonster::FamilyFromType(eType a_Type)
+cMonster::eFamily cMonster::FamilyFromType(eMonsterType a_Type)
{
// Passive-agressive mobs are counted in mob spawning code as passive
@@ -813,7 +890,7 @@ int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily)
-cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
+cMonster * cMonster::NewMonsterFromType(eMonsterType a_MobType)
{
cFastRandom Random;
cMonster * toReturn = NULL;
@@ -1015,7 +1092,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()->IsWeatherWetAt(POSX_TOINT, POSZ_TOINT) // Not raining
+ GetWorld()->IsWeatherSunnyAt(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 cdbd26c09..9fd67d67c 100644
--- a/src/Mobs/Monster.h
+++ b/src/Mobs/Monster.h
@@ -6,6 +6,7 @@
#include "../BlockID.h"
#include "../Item.h"
#include "../Enchantments.h"
+#include "MonsterTypes.h"
@@ -23,41 +24,6 @@ class cMonster :
{
typedef cPawn super;
public:
- /// This identifies individual monster type, as well as their network type-ID
- enum eType
- {
- mtInvalidType = -1,
-
- mtBat = E_META_SPAWN_EGG_BAT,
- mtBlaze = E_META_SPAWN_EGG_BLAZE,
- mtCaveSpider = E_META_SPAWN_EGG_CAVE_SPIDER,
- mtChicken = E_META_SPAWN_EGG_CHICKEN,
- mtCow = E_META_SPAWN_EGG_COW,
- mtCreeper = E_META_SPAWN_EGG_CREEPER,
- mtEnderDragon = E_META_SPAWN_EGG_ENDER_DRAGON,
- mtEnderman = E_META_SPAWN_EGG_ENDERMAN,
- mtGhast = E_META_SPAWN_EGG_GHAST,
- mtGiant = E_META_SPAWN_EGG_GIANT,
- mtHorse = E_META_SPAWN_EGG_HORSE,
- mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM,
- mtMagmaCube = E_META_SPAWN_EGG_MAGMA_CUBE,
- mtMooshroom = E_META_SPAWN_EGG_MOOSHROOM,
- mtOcelot = E_META_SPAWN_EGG_OCELOT,
- mtPig = E_META_SPAWN_EGG_PIG,
- mtSheep = E_META_SPAWN_EGG_SHEEP,
- mtSilverfish = E_META_SPAWN_EGG_SILVERFISH,
- mtSkeleton = E_META_SPAWN_EGG_SKELETON,
- mtSlime = E_META_SPAWN_EGG_SLIME,
- mtSnowGolem = E_META_SPAWN_EGG_SNOW_GOLEM,
- mtSpider = E_META_SPAWN_EGG_SPIDER,
- mtSquid = E_META_SPAWN_EGG_SQUID,
- mtVillager = E_META_SPAWN_EGG_VILLAGER,
- mtWitch = E_META_SPAWN_EGG_WITCH,
- mtWither = E_META_SPAWN_EGG_WITHER,
- mtWolf = E_META_SPAWN_EGG_WOLF,
- mtZombie = E_META_SPAWN_EGG_ZOMBIE,
- mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
- } ;
enum eFamily
{
@@ -80,7 +46,7 @@ public:
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);
+ cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
CLASS_PROTODEF(cMonster)
@@ -92,11 +58,13 @@ public:
virtual void KilledBy(TakeDamageInfo & a_TDI) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
virtual void MoveToPosition(const Vector3d & a_Position); // tolua_export
virtual bool ReachedDestination(void);
// tolua_begin
- eType GetMobType(void) const {return m_MobType; }
+ eMonsterType GetMobType(void) const {return m_MobType; }
eFamily GetMobFamily(void) const;
// tolua_end
@@ -138,21 +106,41 @@ public:
/// Sets whether the mob burns in daylight. Only evaluated at next burn-decision tick
void SetBurnsInDaylight(bool a_BurnsInDaylight) { m_BurnsInDaylight = a_BurnsInDaylight; }
+ double GetRelativeWalkSpeed(void) const { return m_RelativeWalkSpeed; } // tolua_export
+ void SetRelativeWalkSpeed(double a_WalkSpeed) { m_RelativeWalkSpeed = a_WalkSpeed; } // tolua_export
+
// Overridables to handle ageable mobs
virtual bool IsBaby (void) const { return false; }
virtual bool IsTame (void) const { return false; }
virtual bool IsSitting (void) const { return false; }
// tolua_begin
-
+
+ /** Returns true if the monster has a custom name. */
+ bool HasCustomName(void) const { return !m_CustomName.empty(); }
+
+ /** Gets the custom name of the monster. If no custom name is set, the function returns an empty string. */
+ const AString & GetCustomName(void) const { return m_CustomName; }
+
+ /** Sets the custom name of the monster. You see the name over the monster.
+ If you want to disable the custom name, simply set an empty string. */
+ void SetCustomName(const AString & a_CustomName);
+
+ /** Is the custom name of this monster always visible? If not, you only see the name when you sight the mob. */
+ bool IsCustomNameAlwaysVisible(void) const { return m_CustomNameAlwaysVisible; }
+
+ /** Sets the custom name visiblity of this monster.
+ If it's false, you only see the name when you sight the mob. If it's true, you always see the custom name. */
+ void SetCustomNameAlwaysVisible(bool a_CustomNameAlwaysVisible);
+
/// Translates MobType enum to a string, empty string if unknown
- static AString MobTypeToString(eType a_MobType);
+ static AString MobTypeToString(eMonsterType a_MobType);
/// Translates MobType string to the enum, mtInvalidType if not recognized
- static eType StringToMobType(const AString & a_MobTypeName);
+ static eMonsterType StringToMobType(const AString & a_MobTypeName);
/// Returns the mob family based on the type
- static eFamily FamilyFromType(eType a_MobType);
+ static eFamily FamilyFromType(eMonsterType a_MobType);
/// Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family
static int GetSpawnDelay(cMonster::eFamily a_MobFamily);
@@ -163,7 +151,7 @@ public:
a_MobType is the type of the mob to be created
Asserts and returns null if mob type is not specified
*/
- static cMonster * NewMonsterFromType(eType a_MobType);
+ static cMonster * NewMonsterFromType(eMonsterType a_MobType);
protected:
@@ -227,7 +215,9 @@ protected:
float m_IdleInterval;
float m_DestroyTimer;
- eType m_MobType;
+ eMonsterType m_MobType;
+ AString m_CustomName;
+ bool m_CustomNameAlwaysVisible;
AString m_SoundHurt;
AString m_SoundDeath;
@@ -248,6 +238,8 @@ protected:
void HandleDaylightBurning(cChunk & a_Chunk);
bool m_BurnsInDaylight;
+ double m_RelativeWalkSpeed;
+
/** 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);
diff --git a/src/Mobs/MonsterTypes.h b/src/Mobs/MonsterTypes.h
new file mode 100644
index 000000000..852eb3446
--- /dev/null
+++ b/src/Mobs/MonsterTypes.h
@@ -0,0 +1,54 @@
+
+#pragma once
+
+/// This identifies individual monster type, as well as their network type-ID
+// tolua_begin
+enum eMonsterType
+{
+ mtInvalidType = -1,
+
+ mtBat = E_META_SPAWN_EGG_BAT,
+ mtBlaze = E_META_SPAWN_EGG_BLAZE,
+ mtCaveSpider = E_META_SPAWN_EGG_CAVE_SPIDER,
+ mtChicken = E_META_SPAWN_EGG_CHICKEN,
+ mtCow = E_META_SPAWN_EGG_COW,
+ mtCreeper = E_META_SPAWN_EGG_CREEPER,
+ mtEnderDragon = E_META_SPAWN_EGG_ENDER_DRAGON,
+ mtEnderman = E_META_SPAWN_EGG_ENDERMAN,
+ mtGhast = E_META_SPAWN_EGG_GHAST,
+ mtGiant = E_META_SPAWN_EGG_GIANT,
+ mtHorse = E_META_SPAWN_EGG_HORSE,
+ mtIronGolem = E_META_SPAWN_EGG_IRON_GOLEM,
+ mtMagmaCube = E_META_SPAWN_EGG_MAGMA_CUBE,
+ mtMooshroom = E_META_SPAWN_EGG_MOOSHROOM,
+ mtOcelot = E_META_SPAWN_EGG_OCELOT,
+ mtPig = E_META_SPAWN_EGG_PIG,
+ mtSheep = E_META_SPAWN_EGG_SHEEP,
+ mtSilverfish = E_META_SPAWN_EGG_SILVERFISH,
+ mtSkeleton = E_META_SPAWN_EGG_SKELETON,
+ mtSlime = E_META_SPAWN_EGG_SLIME,
+ mtSnowGolem = E_META_SPAWN_EGG_SNOW_GOLEM,
+ mtSpider = E_META_SPAWN_EGG_SPIDER,
+ mtSquid = E_META_SPAWN_EGG_SQUID,
+ mtVillager = E_META_SPAWN_EGG_VILLAGER,
+ mtWitch = E_META_SPAWN_EGG_WITCH,
+ mtWither = E_META_SPAWN_EGG_WITHER,
+ mtWolf = E_META_SPAWN_EGG_WOLF,
+ mtZombie = E_META_SPAWN_EGG_ZOMBIE,
+ mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN,
+} ;
+
+
+
+
+
+/** Translates a mob string ("ocelot") to mobtype (mtOcelot).
+OBSOLETE, use cMonster::StringToMobType() instead.
+Implemented in Monster.cpp. */
+extern eMonsterType StringToMobType(const AString & a_MobString);
+
+// tolua_end
+
+
+
+
diff --git a/src/Mobs/Mooshroom.cpp b/src/Mobs/Mooshroom.cpp
index 81bd3e3b4..99958720f 100644
--- a/src/Mobs/Mooshroom.cpp
+++ b/src/Mobs/Mooshroom.cpp
@@ -67,7 +67,7 @@ void cMooshroom::OnRightClicked(cPlayer & a_Player)
cItems Drops;
Drops.push_back(cItem(E_BLOCK_RED_MUSHROOM, 5, 0));
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
- m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), cMonster::mtCow);
+ m_World->SpawnMob(GetPosX(), GetPosY(), GetPosZ(), mtCow);
Destroy();
} break;
}
diff --git a/src/Mobs/PassiveAggressiveMonster.cpp b/src/Mobs/PassiveAggressiveMonster.cpp
index 24501b1ba..e0cc2fd21 100644
--- a/src/Mobs/PassiveAggressiveMonster.cpp
+++ b/src/Mobs/PassiveAggressiveMonster.cpp
@@ -9,7 +9,7 @@
-cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = PASSIVE;
diff --git a/src/Mobs/PassiveAggressiveMonster.h b/src/Mobs/PassiveAggressiveMonster.h
index a0da50e8e..72f472281 100644
--- a/src/Mobs/PassiveAggressiveMonster.h
+++ b/src/Mobs/PassiveAggressiveMonster.h
@@ -13,7 +13,7 @@ class cPassiveAggressiveMonster :
typedef cAggressiveMonster super;
public:
- cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+ cPassiveAggressiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
} ;
diff --git a/src/Mobs/PassiveMonster.cpp b/src/Mobs/PassiveMonster.cpp
index 2861d7314..be3043e3d 100644
--- a/src/Mobs/PassiveMonster.cpp
+++ b/src/Mobs/PassiveMonster.cpp
@@ -8,7 +8,7 @@
-cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
+cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) :
super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height)
{
m_EMPersonality = PASSIVE;
diff --git a/src/Mobs/PassiveMonster.h b/src/Mobs/PassiveMonster.h
index 70574585a..9221d9a6e 100644
--- a/src/Mobs/PassiveMonster.h
+++ b/src/Mobs/PassiveMonster.h
@@ -13,7 +13,7 @@ class cPassiveMonster :
typedef cMonster super;
public:
- cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
+ cPassiveMonster(const AString & a_ConfigName, eMonsterType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
diff --git a/src/Mobs/Sheep.cpp b/src/Mobs/Sheep.cpp
index 9fb47201d..cbb33cb90 100644
--- a/src/Mobs/Sheep.cpp
+++ b/src/Mobs/Sheep.cpp
@@ -39,6 +39,13 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
a_Drops.push_back(cItem(E_BLOCK_WOOL, 1, m_WoolColor));
}
+
+ int LootingLevel = 0;
+ if (a_Killer != NULL)
+ {
+ LootingLevel = a_Killer->GetEquippedWeapon().m_Enchantments.GetLevel(cEnchantments::enchLooting);
+ }
+ AddRandomDropItem(a_Drops, 1, 3 + LootingLevel, IsOnFire() ? E_ITEM_COOKED_MUTTON : E_ITEM_RAW_MUTTON);
}
@@ -47,6 +54,8 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
void cSheep::OnRightClicked(cPlayer & a_Player)
{
+ super::OnRightClicked(a_Player);
+
const cItem & EquippedItem = a_Player.GetEquippedItem();
if ((EquippedItem.m_ItemType == E_ITEM_SHEARS) && !IsSheared() && !IsBaby())
{
diff --git a/src/Mobs/Villager.cpp b/src/Mobs/Villager.cpp
index 1cdac7c74..0efd5501e 100644
--- a/src/Mobs/Villager.cpp
+++ b/src/Mobs/Villager.cpp
@@ -109,11 +109,11 @@ void cVillager::HandleFarmerPrepareFarmCrops()
Surrounding.Read(
m_World,
(int) GetPosX() - 5,
- (int) GetPosX() + 5,
+ (int) GetPosX() + 6,
(int) GetPosY() - 3,
- (int) GetPosY() + 3,
+ (int) GetPosY() + 4,
(int) GetPosZ() - 5,
- (int) GetPosZ() + 5
+ (int) GetPosZ() + 6
);
for (int I = 0; I < 5; I++)
diff --git a/src/Mobs/Villager.h b/src/Mobs/Villager.h
index aa81f0790..d3a38dbf0 100644
--- a/src/Mobs/Villager.h
+++ b/src/Mobs/Villager.h
@@ -2,7 +2,7 @@
#pragma once
#include "PassiveMonster.h"
-
+#include "Blocks/ChunkInterface.h"
diff --git a/src/Mobs/Wolf.cpp b/src/Mobs/Wolf.cpp
index 5bb97d30e..4fe1ff1d6 100644
--- a/src/Mobs/Wolf.cpp
+++ b/src/Mobs/Wolf.cpp
@@ -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:
diff --git a/src/Mobs/Wolf.h b/src/Mobs/Wolf.h
index 2e83db701..7500854f8 100644
--- a/src/Mobs/Wolf.h
+++ b/src/Mobs/Wolf.h
@@ -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;
} ;