summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/ClientHandle.cpp25
-rw-r--r--source/ClientHandle.h8
-rw-r--r--source/Defines.h4
-rw-r--r--source/Items/ItemFood.h66
-rw-r--r--source/Items/ItemHandler.cpp15
-rw-r--r--source/Items/ItemHandler.h17
-rw-r--r--source/Player.cpp99
-rw-r--r--source/Player.h64
-rw-r--r--source/World.h11
9 files changed, 235 insertions, 74 deletions
diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp
index 155eac38a..d66e47d32 100644
--- a/source/ClientHandle.cpp
+++ b/source/ClientHandle.cpp
@@ -555,11 +555,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
if (ItemHandler->IsFood())
{
- if (PlgMgr->CallHookPlayerEating(*m_Player))
- {
- // A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
- return;
- }
+ m_Player->AbortEating();
+ return;
}
else
{
@@ -569,7 +566,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return;
}
}
- LOGINFO("%s: Status SHOOT / EAT not implemented", __FUNCTION__);
+ LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return;
}
@@ -804,15 +801,19 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
}
else if (ItemHandler->IsFood())
{
- cItem Item;
- Item.m_ItemType = Equipped.m_ItemType;
- Item.m_ItemCount = 1;
- if (ItemHandler->EatItem(m_Player, &Item))
+ if (m_Player->IsSatiated())
{
- ItemHandler->OnFoodEaten(World, m_Player, &Item);
- m_Player->GetInventory().RemoveOneEquippedItem();
+ // The player is satiated, they cannot eat
return;
}
+ m_Player->StartEating();
+ if (PlgMgr->CallHookPlayerEating(*m_Player))
+ {
+ // A plugin won't let us eat, abort (send the proper packets to the client, too):
+ m_Player->AbortEating();
+ return;
+ }
+ return;
}
else
{
diff --git a/source/ClientHandle.h b/source/ClientHandle.h
index a06aca39f..9cf1a3326 100644
--- a/source/ClientHandle.h
+++ b/source/ClientHandle.h
@@ -281,6 +281,9 @@ private:
/// Buffer for received messages to be processed in the Tick thread
AStringList m_PendingMessages;
+
+ static int s_ClientCount;
+ int m_UniqueID;
@@ -307,14 +310,11 @@ private:
/// Processes the messages in m_PendingMessages; called from the Tick thread
void ProcessPendingMessages(void);
-
+
// cSocketThreads::cCallback overrides:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
virtual void SocketClosed (void) override; // The socket has been closed for any reason
-
- static int s_ClientCount;
- int m_UniqueID;
}; // tolua_export
diff --git a/source/Defines.h b/source/Defines.h
index f52050a9b..94e618eb0 100644
--- a/source/Defines.h
+++ b/source/Defines.h
@@ -116,6 +116,10 @@ enum eGameMode
gmSurvival = eGameMode_Survival,
gmCreative = eGameMode_Creative,
gmAdventure = eGameMode_Adventure,
+
+ // These two are used to check GameMode for validity when converting from integers.
+ gmMax, // Gets automatically assigned
+ gmMin = 0,
} ;
diff --git a/source/Items/ItemFood.h b/source/Items/ItemFood.h
index d4c0a012a..4ec2f7a36 100644
--- a/source/Items/ItemFood.h
+++ b/source/Items/ItemFood.h
@@ -4,53 +4,53 @@
#include "ItemHandler.h"
-class cItemFoodHandler : public cItemHandler
+
+
+
+class cItemFoodHandler :
+ public cItemHandler
{
+ typedef cItemHandler super;
+
public:
cItemFoodHandler(int a_ItemType)
- : cItemHandler(a_ItemType)
+ : super(a_ItemType)
{
}
- virtual bool IsFood() override
+
+ virtual bool IsFood(void) override
{
return true;
}
- virtual FoodInfo GetFoodInfo() override
+
+ virtual FoodInfo GetFoodInfo(void) override
{
switch(m_ItemType)
{
- case E_ITEM_BREAD:
- return FoodInfo(5, 6.f);
- case E_ITEM_COOKIE:
- return FoodInfo(2, 0.4f);
- case E_ITEM_MELON_SLICE:
- return FoodInfo(2, 1.2f);
- case E_ITEM_RAW_CHICKEN:
- return FoodInfo(2, 1.2f, 30);
- case E_ITEM_COOKED_CHICKEN:
- return FoodInfo(6, 7.2f);
- case E_ITEM_RAW_BEEF:
- case E_ITEM_RAW_PORKCHOP:
- return FoodInfo(3, 1.8f);
- case E_ITEM_STEAK:
- case E_ITEM_COOKED_PORKCHOP:
- return FoodInfo(8, 12.8f);
- case E_ITEM_RAW_FISH:
- return FoodInfo(2, 1.2f);
- case E_ITEM_COOKED_FISH:
- return FoodInfo(5, 6.f);
- case E_ITEM_RED_APPLE:
- return FoodInfo(4, 2.4f);
- case E_ITEM_GOLDEN_APPLE:
- return FoodInfo(4, 9.6f);
- case E_ITEM_ROTTEN_FLESH:
- return FoodInfo(4, 0.8f, 80);
- case E_ITEM_SPIDER_EYE:
- return FoodInfo(2, 3.2f, 100);
+ case E_ITEM_BREAD: return FoodInfo(5, 6);
+ case E_ITEM_COOKIE: return FoodInfo(2, 0.4);
+ case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
+ case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
+ case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
+ case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
+ case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
+ case E_ITEM_STEAK: return FoodInfo(8, 12.8);
+ case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
+ case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
+ case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
+ case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
+ case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
+ case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
+ case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
}
+ LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f);
}
-}; \ No newline at end of file
+};
+
+
+
+
diff --git a/source/Items/ItemHandler.cpp b/source/Items/ItemHandler.cpp
index d99457029..acb6b6371 100644
--- a/source/Items/ItemHandler.cpp
+++ b/source/Items/ItemHandler.cpp
@@ -4,6 +4,7 @@
#include "../Item.h"
#include "../World.h"
#include "../Player.h"
+#include "../FastRandom.h"
// Handlers:
#include "ItemBed.h"
@@ -465,15 +466,17 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
FoodInfo Info = GetFoodInfo();
- if(Info.FoodLevel > 0 || Info.Saturation > 0.f)
+ if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
{
bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation);
- if(Success && Info.PoisionChance > 0)
+
+ // If consumed and there's chance of foodpoisoning, do it:
+ if (Success && (Info.PoisonChance > 0))
{
- MTRand r1;
- if((r1.randInt(100) - Info.PoisionChance) <= 0)
- { //Unlucky guy :D
- //TODO: Make player ill
+ cFastRandom r1;
+ if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
+ {
+ a_Player->FoodPoison(300);
}
}
diff --git a/source/Items/ItemHandler.h b/source/Items/ItemHandler.h
index 0c141dea0..f7985327a 100644
--- a/source/Items/ItemHandler.h
+++ b/source/Items/ItemHandler.h
@@ -38,16 +38,17 @@ public:
struct FoodInfo
{
- FoodInfo(short a_FoodLevel, float a_Saturation, char a_PoisionChance = 0)
+ int FoodLevel;
+ double Saturation;
+ int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
+
+ FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
+ FoodLevel(a_FoodLevel),
+ Saturation(a_Saturation),
+ PoisonChance(a_PoisonChance)
{
- FoodLevel = a_FoodLevel;
- Saturation = a_Saturation;
- PoisionChance = a_PoisionChance;
}
- short FoodLevel;
- float Saturation;
- char PoisionChance; //0 - 100
- };
+ } ;
/// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance)
virtual FoodInfo GetFoodInfo();
diff --git a/source/Player.cpp b/source/Player.cpp
index 83181dda6..c90f3c99c 100644
--- a/source/Player.cpp
+++ b/source/Player.cpp
@@ -20,6 +20,7 @@
#include "OSSupport/Timer.h"
#include "MersenneTwister.h"
#include "Chunk.h"
+#include "Items/ItemHandler.h"
#include "Vector3d.h"
#include "Vector3f.h"
@@ -58,6 +59,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_SprintingMaxSpeed(0.13)
, m_IsCrouched(false)
, m_IsSprinting(false)
+ , m_EatingFinishTick(-1)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(),
@@ -189,6 +191,11 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
{
m_World->CollectPickupsByPlayer(this);
+ if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
+ {
+ FinishEating();
+ }
+
HandleFood();
}
@@ -349,6 +356,57 @@ void cPlayer::FoodPoison(int a_NumTicks)
+void cPlayer::StartEating(void)
+{
+ // Set the timer:
+ m_EatingFinishTick = m_World->GetWorldAge() + EATING_TICKS;
+
+ // Send the packets:
+ m_World->BroadcastPlayerAnimation(*this, 5);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
+void cPlayer::FinishEating(void)
+{
+ // Reset the timer:
+ m_EatingFinishTick = -1;
+
+ // Send the packets:
+ m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
+ m_World->BroadcastPlayerAnimation(*this, 0);
+ m_World->BroadcastEntityMetadata(*this);
+
+ // consume the item:
+ cItem Item(GetEquippedItem());
+ Item.m_ItemCount = 1;
+ cItemHandler * ItemHandler = cItemHandler::GetItemHandler(Item.m_ItemType);
+ if (!ItemHandler->EatItem(this, &Item))
+ {
+ return;
+ }
+ ItemHandler->OnFoodEaten(m_World, this, &Item);
+ GetInventory().RemoveOneEquippedItem();
+}
+
+
+
+
+
+void cPlayer::AbortEating(void)
+{
+ m_EatingFinishTick = -1;
+ m_World->BroadcastPlayerAnimation(*this, 0);
+ m_World->BroadcastEntityMetadata(*this);
+}
+
+
+
+
+
void cPlayer::SendHealth(void)
{
if (m_ClientHandle != NULL)
@@ -505,7 +563,10 @@ void cPlayer::KilledBy(cEntity * a_Killer)
void cPlayer::Respawn(void)
{
m_Health = GetMaxHealth();
+
+ // Reset food level:
m_FoodLevel = 20;
+ m_FoodSaturationLevel = 5;
m_ClientHandle->SendRespawn();
@@ -538,6 +599,36 @@ Vector3d cPlayer::GetEyePosition(void) const
+bool cPlayer::IsGameModeCreative(void) const
+{
+ return (m_GameMode == gmCreative) || // Either the player is explicitly in Creative
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Creative
+}
+
+
+
+
+
+bool cPlayer::IsGameModeSurvival(void) const
+{
+ return (m_GameMode == gmSurvival) || // Either the player is explicitly in Survival
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeSurvival()); // or they inherit from the world and the world is Survival
+}
+
+
+
+
+
+bool cPlayer::IsGameModeAdventure(void) const
+{
+ return (m_GameMode == gmCreative) || // Either the player is explicitly in Adventure
+ ((m_GameMode == gmNotSet) && m_World->IsGameModeCreative()); // or they inherit from the world and the world is Adventure
+}
+
+
+
+
+
void cPlayer::OpenWindow(cWindow * a_Window)
{
if (a_Window != m_CurrentWindow)
@@ -614,7 +705,7 @@ void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
void cPlayer::SetGameMode(eGameMode a_GameMode)
{
- if ((a_GameMode >= 3) || (a_GameMode < 0))
+ if ((a_GameMode >= gmMin) || (a_GameMode < gmMax))
{
LOGWARNING("%s: Setting invalid gamemode: %d", GetName().c_str(), a_GameMode);
return;
@@ -1283,8 +1374,14 @@ void cPlayer::HandleFood(void)
void cPlayer::ApplyFoodExhaustionFromMovement(cChunk & a_Chunk)
{
+ if (IsGameModeCreative())
+ {
+ return;
+ }
+
// Calculate the distance travelled, update the last pos:
Vector3d Movement(GetPosition() - m_LastFoodPos);
+ Movement.y = 0; // Only take XZ movement into account
m_LastFoodPos = GetPosition();
// If riding anything, apply no food exhaustion
diff --git a/source/Player.h b/source/Player.h
index fed222157..eea8c1596 100644
--- a/source/Player.h
+++ b/source/Player.h
@@ -28,6 +28,7 @@ public:
{
MAX_HEALTH = 20,
MAX_FOOD_LEVEL = 20,
+ EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
} ;
// tolua_end
@@ -65,7 +66,7 @@ public:
double GetEyeHeight(void) const; // tolua_export
Vector3d GetEyePosition(void) const; // tolua_export
inline bool IsOnGround(void) const {return m_bTouchGround; } // tolua_export
- inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
+ inline const double GetStance(void) const { return GetPosY() + 1.62; } // tolua_export // TODO: Proper stance when crouching etc.
inline cInventory & GetInventory(void) { return m_Inventory; } // tolua_export
inline const cInventory & GetInventory(void) const { return m_Inventory; }
@@ -73,18 +74,42 @@ public:
virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override;
- eGameMode GetGameMode(void) const { return m_GameMode; } // tolua_export
- std::string GetIP() { return m_IP; } // tolua_export
- float GetLastBlockActionTime() { return m_LastBlockActionTime; } // tolua_export
- int GetLastBlockActionCnt() { return m_LastBlockActionCnt; } // tolua_export
- void SetLastBlockActionCnt( int ); // tolua_export
- void SetLastBlockActionTime(); // tolua_export
- void SetGameMode( eGameMode a_GameMode ); // tolua_export
- void LoginSetGameMode( eGameMode a_GameMode );
+ // tolua_begin
+
+ /// Returns the current gamemode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
+ eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /** Sets the gamemode for the player.
+ The gamemode may be gmNotSet, in that case the player inherits the world's gamemode.
+ Updates the gamemode on the client (sends the packet)
+ */
+ void SetGameMode(eGameMode a_GameMode);
+
+ /// Returns true if the player is in Creative mode, either explicitly, or by inheriting from current world
+ bool IsGameModeCreative(void) const;
+
+ /// Returns true if the player is in Survival mode, either explicitly, or by inheriting from current world
+ bool IsGameModeSurvival(void) const;
+
+ /// Returns true if the player is in Adventure mode, either explicitly, or by inheriting from current world
+ bool IsGameModeAdventure(void) const;
+
+ AString GetIP(void) const { return m_IP; } // tolua_export
+
+ // tolua_end
+
void SetIP(const AString & a_IP);
+ float GetLastBlockActionTime() { return m_LastBlockActionTime; }
+ int GetLastBlockActionCnt() { return m_LastBlockActionCnt; }
+ void SetLastBlockActionCnt( int );
+ void SetLastBlockActionTime();
+
+ // Sets the current gamemode, doesn't check validity, doesn't send update packets to client
+ void LoginSetGameMode(eGameMode a_GameMode);
+
/// Tries to move to a new position, with collision checks and stuff
- virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export
+ virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export
cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export
const cWindow * GetWindow(void) const { return m_CurrentWindow; }
@@ -136,6 +161,9 @@ public:
double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; }
int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; }
+ /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore
+ bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); }
+
void SetFoodLevel (int a_FoodLevel);
void SetFoodSaturationLevel (double a_FoodSaturationLevel);
void SetFoodTickTimer (int a_FoodTickTimer);
@@ -151,8 +179,20 @@ public:
/// Starts the food poisoning for the specified amount of ticks; if already foodpoisoned, sets FoodPoisonedTicksRemaining to the larger of the two
void FoodPoison(int a_NumTicks);
+ /// Returns true if the player is currently in the process of eating the currently equipped item
+ bool IsEating(void) const { return (m_EatingFinishTick >= 0); }
+
// tolua_end
+ /// Starts eating the currently equipped item. Resets the eating timer and sends the proper animation packet
+ void StartEating(void);
+
+ /// Finishes eating the currently equipped item. Consumes the item, updates health and broadcasts the packets
+ void FinishEating(void);
+
+ /// Aborts the current eating operation
+ void AbortEating(void);
+
virtual void KilledBy(cEntity * a_Killer) override;
void Respawn(void); // tolua_export
@@ -214,6 +254,7 @@ public:
// cEntity overrides:
virtual bool IsCrouched (void) const { return m_IsCrouched; }
virtual bool IsSprinting(void) const { return m_IsSprinting; }
+ virtual bool IsRclking (void) const { return IsEating(); }
protected:
typedef std::map< std::string, bool > PermissionMap;
@@ -285,6 +326,9 @@ protected:
bool m_IsCrouched;
bool m_IsSprinting;
+ /// The world tick in which eating will be finished. -1 if not eating
+ Int64 m_EatingFinishTick;
+
virtual void Destroyed(void);
diff --git a/source/World.h b/source/World.h
index 5da7218e2..e67b06789 100644
--- a/source/World.h
+++ b/source/World.h
@@ -106,7 +106,18 @@ public:
SetTimeOfDay(a_TimeOfDay);
}
+ /// Returns the current game mode. Partly OBSOLETE, you should use IsGameModeXXX() functions wherever applicable
eGameMode GetGameMode(void) const { return m_GameMode; }
+
+ /// Returns true if the world is in Creative mode
+ bool IsGameModeCreative(void) const { return (m_GameMode == gmCreative); }
+
+ /// Returns true if the world is in Survival mode
+ bool IsGameModeSurvival(void) const { return (m_GameMode == gmSurvival); }
+
+ /// Returns true if the world is in Adventure mode
+ bool IsGameModeAdventure(void) const { return (m_GameMode == gmAdventure); }
+
bool IsPVPEnabled(void) const { return m_bEnabledPVP; }
bool IsDeepSnowEnabled(void) const { return m_IsDeepSnowEnabled; }