summaryrefslogtreecommitdiffstats
path: root/src/Entities
diff options
context:
space:
mode:
Diffstat (limited to 'src/Entities')
-rw-r--r--src/Entities/Entity.h4
-rw-r--r--src/Entities/ExpOrb.cpp7
-rw-r--r--src/Entities/ItemFrame.cpp124
-rw-r--r--src/Entities/ItemFrame.h42
-rw-r--r--src/Entities/Painting.cpp43
-rw-r--r--src/Entities/Painting.h42
-rw-r--r--src/Entities/Player.cpp17
-rw-r--r--src/Entities/Player.h4
-rw-r--r--src/Entities/ProjectileEntity.cpp1
9 files changed, 279 insertions, 5 deletions
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index b2edfc2b4..b3b1cef83 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -81,6 +81,8 @@ public:
etProjectile,
etExpOrb,
etFloater,
+ etItemFrame,
+ etPainting,
// Common variations
etMob = etMonster, // DEPRECATED, use etMonster instead!
@@ -139,6 +141,8 @@ public:
bool IsProjectile (void) const { return (m_EntityType == etProjectile); }
bool IsExpOrb (void) const { return (m_EntityType == etExpOrb); }
bool IsFloater (void) const { return (m_EntityType == etFloater); }
+ bool IsItemFrame (void) const { return (m_EntityType == etItemFrame); }
+ bool IsPainting (void) const { return (m_EntityType == etPainting); }
/// Returns true if the entity is of the specified class or a subclass (cPawn's IsA("cEntity") returns true)
virtual bool IsA(const char * a_ClassName) const;
diff --git a/src/Entities/ExpOrb.cpp b/src/Entities/ExpOrb.cpp
index 04ee85823..3398f1c7b 100644
--- a/src/Entities/ExpOrb.cpp
+++ b/src/Entities/ExpOrb.cpp
@@ -51,7 +51,10 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
{
LOGD("Player %s picked up an ExpOrb. His reward is %i", a_ClosestPlayer->GetName().c_str(), m_Reward);
a_ClosestPlayer->DeltaExperience(m_Reward);
- Destroy(true);
+
+ m_World->BroadcastSoundEffect("random.orb", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
+
+ Destroy();
}
a_Distance.Normalize();
a_Distance *= ((float) (5.5 - Distance));
@@ -61,4 +64,4 @@ void cExpOrb::Tick(float a_Dt, cChunk & a_Chunk)
BroadcastMovementUpdate();
}
HandlePhysics(a_Dt, a_Chunk);
-} \ No newline at end of file
+}
diff --git a/src/Entities/ItemFrame.cpp b/src/Entities/ItemFrame.cpp
new file mode 100644
index 000000000..8cfa5e18d
--- /dev/null
+++ b/src/Entities/ItemFrame.cpp
@@ -0,0 +1,124 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "ItemFrame.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cItemFrame::cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z)
+ : cEntity(etItemFrame, a_X, a_Y, a_Z, 0.8, 0.8),
+ m_BlockFace(a_BlockFace),
+ m_Item(E_BLOCK_AIR),
+ m_Rotation(0)
+{
+ SetMaxHealth(1);
+ SetHealth(1);
+}
+
+
+
+
+
+void cItemFrame::SpawnOn(cClientHandle & a_ClientHandle)
+{
+ int Dir = 0;
+
+ // The client uses different values for item frame directions and block faces. Our constants are for the block faces, so we convert them here to item frame faces
+ switch (m_BlockFace)
+ {
+ case BLOCK_FACE_ZP: break; // Initialised to zero
+ case BLOCK_FACE_ZM: Dir = 2; break;
+ case BLOCK_FACE_XM: Dir = 1; break;
+ case BLOCK_FACE_XP: Dir = 3; break;
+ default: ASSERT(!"Unhandled block face when trying to spawn item frame!"); return;
+ }
+
+ if ((Dir == 0) || (Dir == 2)) // Probably a client bug, but two directions are flipped and contrary to the norm, so we do -180
+ {
+ SetYaw((Dir * 90) - 180);
+ }
+ else
+ {
+ SetYaw(Dir * 90);
+ }
+
+ a_ClientHandle.SendSpawnObject(*this, 71, Dir, (Byte)GetYaw(), (Byte)GetPitch());
+}
+
+
+
+
+
+void cItemFrame::OnRightClicked(cPlayer & a_Player)
+{
+ if (!m_Item.IsEmpty())
+ {
+ // Item not empty, rotate, clipping values to zero to three inclusive
+ m_Rotation++;
+ if (m_Rotation >= 4)
+ {
+ m_Rotation = 0;
+ }
+ }
+ else if (!a_Player.GetEquippedItem().IsEmpty())
+ {
+ // Item empty, and player held item not empty - add this item to self
+ m_Item = a_Player.GetEquippedItem();
+ m_Item.m_ItemCount = 1;
+
+ if (!a_Player.IsGameModeCreative())
+ {
+ a_Player.GetInventory().RemoveOneEquippedItem();
+ }
+ }
+
+ GetWorld()->BroadcastEntityMetadata(*this); // Update clients
+}
+
+
+
+
+
+
+void cItemFrame::KilledBy(cEntity * a_Killer)
+{
+ if (m_Item.IsEmpty())
+ {
+ super::KilledBy(a_Killer);
+ Destroy();
+ return;
+ }
+
+ if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
+ {
+ cItems Item;
+ Item.push_back(m_Item);
+
+ GetWorld()->SpawnItemPickups(Item, GetPosX(), GetPosY(), GetPosZ());
+ }
+
+ SetHealth(GetMaxHealth());
+ m_Item.Clear();
+ m_Rotation = 0;
+ GetWorld()->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cItemFrame::GetDrops(cItems & a_Items, cEntity * a_Killer)
+{
+ if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
+ {
+ a_Items.push_back(cItem(E_ITEM_ITEM_FRAME));
+ }
+}
+
+
+
+
diff --git a/src/Entities/ItemFrame.h b/src/Entities/ItemFrame.h
new file mode 100644
index 000000000..43915e3f9
--- /dev/null
+++ b/src/Entities/ItemFrame.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cItemFrame :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+
+ CLASS_PROTODEF(cItemFrame);
+
+ cItemFrame(eBlockFace a_BlockFace, double a_X, double a_Y, double a_Z);
+
+ const cItem & GetItem(void) { return m_Item; }
+ Byte GetRotation(void) const { return m_Rotation; }
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
+ virtual void OnRightClicked(cPlayer & a_Player) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+ virtual void KilledBy(cEntity * a_Killer) override;
+ virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
+
+ eBlockFace m_BlockFace;
+ cItem m_Item;
+ Byte m_Rotation;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/Painting.cpp b/src/Entities/Painting.cpp
new file mode 100644
index 000000000..b98c1e67a
--- /dev/null
+++ b/src/Entities/Painting.cpp
@@ -0,0 +1,43 @@
+
+#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
+
+#include "Painting.h"
+#include "ClientHandle.h"
+#include "Player.h"
+
+
+
+
+
+cPainting::cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z)
+ : cEntity(etPainting, a_X, a_Y, a_Z, 1, 1),
+ m_Name(a_Name),
+ m_Direction(a_Direction)
+{
+}
+
+
+
+
+
+
+void cPainting::SpawnOn(cClientHandle & a_Client)
+{
+ a_Client.SendPaintingSpawn(*this);
+}
+
+
+
+
+
+void cPainting::GetDrops(cItems & a_Items, cEntity * a_Killer)
+{
+ if ((a_Killer != NULL) && a_Killer->IsPlayer() && !((cPlayer *)a_Killer)->IsGameModeCreative())
+ {
+ a_Items.push_back(cItem(E_ITEM_PAINTING));
+ }
+}
+
+
+
+
diff --git a/src/Entities/Painting.h b/src/Entities/Painting.h
new file mode 100644
index 000000000..95afbed1e
--- /dev/null
+++ b/src/Entities/Painting.h
@@ -0,0 +1,42 @@
+
+#pragma once
+
+#include "Entity.h"
+
+
+
+
+
+// tolua_begin
+class cPainting :
+ public cEntity
+{
+ // tolua_end
+ typedef cEntity super;
+
+public:
+ CLASS_PROTODEF(cPainting);
+
+ cPainting(const AString & a_Name, int a_Direction, double a_X, double a_Y, double a_Z);
+ const AString & GetName(void) const { return m_Name; } // tolua_export
+ int GetDirection(void) const { return m_Direction; } // tolua_export
+
+private:
+
+ virtual void SpawnOn(cClientHandle & a_Client) override;
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override {};
+ virtual void GetDrops(cItems & a_Items, cEntity * a_Killer) override;
+ virtual void KilledBy(cEntity * a_Killer) override
+ {
+ super::KilledBy(a_Killer);
+ Destroy();
+ }
+
+ AString m_Name;
+ int m_Direction;
+
+}; // tolua_export
+
+
+
+
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index fdf8d4303..0152bfc5b 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -842,6 +842,12 @@ void cPlayer::KilledBy(cEntity * a_Killer)
cItems Pickups;
m_Inventory.CopyToItems(Pickups);
m_Inventory.Clear();
+
+ if (GetName() == "Notch")
+ {
+ Pickups.Add(cItem(E_ITEM_RED_APPLE));
+ }
+
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
SaveToDisk(); // Save it, yeah the world is a tough place !
@@ -1125,8 +1131,9 @@ void cPlayer::SetIP(const AString & a_IP)
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
{
- SetPosition( a_PosX, a_PosY, a_PosZ );
+ SetPosition(a_PosX, a_PosY, a_PosZ);
m_LastGroundHeight = (float)a_PosY;
+ m_LastJumpHeight = (float)a_PosY;
m_World->BroadcastTeleportEntity(*this, GetClientHandle());
m_ClientHandle->SendPlayerMoveLook();
@@ -1760,6 +1767,12 @@ void cPlayer::HandleFood(void)
{
// Ref.: http://www.minecraftwiki.net/wiki/Hunger
+ if (IsGameModeCreative())
+ {
+ // Hunger is disabled for Creative
+ return;
+ }
+
// Remember the food level before processing, for later comparison
int LastFoodLevel = m_FoodLevel;
@@ -1777,7 +1790,7 @@ void cPlayer::HandleFood(void)
Heal(1);
m_FoodExhaustionLevel += 3;
}
- else if (m_FoodLevel <= 0)
+ else if ((m_FoodLevel <= 0) && (m_Health > 1))
{
// Damage from starving
TakeDamage(dtStarving, NULL, 1, 1, 0);
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index 7db9544cb..a795bb9eb 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -203,6 +203,7 @@ public:
void SendMessageWarning (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtWarning); }
void SendMessageFatal (const AString & a_Message) { m_ClientHandle->SendChat(a_Message, mtFailure); }
void SendMessagePrivateMsg(const AString & a_Message, const AString & a_Sender) { m_ClientHandle->SendChat(a_Message, mtPrivateMessage, a_Sender); }
+ void SendMessage (const cCompositeChat & a_Message) { m_ClientHandle->SendChat(a_Message); }
const AString & GetName(void) const { return m_PlayerName; }
void SetName(const AString & a_Name) { m_PlayerName = a_Name; }
@@ -225,7 +226,8 @@ public:
// tolua_begin
- /// Returns the full color code to use for this player, based on their primary group or set in m_Color
+ /** Returns the full color code to use for this player, based on their primary group or set in m_Color.
+ The returned value includes the cChatColor::Delimiter. */
AString GetColor(void) const;
/** tosses the item in the selected hotbar slot */
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index a3fa9d557..ef82c6e94 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -680,6 +680,7 @@ super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
{
// Spawn an experience orb with a reward between 3 and 11.
+ m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
Destroy();