From 5db6213f34318031ece7e2a6765f69564b671891 Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Tue, 8 Oct 2013 19:20:49 +0100 Subject: [PATCH] Initial Metadata Commit [SEE DESC] + Pigs, Minecarts, Sheep, Skeletons, Slimes, Villagers, Wolves, and Horses have metadata + Base code on taming wolves, shearing sheep, and taming horses + Sheep and horses have different colours when spawned --- VC2008/MCServer.vcproj | 4 + source/Entities/Entity.h | 63 +++++++++ source/Entities/Minecart.cpp | 58 ++++++++- source/Entities/Minecart.h | 13 +- source/Mobs/Horse.cpp | 95 +++++++++++++- source/Mobs/Horse.h | 19 ++- source/Mobs/Magmacube.h | 1 + source/Mobs/Pig.cpp | 49 ++++++- source/Mobs/Pig.h | 7 + source/Mobs/Sheep.cpp | 28 +++- source/Mobs/Sheep.h | 16 ++- source/Mobs/Skeleton.cpp | 5 +- source/Mobs/Skeleton.h | 8 +- source/Mobs/Slime.cpp | 2 - source/Mobs/Slime.h | 1 + source/Mobs/Villager.cpp | 22 +++- source/Mobs/Villager.h | 10 +- source/Mobs/Wolf.cpp | 79 ++++++++++++ source/Mobs/Wolf.h | 22 +++- source/Protocol/Protocol125.cpp | 220 ++++++++++++++++++++++++++++---- source/Protocol/Protocol125.h | 7 +- source/Protocol/Protocol132.cpp | 3 +- source/World.cpp | 77 ++++++----- 23 files changed, 714 insertions(+), 95 deletions(-) create mode 100644 source/Mobs/Wolf.cpp diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index c1c2593bf..cf1bb5b77 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1139,6 +1139,10 @@ RelativePath="..\source\Mobs\Wither.h" > + + 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; } - return Flags; + 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 + } + + // 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 Size = GetTickRandomNumber(2) + 1; // 1 .. 3 + 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 + + 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(); }