1
0

Implemented basic eating support.

Food is now properly consumed and it takes 1.5 sec.
This commit is contained in:
madmaxoft 2013-07-28 19:15:03 +02:00
parent 00196e975a
commit 4746d2251c
7 changed files with 134 additions and 63 deletions

View File

@ -555,11 +555,8 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem()); cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
if (ItemHandler->IsFood()) if (ItemHandler->IsFood())
{ {
if (PlgMgr->CallHookPlayerEating(*m_Player)) m_Player->AbortEating();
{ return;
// A plugin doesn't agree with the action. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
return;
}
} }
else else
{ {
@ -569,7 +566,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return; return;
} }
} }
LOGINFO("%s: Status SHOOT / EAT not implemented", __FUNCTION__); LOGINFO("%s: Status SHOOT not implemented", __FUNCTION__);
return; return;
} }
@ -804,15 +801,14 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, c
} }
else if (ItemHandler->IsFood()) else if (ItemHandler->IsFood())
{ {
cItem Item; m_Player->StartEating();
Item.m_ItemType = Equipped.m_ItemType; if (PlgMgr->CallHookPlayerEating(*m_Player))
Item.m_ItemCount = 1;
if (ItemHandler->EatItem(m_Player, &Item))
{ {
ItemHandler->OnFoodEaten(World, m_Player, &Item); // A plugin won't let us eat, abort (send the proper packets to the client, too):
m_Player->GetInventory().RemoveOneEquippedItem(); m_Player->AbortEating();
return; return;
} }
return;
} }
else else
{ {

View File

@ -282,6 +282,9 @@ private:
/// Buffer for received messages to be processed in the Tick thread /// Buffer for received messages to be processed in the Tick thread
AStringList m_PendingMessages; AStringList m_PendingMessages;
static int s_ClientCount;
int m_UniqueID;
/// Returns true if the rate block interactions is within a reasonable limit (bot protection) /// Returns true if the rate block interactions is within a reasonable limit (bot protection)
@ -312,9 +315,6 @@ private:
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client 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 GetOutgoingData(AString & a_Data) override; // Data can be sent to client
virtual void SocketClosed (void) override; // The socket has been closed for any reason virtual void SocketClosed (void) override; // The socket has been closed for any reason
static int s_ClientCount;
int m_UniqueID;
}; // tolua_export }; // tolua_export

View File

@ -4,53 +4,53 @@
#include "ItemHandler.h" #include "ItemHandler.h"
class cItemFoodHandler : public cItemHandler
class cItemFoodHandler :
public cItemHandler
{ {
typedef cItemHandler super;
public: public:
cItemFoodHandler(int a_ItemType) cItemFoodHandler(int a_ItemType)
: cItemHandler(a_ItemType) : super(a_ItemType)
{ {
} }
virtual bool IsFood() override
virtual bool IsFood(void) override
{ {
return true; return true;
} }
virtual FoodInfo GetFoodInfo() override
virtual FoodInfo GetFoodInfo(void) override
{ {
switch(m_ItemType) switch(m_ItemType)
{ {
case E_ITEM_BREAD: case E_ITEM_BREAD: return FoodInfo(5, 6);
return FoodInfo(5, 6.f); case E_ITEM_COOKIE: return FoodInfo(2, 0.4);
case E_ITEM_COOKIE: case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
return FoodInfo(2, 0.4f); case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
case E_ITEM_MELON_SLICE: case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
return FoodInfo(2, 1.2f); case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
case E_ITEM_RAW_CHICKEN: case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
return FoodInfo(2, 1.2f, 30); case E_ITEM_STEAK: return FoodInfo(8, 12.8);
case E_ITEM_COOKED_CHICKEN: case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
return FoodInfo(6, 7.2f); case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
case E_ITEM_RAW_BEEF: case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
case E_ITEM_RAW_PORKCHOP: case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
return FoodInfo(3, 1.8f); case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
case E_ITEM_STEAK: case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
case E_ITEM_COOKED_PORKCHOP: case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
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);
} }
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f); return FoodInfo(0, 0.f);
} }
}; };

View File

@ -4,6 +4,7 @@
#include "../Item.h" #include "../Item.h"
#include "../World.h" #include "../World.h"
#include "../Player.h" #include "../Player.h"
#include "../FastRandom.h"
// Handlers: // Handlers:
#include "ItemBed.h" #include "ItemBed.h"
@ -465,15 +466,17 @@ bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{ {
FoodInfo Info = GetFoodInfo(); 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); 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; cFastRandom r1;
if((r1.randInt(100) - Info.PoisionChance) <= 0) if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
{ //Unlucky guy :D {
//TODO: Make player ill a_Player->FoodPoison(300);
} }
} }

View File

@ -38,16 +38,17 @@ public:
struct FoodInfo 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) /// Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance)
virtual FoodInfo GetFoodInfo(); virtual FoodInfo GetFoodInfo();

View File

@ -20,6 +20,7 @@
#include "OSSupport/Timer.h" #include "OSSupport/Timer.h"
#include "MersenneTwister.h" #include "MersenneTwister.h"
#include "Chunk.h" #include "Chunk.h"
#include "Items/ItemHandler.h"
#include "Vector3d.h" #include "Vector3d.h"
#include "Vector3f.h" #include "Vector3f.h"
@ -58,6 +59,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_SprintingMaxSpeed(0.13) , m_SprintingMaxSpeed(0.13)
, m_IsCrouched(false) , m_IsCrouched(false)
, m_IsSprinting(false) , m_IsSprinting(false)
, m_EatingFinishTick(-1)
{ {
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetIPString().c_str(), 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); m_World->CollectPickupsByPlayer(this);
if ((m_EatingFinishTick >= 0) && (m_EatingFinishTick <= m_World->GetWorldAge()))
{
FinishEating();
}
HandleFood(); 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) void cPlayer::SendHealth(void)
{ {
if (m_ClientHandle != NULL) if (m_ClientHandle != NULL)

View File

@ -28,6 +28,7 @@ public:
{ {
MAX_HEALTH = 20, MAX_HEALTH = 20,
MAX_FOOD_LEVEL = 20, MAX_FOOD_LEVEL = 20,
EATING_TICKS = 30, ///< Number of ticks it takes to eat an item
} ; } ;
// tolua_end // tolua_end
@ -164,6 +165,15 @@ public:
// tolua_end // 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; virtual void KilledBy(cEntity * a_Killer) override;
void Respawn(void); // tolua_export void Respawn(void); // tolua_export
@ -296,6 +306,9 @@ protected:
bool m_IsCrouched; bool m_IsCrouched;
bool m_IsSprinting; bool m_IsSprinting;
/// The world tick in which eating will be finished. -1 if not eating
Int64 m_EatingFinishTick;
virtual void Destroyed(void); virtual void Destroyed(void);