summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--source/Entities/Entity.h63
-rw-r--r--source/Entities/Minecart.cpp58
-rw-r--r--source/Entities/Minecart.h13
-rw-r--r--source/Mobs/Horse.cpp95
-rw-r--r--source/Mobs/Horse.h19
-rw-r--r--source/Mobs/Magmacube.h1
-rw-r--r--source/Mobs/Pig.cpp49
-rw-r--r--source/Mobs/Pig.h7
-rw-r--r--source/Mobs/Sheep.cpp28
-rw-r--r--source/Mobs/Sheep.h16
-rw-r--r--source/Mobs/Skeleton.cpp5
-rw-r--r--source/Mobs/Skeleton.h8
-rw-r--r--source/Mobs/Slime.cpp2
-rw-r--r--source/Mobs/Slime.h1
-rw-r--r--source/Mobs/Villager.cpp22
-rw-r--r--source/Mobs/Villager.h10
-rw-r--r--source/Mobs/Wolf.cpp79
-rw-r--r--source/Mobs/Wolf.h22
-rw-r--r--source/Protocol/Protocol125.cpp220
-rw-r--r--source/Protocol/Protocol125.h7
-rw-r--r--source/Protocol/Protocol132.cpp3
-rw-r--r--source/World.cpp77
22 files changed, 710 insertions, 95 deletions
diff --git a/source/Entities/Entity.h b/source/Entities/Entity.h
index a2c99d2a0..764c5a64b 100644
--- a/source/Entities/Entity.h
+++ b/source/Entities/Entity.h
@@ -71,6 +71,13 @@ public:
ENTITY_STATUS_WOLF_SHAKING = 8,
ENTITY_STATUS_EATING_ACCEPTED = 9,
ENTITY_STATUS_SHEEP_EATING = 10,
+ ENTITY_STATUS_GOLEM_ROSING = 11,
+ ENTITY_STATUS_VILLAGER_HEARTS = 12,
+ ENTITY_STATUS_VILLAGER_ANGRY = 13,
+ ENTITY_STATUS_VILLAGER_HAPPY = 14,
+ ENTITY_STATUS_WITCH_MAGICKING = 15,
+ // It seems 16 (zombie conversion) is now done with metadata
+ ENTITY_STATUS_FIREWORK_EXPLODE= 17,
} ;
enum
@@ -333,6 +340,62 @@ public:
virtual bool IsRiding (void) const {return false; }
virtual bool IsSprinting(void) const {return false; }
virtual bool IsRclking (void) const {return false; }
+ virtual bool IsInvisible(void) const {return false; }
+
+ // Ageables + Tameables
+ virtual bool IsBabby (void) const {return false; }
+ virtual bool IsSitting (void) const {return false; }
+ virtual bool IsTame (void) const {return false; }
+
+ // Creepers
+ virtual bool IsCharged (void) const {return false; }
+ virtual bool IsBlowing (void) const {return false; }
+
+ // Furnace Minecarts & Minecarts
+ virtual int LastDamage (void) const {return 0; }
+ virtual bool IsFueled (void) const {return false; }
+
+ // Bat
+ virtual bool IsHanging (void) const {return false; }
+
+ // Pig
+ virtual bool IsSaddled (void) const {return false; }
+
+ // TESTIFICATE
+ virtual int GetVilType(void) const {return 0; }
+
+ // Zombie
+ virtual bool IsVillager(void) const {return false; }
+ virtual bool IsConvert (void) const {return false; }
+
+ // Ghast
+ virtual bool IsCharging(void) const {return false; }
+
+ // Arrow
+ virtual bool IsCritical(void) const {return false; }
+
+ // Wolf
+ virtual bool IsAngry (void) const {return false; }
+ virtual bool IsBegging (void) const {return false; }
+ virtual int GetCollar (void) const {return 0; }
+
+ // Sheep
+ virtual int GetFurColor(void) const {return 0; }
+ virtual bool IsSheared (void) const {return false; }
+
+ // Enderman
+ virtual BLOCKTYPE CarriedBlock (void) const {return E_BLOCK_AIR; }
+ virtual NIBBLETYPE CarriedMeta (void) const {return 0; }
+ virtual bool IsScream (void) const {return false; }
+
+ // Skeleton || Wither Skeleton
+ virtual bool IsWither (void) const {return false; }
+
+ // Witch
+ virtual bool IsNosey (void) const {return false; }
+
+ // Slimes and Magma cubes
+ virtual int GetSize (void) const {return 1; }
// tolua_end
diff --git a/source/Entities/Minecart.cpp b/source/Entities/Minecart.cpp
index a2f1e5593..1711e296f 100644
--- a/source/Entities/Minecart.cpp
+++ b/source/Entities/Minecart.cpp
@@ -16,7 +16,8 @@
cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7),
- m_Payload(a_Payload)
+ m_Payload(a_Payload),
+ m_LastDamage(0)
{
SetMass(20.f);
SetMaxHealth(6);
@@ -344,11 +345,51 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
+ m_LastDamage = TDI.FinalDamage;
super::DoTakeDamage(TDI);
+ m_World->BroadcastEntityMetadata(*this);
+
if (GetHealth() <= 0)
{
Destroy(true);
+
+ cItems Drops;
+ switch (m_Payload)
+ {
+ case mpNone:
+ {
+ Drops.push_back(cItem(E_ITEM_MINECART, 1, 0));
+ break;
+ }
+ case mpChest:
+ {
+ Drops.push_back(cItem(E_ITEM_CHEST_MINECART, 1, 0));
+ break;
+ }
+ case mpFurnace:
+ {
+ Drops.push_back(cItem(E_ITEM_FURNACE_MINECART, 1, 0));
+ break;
+ }
+ case mpTNT:
+ {
+ Drops.push_back(cItem(0, 1, 0));
+ break;
+ }
+ case mpHopper:
+ {
+ Drops.push_back(cItem(0, 1, 0));
+ break;
+ }
+ default:
+ {
+ ASSERT(!"Unhandled minecart type when spawning pickup!");
+ return;
+ }
+ }
+
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
}
}
@@ -434,7 +475,8 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
// cMinecartWithFurnace:
cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
- super(mpFurnace, a_X, a_Y, a_Z)
+ super(mpFurnace, a_X, a_Y, a_Z),
+ m_IsFueled(false)
{
}
@@ -444,8 +486,16 @@ cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
{
- // Try to power the furnace with whatever the player is holding
- // TODO
+ if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_COAL)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ m_IsFueled = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
}
diff --git a/source/Entities/Minecart.h b/source/Entities/Minecart.h
index 0152f5dfc..f974ea76a 100644
--- a/source/Entities/Minecart.h
+++ b/source/Entities/Minecart.h
@@ -50,16 +50,19 @@ public:
// cEntity overrides:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
- void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
-
+ int LastDamage(void) const { return m_LastDamage; }
+ void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
ePayload GetPayload(void) const { return m_Payload; }
protected:
ePayload m_Payload;
cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z);
+
+ int m_LastDamage;
+
} ;
@@ -127,6 +130,12 @@ public:
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
+ bool IsFueled (void) const { return m_IsFueled; }
+
+private:
+
+ bool m_IsFueled;
+
} ;
diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp
index 05ac73c15..50eab33cc 100644
--- a/source/Mobs/Horse.cpp
+++ b/source/Mobs/Horse.cpp
@@ -2,13 +2,26 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Horse.h"
+#include "../World.h"
+#include "../Entities/Player.h"
-cHorse::cHorse(void) :
- super("Horse", 100, "mob.horse.hit", "mob.horse.death", 1.4, 1.6)
+cHorse::cHorse(int Type, int Color, int Style, int TameTimes) :
+ super("Horse", 100, "mob.horse.hit", "mob.horse.death", 1.4, 1.6),
+ m_bIsChested(false),
+ m_bIsEating(false),
+ m_bIsRearing(false),
+ m_bIsMouthOpen(false),
+ m_bIsTame(false),
+ m_Type(Type),
+ m_Color(Color),
+ m_Style(Style),
+ m_Armour(0),
+ m_TimesToTame(TameTimes),
+ m_TameAttemptTimes(0)
{
}
@@ -16,6 +29,84 @@ cHorse::cHorse(void) :
+void cHorse::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (!m_bIsMouthOpen)
+ {
+ if (m_World->GetTickRandomNumber(50) == 25)
+ {
+ m_bIsMouthOpen = true;
+ }
+ }
+ else
+ {
+ if (m_World->GetTickRandomNumber(10) == 5)
+ {
+ m_bIsMouthOpen = false;
+ }
+ }
+
+ if ((m_Attachee != NULL) && (!m_bIsTame))
+ {
+ if (m_TameAttemptTimes < m_TimesToTame)
+ {
+ if (m_World->GetTickRandomNumber(50) == 25)
+ {
+ m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 0);
+ m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 2);
+ m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 6);
+ m_World->BroadcastSoundParticleEffect(2000, (int)(floor(GetPosX()) * 8), (int)(floor(GetPosY()) * 8), (int)(floor(GetPosZ()) * 8), 8);
+
+ m_Attachee->Detach();
+ m_bIsRearing = true;
+ }
+ }
+ else
+ {
+ m_bIsTame = true;
+ }
+ }
+
+ if ((m_bIsRearing) && (m_World->GetTickRandomNumber(15) == 6))
+ {
+ m_bIsRearing = false;
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cHorse::OnRightClicked(cPlayer & a_Player)
+{
+ if (m_Attachee != NULL)
+ {
+ if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
+ {
+ a_Player.Detach();
+ return;
+ }
+
+ if (m_Attachee->IsPlayer())
+ {
+ return;
+ }
+
+ m_Attachee->Detach();
+ }
+
+ m_TameAttemptTimes++;
+ a_Player.AttachTo(this);
+}
+
+
+
+
+
void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer)
{
AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER);
diff --git a/source/Mobs/Horse.h b/source/Mobs/Horse.h
index ea6e441bd..d950ff1bf 100644
--- a/source/Mobs/Horse.h
+++ b/source/Mobs/Horse.h
@@ -13,11 +13,28 @@ class cHorse :
typedef cPassiveMonster super;
public:
- cHorse(void);
+ cHorse(int Type, int Color, int Style, int TameTimes);
CLASS_PROTODEF(cHorse);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ bool IsChested (void) const {return m_bIsChested; }
+ bool IsEating (void) const {return m_bIsEating; }
+ bool IsRearing (void) const {return m_bIsRearing; }
+ bool IsMthOpen (void) const {return m_bIsMouthOpen; }
+ bool IsTame (void) const {return m_bIsTame; }
+ int GetHType (void) const {return m_Type; }
+ int GetHColor (void) const {return m_Color; }
+ int GetHStyle (void) const {return m_Style; }
+ int GetHArmour (void) const {return m_Armour;}
+
+private:
+
+ bool m_bIsChested, m_bIsEating, m_bIsRearing, m_bIsMouthOpen, m_bIsTame;
+ int m_Type, m_Color, m_Style, m_Armour, m_TimesToTame, m_TameAttemptTimes;
+
} ;
diff --git a/source/Mobs/Magmacube.h b/source/Mobs/Magmacube.h
index 80a1d0701..130952970 100644
--- a/source/Mobs/Magmacube.h
+++ b/source/Mobs/Magmacube.h
@@ -19,6 +19,7 @@ public:
CLASS_PROTODEF(cMagmaCube);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ int GetSize(void) const { return m_Size; }
protected:
diff --git a/source/Mobs/Pig.cpp b/source/Mobs/Pig.cpp
index 9df2c2571..cd18c087f 100644
--- a/source/Mobs/Pig.cpp
+++ b/source/Mobs/Pig.cpp
@@ -2,13 +2,16 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Pig.h"
+#include "../Entities/Player.h"
+#include "../World.h"
cPig::cPig(void) :
- super("Pig", 90, "mob.pig.say", "mob.pig.death", 0.9, 0.9)
+ super("Pig", 90, "mob.pig.say", "mob.pig.death", 0.9, 0.9),
+ m_bIsSaddled(false)
{
}
@@ -24,3 +27,47 @@ void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+
+void cPig::OnRightClicked(cPlayer & a_Player)
+{
+ if (m_bIsSaddled)
+ {
+ if (m_Attachee != NULL)
+ {
+ if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID())
+ {
+ // This player is already sitting in, they want out.
+ a_Player.Detach();
+ return;
+ }
+
+ if (m_Attachee->IsPlayer())
+ {
+ // Another player is already sitting in here, cannot attach
+ return;
+ }
+
+ // Detach whatever is sitting in this pig now:
+ m_Attachee->Detach();
+ }
+
+ // Attach the player to this pig
+ a_Player.AttachTo(this);
+ }
+ else if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ // Set saddle state & broadcast metadata
+ m_bIsSaddled = true;
+ m_World->BroadcastEntityMetadata(*this);
+ }
+}
+
+
+
+
+
diff --git a/source/Mobs/Pig.h b/source/Mobs/Pig.h
index ae790ac2f..4fd0d8db8 100644
--- a/source/Mobs/Pig.h
+++ b/source/Mobs/Pig.h
@@ -18,6 +18,13 @@ public:
CLASS_PROTODEF(cPig);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ bool IsSaddled(void) const { return m_bIsSaddled; }
+
+private:
+
+ bool m_bIsSaddled;
+
} ;
diff --git a/source/Mobs/Sheep.cpp b/source/Mobs/Sheep.cpp
index 2f371f384..440c5c2b9 100644
--- a/source/Mobs/Sheep.cpp
+++ b/source/Mobs/Sheep.cpp
@@ -3,15 +3,17 @@
#include "Sheep.h"
#include "../BlockID.h"
+#include "../Entities/Player.h"
+#include "../World.h"
-cSheep::cSheep(void) :
+cSheep::cSheep(int a_Color) :
super("Sheep", 91, "mob.sheep.say", "mob.sheep.say", 0.6, 1.3),
m_IsSheared(false),
- m_WoolColor(E_META_WOOL_WHITE)
+ m_WoolColor(a_Color)
{
}
@@ -30,3 +32,25 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer)
+
+void cSheep::OnRightClicked(cPlayer & a_Player)
+{
+ if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared))
+ {
+ m_IsSheared = true;
+ m_World->BroadcastEntityMetadata(*this);
+
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.UseEquippedItem();
+ }
+
+ cItems Drops;
+ Drops.push_back(cItem(E_BLOCK_WOOL, 4, m_WoolColor));
+ m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10);
+ }
+}
+
+
+
+
diff --git a/source/Mobs/Sheep.h b/source/Mobs/Sheep.h
index 369fc78c5..8293a2c05 100644
--- a/source/Mobs/Sheep.h
+++ b/source/Mobs/Sheep.h
@@ -13,14 +13,20 @@ class cSheep :
typedef cPassiveMonster super;
public:
- cSheep(void);
+ cSheep(int a_Color);
- bool m_IsSheared;
- NIBBLETYPE m_WoolColor; // Uses E_META_WOOL_ constants for colors
-
CLASS_PROTODEF(cSheep);
-
+
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ bool IsSheared(void) const { return m_IsSheared; }
+ int GetFurColor(void) const { return m_WoolColor; }
+
+private:
+
+ bool m_IsSheared;
+ int m_WoolColor;
+
} ;
diff --git a/source/Mobs/Skeleton.cpp b/source/Mobs/Skeleton.cpp
index 10dad4065..6297b867c 100644
--- a/source/Mobs/Skeleton.cpp
+++ b/source/Mobs/Skeleton.cpp
@@ -8,8 +8,9 @@
-cSkeleton::cSkeleton(void) :
- super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8)
+cSkeleton::cSkeleton(bool IsWither) :
+ super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8),
+ m_bIsWither(IsWither)
{
SetBurnsInDaylight(true);
}
diff --git a/source/Mobs/Skeleton.h b/source/Mobs/Skeleton.h
index d0a2da490..7a4af7e22 100644
--- a/source/Mobs/Skeleton.h
+++ b/source/Mobs/Skeleton.h
@@ -13,11 +13,17 @@ class cSkeleton :
typedef cAggressiveMonster super;
public:
- cSkeleton();
+ cSkeleton(bool IsWither);
CLASS_PROTODEF(cSkeleton);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ bool IsWither(void) const { return m_bIsWither; };
+
+private:
+
+ bool m_bIsWither;
+
} ;
diff --git a/source/Mobs/Slime.cpp b/source/Mobs/Slime.cpp
index b209ac869..7a9487a06 100644
--- a/source/Mobs/Slime.cpp
+++ b/source/Mobs/Slime.cpp
@@ -3,8 +3,6 @@
#include "Slime.h"
-// TODO: Implement sized slimes
-
diff --git a/source/Mobs/Slime.h b/source/Mobs/Slime.h
index 88136ff32..782c3113f 100644
--- a/source/Mobs/Slime.h
+++ b/source/Mobs/Slime.h
@@ -19,6 +19,7 @@ public:
CLASS_PROTODEF(cSlime);
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
+ int GetSize(void) const { return m_Size; }
protected:
diff --git a/source/Mobs/Villager.cpp b/source/Mobs/Villager.cpp
index 98e5276e1..cb50d8cfc 100644
--- a/source/Mobs/Villager.cpp
+++ b/source/Mobs/Villager.cpp
@@ -2,16 +2,34 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Villager.h"
+#include "../World.h"
-cVillager::cVillager(void) :
- super("Villager", 120, "", "", 0.6, 1.8)
+cVillager::cVillager(int Type) :
+ super("Villager", 120, "", "", 0.6, 1.8),
+ m_Type(Type)
{
}
+
+void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ super::DoTakeDamage(a_TDI);
+ if (a_TDI.Attacker->IsPlayer())
+ {
+ if (m_World->GetTickRandomNumber(5) == 3)
+ {
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY);
+ }
+ }
+}
+
+
+
+
diff --git a/source/Mobs/Villager.h b/source/Mobs/Villager.h
index 92267a979..5fcb519dd 100644
--- a/source/Mobs/Villager.h
+++ b/source/Mobs/Villager.h
@@ -13,9 +13,17 @@ class cVillager :
typedef cPassiveMonster super;
public:
- cVillager();
+ cVillager(int Type);
CLASS_PROTODEF(cVillager);
+
+ virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ int GetVilType(void) const { return m_Type; }
+
+private:
+
+ int m_Type;
+
} ;
diff --git a/source/Mobs/Wolf.cpp b/source/Mobs/Wolf.cpp
new file mode 100644
index 000000000..e76f991dc
--- /dev/null
+++ b/source/Mobs/Wolf.cpp
@@ -0,0 +1,79 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Wolf.h"
+#include "../World.h"
+#include "../Entities/Player.h"
+
+
+
+
+
+cWolf::cWolf(void) :
+ super("Wolf", 95, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8),
+ m_bIsAngry(false),
+ m_bIsTame(false),
+ m_bIsSitting(false),
+ m_bIsBegging(false)
+{
+}
+
+
+
+
+
+void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
+{
+ super::DoTakeDamage(a_TDI);
+ if (!m_bIsTame)
+ {
+ m_bIsAngry = true;
+ }
+ m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
+}
+
+
+
+
+
+void cWolf::OnRightClicked(cPlayer & a_Player)
+{
+ if ((!m_bIsTame) && (!m_bIsAngry))
+ {
+ if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_BONE)
+ {
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+
+ if (m_World->GetTickRandomNumber(10) == 5)
+ {
+ SetMaxHealth(20);
+ m_bIsTame = true;
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED);
+ }
+ else
+ {
+ m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING);
+ }
+ }
+ }
+ else if (m_bIsTame)
+ {
+ if (m_bIsSitting)
+ {
+ m_bIsSitting = false;
+ }
+ else
+ {
+ m_bIsSitting = true;
+ }
+ }
+
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
diff --git a/source/Mobs/Wolf.h b/source/Mobs/Wolf.h
index 405df80a6..98074ba11 100644
--- a/source/Mobs/Wolf.h
+++ b/source/Mobs/Wolf.h
@@ -13,13 +13,25 @@ class cWolf :
typedef cPassiveAggressiveMonster super;
public:
- cWolf(void) :
- // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here (wiki.vg values are suspicious)
- super("Wolf", 95, "mob.wolf.hurt", "mob.wolf.death", 0.9, 0.9)
- {
- }
+ cWolf(void);
CLASS_PROTODEF(cWolf);
+
+ virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+
+ bool IsSitting(void) const { return m_bIsSitting; }
+ bool IsTame(void) const { return m_bIsTame; }
+ bool IsBegging(void) const { return m_bIsBegging; }
+ bool IsAngry(void) const { return m_bIsAngry; }
+
+private:
+
+ bool m_bIsSitting;
+ bool m_bIsTame;
+ bool m_bIsBegging;
+ bool m_bIsAngry;
+
} ;
diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp
index 54bd28c9f..89b2c15ec 100644
--- a/source/Protocol/Protocol125.cpp
+++ b/source/Protocol/Protocol125.cpp
@@ -343,8 +343,9 @@ void cProtocol125::SendEntityMetadata(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_METADATA);
WriteInt (a_Entity.GetUniqueID());
- AString MetaData = GetEntityMetaData(a_Entity);
- SendData(MetaData.data(), MetaData.size());
+
+ WriteMetadata(a_Entity);
+
Flush();
}
@@ -710,8 +711,7 @@ void cProtocol125::SendSpawnMob(const cMonster & a_Mob)
WriteByte (0);
WriteByte (0);
WriteByte (0);
- AString MetaData = GetEntityMetaData(a_Mob);
- SendData (MetaData.data(), MetaData.size());
+ WriteMetadata(a_Mob);
Flush();
}
@@ -1614,48 +1614,212 @@ int cProtocol125::ParseItem(cItem & a_Item)
-AString cProtocol125::GetEntityMetaData(const cEntity & a_Entity)
+void cProtocol125::WriteMetadata(const cEntity & a_Entity)
{
- // We should send all the metadata here
- AString MetaData;
- // Common metadata (index 0, byte):
- MetaData.push_back(0);
- MetaData.push_back(GetEntityMetadataFlags(a_Entity));
-
- // TODO: Add more entity-specific metadata
-
- MetaData.push_back(0x7f); // End metadata
- return MetaData;
-}
+ // Common Metadata
+ Byte CommonMetadata = 0;
-
-
-
-char cProtocol125::GetEntityMetadataFlags(const cEntity & a_Entity)
-{
- char Flags = 0;
if (a_Entity.IsOnFire())
{
- Flags |= 1;
+ CommonMetadata |= 0x1;
}
if (a_Entity.IsCrouched())
{
- Flags |= 2;
+ CommonMetadata |= 0x2;
}
if (a_Entity.IsRiding())
{
- Flags |= 4;
+ CommonMetadata |= 0x4;
}
if (a_Entity.IsSprinting())
{
- Flags |= 8;
+ CommonMetadata |= 0x8;
}
if (a_Entity.IsRclking())
{
- Flags |= 16;
+ CommonMetadata |= 0x16;
+ }
+ if (a_Entity.IsInvisible())
+ {
+ CommonMetadata |= 0x32;
+ }
+
+ WriteByte(0x0);
+ WriteByte(CommonMetadata);
+
+ // Common Metadata End
+ // Specific Entity Metadata
+
+ if (a_Entity.IsMinecart())
+ {
+ WriteByte(0x51);
+ // No idea how Mojang makes their carts shakey shakey, so here is a complicated one-liner expression that does something similar
+ WriteInt( (((a_Entity.GetMaxHealth() / 2) - (a_Entity.GetHealth() - (a_Entity.GetMaxHealth() / 2))) * a_Entity.LastDamage()) * 4 );
+ WriteByte(0x52);
+ WriteInt(1); // Shaking direction, doesn't seem to affect anything
+ WriteByte(0x73);
+ WriteFloat((float)(a_Entity.LastDamage() + 10)); // Damage taken / shake effect multiplyer
+ }
+ else if (a_Entity.IsA("cCreeper"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsBlowing() ? 1 : -1); // Blowing up?
+ WriteByte(0x11);
+ WriteByte(a_Entity.IsCharged() ? 1 : 0); // Lightning-charged?
+ }
+ else if (a_Entity.IsA("cMinecartWithFurnace"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsFueled() ? 1 : 0); // Fueled?
+ }
+ else if (a_Entity.IsA("cBat"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsHanging() ? 1 : 0); // Upside down?
+ }
+ else if (a_Entity.IsA("cPig"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsSaddled() ? 1 : 0); // Saddled?
+ }
+ else if (a_Entity.IsA("cVillager"))
+ {
+ WriteByte(0x50);
+ WriteInt(a_Entity.GetVilType()); // What sort of TESTIFICATE?
+ }
+ else if (a_Entity.IsA("cZombie"))
+ {
+ WriteByte(0xC);
+ WriteByte(a_Entity.IsBabby() ? 1 : 0); // Babby zombie?
+ WriteByte(0xD);
+ WriteByte(a_Entity.IsVillZomb() ? 1 : 0); // Converted zombie?
+ WriteByte(0xE);
+ WriteByte(a_Entity.IsConvert() ? 1 : 0); // Converted-but-converting-back zombllager?
+ }
+ else if (a_Entity.IsA("cGhast"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsCharging()); // About to eject un flamé-bol? :P
+ }
+ else if (a_Entity.IsA("cArrowEntity"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.IsCritical() ? 1 : 0); // Critical hitting arrow?
+ }
+ else if (a_Entity.IsA("cWolf"))
+ {
+ Byte WolfStatus = 0;
+ if (a_Entity.IsSitting())
+ {
+ WolfStatus |= 0x1;
+ }
+ if (a_Entity.IsAngry())
+ {
+ WolfStatus |= 0x2;
+ }
+ if (a_Entity.IsTame())
+ {
+ WolfStatus |= 0x4;
+ }
+ WriteByte(0x10);
+ WriteByte(WolfStatus);
+
+ WriteByte(0x72);
+ WriteFloat((float)(a_Entity.GetHealth())); // Tail health-o-meter (only shown when tamed, by the way)
+ WriteByte(0x13);
+ WriteByte(a_Entity.IsBegging() ? 1 : 0); // Ultra cute mode?
+ }
+ else if (a_Entity.IsA("cSheep"))
+ {
+ // [1](1111)
+ // [] = Is sheared? () = Color, from 0 to 15
+
+ WriteByte(0x10);
+ Byte SheepMetadata = 0;
+ SheepMetadata = a_Entity.GetFurColor(); // Fur colour
+
+ if (a_Entity.IsSheared()) // Is sheared?
+ {
+ SheepMetadata |= 0x16;
+ }
+ WriteByte(SheepMetadata);
+ }
+ else if (a_Entity.IsA("cEnderman"))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.CarriedBlock()); // Stolen block
+ WriteByte(0x11);
+ WriteByte(a_Entity.CarriedMeta()); // Stolen metea
+ WriteByte(0x12);
+ WriteByte(a_Entity.IsScream() ? 1 : 0); // I HATE YER FACE, I SCWEAM AT YER FACE
+ }
+ else if (a_Entity.IsA("cSkeleton"))
+ {
+ WriteByte(0xD);
+ WriteByte(a_Entity.IsWither() ? 1 : 0); // It's a skeleton, but it's not
+ }
+ else if (a_Entity.IsA("cWitch"))
+ {
+ WriteByte(0x15);
+ WriteByte(a_Entity.IsNosey() ? 1 : 0); // Drinking-nose: like Squidward
+ }
+ else if ((a_Entity.IsA("cSlime")) || (a_Entity.IsA("cMagmaCube")))
+ {
+ WriteByte(0x10);
+ WriteByte(a_Entity.GetSize()); // Size of slime - HEWGE, meh, cute BABBY SLIME
+ }
+ else if (a_Entity.IsA("cHorse"))
+ {
+ int Flags = 0;
+ if (a_Entity.IsTame())
+ {
+ Flags |= 0x2;
+ }
+ if (a_Entity.IsSaddled())
+ {
+ Flags |= 0x4;
+ }
+ if (a_Entity.IsChested())
+ {
+ Flags |= 0x8;
+ }
+ if (a_Entity.IsBabby())
+ {
+ Flags |= 0x10; // IsBred flag, according to wiki.vg - don't think it does anything in multiplayer
+ }
+ if (a_Entity.IsEating())
+ {
+ Flags |= 0x20;
+ }
+ if (a_Entity.IsRearing())
+ {
+ Flags |= 0x40;
+ }
+ if (a_Entity.IsMthOpen())
+ {
+ Flags |= 0x80;
+ }
+ WriteByte(0x50);
+ WriteInt(Flags);
+
+ WriteByte(0x13);
+ WriteByte(a_Entity.GetHType()); // Type of horse (donkey, chestnut, etc.)
+
+ WriteByte(0x54);
+ int Appearance = 0;
+ Appearance = a_Entity.GetHColor(); // Mask FF
+ Appearance |= a_Entity.GetHStyle() * 256; // Mask FF00, so multiply by 256
+ WriteInt(Appearance);
+
+ WriteByte(0x56);
+ WriteInt(a_Entity.GetHArmour()); // Horshey armour
}
- return Flags;
+
+ // End Specific Metadata
+ // End Metadata Packet
+
+ WriteByte(0x7f);
}
diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h
index c5c8cd1a0..7b493881b 100644
--- a/source/Protocol/Protocol125.h
+++ b/source/Protocol/Protocol125.h
@@ -142,11 +142,8 @@ protected:
/// Parses one item, "slot" as the protocol wiki calls it, from m_ReceivedData; returns the usual ParsePacket() codes
virtual int ParseItem(cItem & a_Item);
- /// Returns the entity metadata representation
- AString GetEntityMetaData(const cEntity & a_Entity);
-
- /// Returns the entity common metadata, index 0 (generic flags)
- char GetEntityMetadataFlags(const cEntity & a_Entity);
+ /// Writes the entity metadata
+ void WriteMetadata(const cEntity & a_Entity);
} ;
diff --git a/source/Protocol/Protocol132.cpp b/source/Protocol/Protocol132.cpp
index a06eb0b8b..63b838b70 100644
--- a/source/Protocol/Protocol132.cpp
+++ b/source/Protocol/Protocol132.cpp
@@ -416,8 +416,7 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
WriteShort ((short)(a_Mob.GetSpeedX() * 400));
WriteShort ((short)(a_Mob.GetSpeedY() * 400));
WriteShort ((short)(a_Mob.GetSpeedZ() * 400));
- AString MetaData = GetEntityMetaData(a_Mob);
- SendData (MetaData.data(), MetaData.size());
+ WriteMetadata(a_Mob);
Flush();
}
diff --git a/source/World.cpp b/source/World.cpp
index 606ef0787..784df49f3 100644
--- a/source/World.cpp
+++ b/source/World.cpp
@@ -2571,40 +2571,53 @@ bool cWorld::IsBlockDirectlyWatered(int a_BlockX, int a_BlockY, int a_BlockZ)
int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType)
{
cMonster * Monster = NULL;
+
+ int SlSize = GetTickRandomNumber(2) + 1; // 1 .. 3 - Slime
+ int ShColor = GetTickRandomNumber(15); // 0 .. 15 - Sheep
+ bool SkType = GetDimension() == biNether; // Skeleton
+ int VilType = GetTickRandomNumber(5); // 0 .. 5 - Villager
+
+ int HseType = GetTickRandomNumber(7); // 0 .. 7 - Horse Type (donkey, zombie, etc.)
+ int HseColor = GetTickRandomNumber(6); // 0 .. 6 - Horse
+ int HseStyle = GetTickRandomNumber(4); // 0 .. 4 - Horse
+ int HseTameTimes = GetTickRandomNumber(6) + 1; // 1 .. 7 - Horse tame amount
- int Size = GetTickRandomNumber(2) + 1; // 1 .. 3
+ if ((HseType == 5) || (HseType == 6) || (HseType == 7)) { HseType = 0; } // 5,6,7 = 0 because little chance of getting 0 with TickRand
switch (a_MonsterType)
{
- case cMonster::mtBat: Monster = new cBat(); break;
- case cMonster::mtBlaze: Monster = new cBlaze(); break;
- case cMonster::mtCaveSpider: Monster = new cCavespider(); break;
- case cMonster::mtChicken: Monster = new cChicken(); break;
- case cMonster::mtCow: Monster = new cCow(); break;
- case cMonster::mtCreeper: Monster = new cCreeper(); break;
- case cMonster::mtEnderman: Monster = new cEnderman(); break;
- case cMonster::mtEnderDragon: Monster = new cEnderDragon(); break;
- case cMonster::mtGhast: Monster = new cGhast(); break;
- case cMonster::mtGiant: Monster = new cGiant(); break;
- case cMonster::mtHorse: Monster = new cHorse(); break;
- case cMonster::mtIronGolem: Monster = new cIronGolem(); break;
- case cMonster::mtMagmaCube: Monster = new cMagmaCube(Size); break;
- case cMonster::mtMooshroom: Monster = new cMooshroom(); break;
- case cMonster::mtOcelot: Monster = new cOcelot(); break;
- case cMonster::mtPig: Monster = new cPig(); break;
- case cMonster::mtSheep: Monster = new cSheep(); break;
- case cMonster::mtSilverfish: Monster = new cSilverfish(); break;
- case cMonster::mtSkeleton: Monster = new cSkeleton(); break;
- case cMonster::mtSlime: Monster = new cSlime(Size); break;
- case cMonster::mtSnowGolem: Monster = new cSnowGolem(); break;
- case cMonster::mtSpider: Monster = new cSpider(); break;
- case cMonster::mtSquid: Monster = new cSquid(); break;
- case cMonster::mtVillager: Monster = new cVillager(); break;
- case cMonster::mtWitch: Monster = new cWitch(); break;
- case cMonster::mtWither: Monster = new cWither(); break;
- case cMonster::mtWolf: Monster = new cWolf(); break;
- case cMonster::mtZombie: Monster = new cZombie(); break;
- case cMonster::mtZombiePigman: Monster = new cZombiePigman(); break;
+ case cMonster::mtBat: Monster = new cBat(); break;
+ case cMonster::mtBlaze: Monster = new cBlaze(); break;
+ case cMonster::mtCaveSpider: Monster = new cCavespider(); break;
+ case cMonster::mtChicken: Monster = new cChicken(); break;
+ case cMonster::mtCow: Monster = new cCow(); break;
+ case cMonster::mtCreeper: Monster = new cCreeper(); break;
+ case cMonster::mtEnderman: Monster = new cEnderman(); break;
+ case cMonster::mtEnderDragon: Monster = new cEnderDragon(); break;
+ case cMonster::mtGhast: Monster = new cGhast(); break;
+ case cMonster::mtGiant: Monster = new cGiant(); break;
+ case cMonster::mtHorse:
+ {
+ Monster = new cHorse(HseType, HseColor, HseStyle, HseTameTimes); break;
+ }
+ case cMonster::mtIronGolem: Monster = new cIronGolem(); break;
+ case cMonster::mtMagmaCube: Monster = new cMagmaCube(SlSize); break;
+ case cMonster::mtMooshroom: Monster = new cMooshroom(); break;
+ case cMonster::mtOcelot: Monster = new cOcelot(); break;
+ case cMonster::mtPig: Monster = new cPig(); break;
+ case cMonster::mtSheep: Monster = new cSheep(ShColor); break;
+ case cMonster::mtSilverfish: Monster = new cSilverfish(); break;
+ case cMonster::mtSkeleton: Monster = new cSkeleton(SkType); break;
+ case cMonster::mtSlime: Monster = new cSlime(SlSize); break;
+ case cMonster::mtSnowGolem: Monster = new cSnowGolem(); break;
+ case cMonster::mtSpider: Monster = new cSpider(); break;
+ case cMonster::mtSquid: Monster = new cSquid(); break;
+ case cMonster::mtVillager: Monster = new cVillager(VilType); break;
+ case cMonster::mtWitch: Monster = new cWitch(); break;
+ case cMonster::mtWither: Monster = new cWither(); break;
+ case cMonster::mtWolf: Monster = new cWolf(); break;
+ case cMonster::mtZombie: Monster = new cZombie(); break;
+ case cMonster::mtZombiePigman: Monster = new cZombiePigman(); break;
default:
{
@@ -2624,7 +2637,11 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp
delete Monster;
return -1;
}
+
BroadcastSpawnEntity(*Monster);
+ // Because it's logical that ALL mob spawns need spawn effects, not just spawners
+ BroadcastSoundParticleEffect(2004, (int)(floor(a_PosX) * 8), (int)(floor(a_PosY) * 8), (int)(floor(a_PosZ) * 8), 0);
+
cPluginManager::Get()->CallHookSpawnedMonster(*this, *Monster);
return Monster->GetUniqueID();
}