Simple health regeneration system

Prepared for food

git-svn-id: http://mc-server.googlecode.com/svn/trunk@679 0a769ca7-a7f5-676a-18bf-c427514a06d6
master
lapayo94@gmail.com 2012-07-17 12:02:03 +00:00
parent 3cfa4152e6
commit f473f13585
13 changed files with 212 additions and 143 deletions

View File

@ -638,6 +638,7 @@
<ClInclude Include="..\source\items\Item.h" />
<ClInclude Include="..\source\items\ItemDoor.h" />
<ClInclude Include="..\source\items\ItemDye.h" />
<ClInclude Include="..\source\items\ItemFood.h" />
<ClInclude Include="..\source\items\ItemHoe.h" />
<ClInclude Include="..\source\items\ItemLeaves.h" />
<ClInclude Include="..\source\items\ItemLighter.h" />

View File

@ -1640,6 +1640,9 @@
<ClInclude Include="..\source\items\ItemRedstoneRepeater.h">
<Filter>Items</Filter>
</ClInclude>
<ClInclude Include="..\source\items\ItemFood.h">
<Filter>Items</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\source\AllToLua.pkg">

View File

@ -339,11 +339,7 @@ void cClientHandle::Authenticate(void)
m_Player->GetInventory().SendWholeInventory(this);
// Send health
cPacket_UpdateHealth Health;
Health.m_Health = (short)m_Player->GetHealth();
Health.m_Food = m_Player->GetFood();
Health.m_Saturation = m_Player->GetFoodSaturation();
Send(Health);
m_Player->SendHealth();
m_Player->Initialize(World);
StreamChunks();
@ -856,13 +852,6 @@ void cClientHandle::HandleBlockDig(cPacket_BlockDig * a_Packet)
void cClientHandle::HandleBlockPlace(cPacket_BlockPlace * a_Packet)
{
if(a_Packet->m_PosX == -1
&& a_Packet->m_PosY == 255
&& a_Packet->m_PosZ == -1)
{
//I don´t know whats the idea behind these packets O.o
return;
}
if (!CheckBlockInteractionsRate())
{
@ -960,7 +949,7 @@ void cClientHandle::HandleBlockPlace(cPacket_BlockPlace * a_Packet)
cItem Item;
Item.m_ItemID = Equipped.m_ItemID;
Item.m_ItemCount = 1;
if (m_Player->EatItem(Item.m_ItemID))
if (ItemHandler->EatItem(m_Player, &Item))
{
ItemHandler->OnFoodEaten(World, m_Player, &Item);
m_Player->GetInventory().RemoveItem(Item);

View File

@ -38,7 +38,6 @@ cPawn::cPawn()
, m_BurnPeriod(0.f)
{
SetMaxHealth(20);
SetMaxFoodLevel(125);
}
@ -235,18 +234,3 @@ void cPawn::SetMaxHealth(short a_MaxHealth)
m_Health = a_MaxHealth;
}
void cPawn::SetMaxFoodLevel(short a_MaxFoodLevel)
{
m_MaxFoodLevel = a_MaxFoodLevel;
//Reset food level
m_FoodLevel = a_MaxFoodLevel;
}

View File

@ -47,23 +47,11 @@ public:
virtual void SetMaxHealth(short a_MaxHealth);
virtual short GetMaxHealth() { return m_MaxHealth; }
//virtual void SetMaxFood(short a_MaxFood);
virtual short GetMaxFood() { return m_MaxFoodLevel / 6; }
virtual short GetFood() { return m_FoodLevel / 6; }
//virtual void SetMaxFoodSaturation(float a_MaxFoodSaturation);
virtual float GetMaxFoodSaturation() { return fmod(m_MaxFoodLevel, 6.f); }
virtual float GetFoodSaturation() { return fmod(m_FoodLevel, 6.f); }
virtual void SetMaxFoodLevel(short a_MaxFoodLevel);
virtual short GetMaxFoodLevel() { return m_MaxFoodLevel; }
protected:
short m_Health;
short m_FoodLevel;
short m_MaxHealth;
short m_MaxFoodLevel;
bool m_bBurnable;

View File

@ -66,14 +66,22 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName)
, m_TimeLastPickupCheck( 0.f )
, m_Color('-')
, m_ClientHandle( a_Client )
, m_FoodExhaustionLevel(0.f)
, m_FoodTickTimer(0)
{
LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d",
a_PlayerName.c_str(), a_Client->GetSocket().GetIPString().c_str(),
this, GetUniqueID()
);
m_EntityType = eEntityType_Player;
SetMaxHealth(20);
SetMaxFoodLevel(125);
m_MaxFoodLevel = 20;
m_MaxFoodSaturationLevel = 20.f;
m_FoodLevel = m_MaxFoodLevel;
m_FoodSaturationLevel = 5.f;
m_Inventory = new cSurvivalInventory( this );
m_CreativeInventory = new cCreativeInventory(this);
cTimer t1;
@ -242,6 +250,34 @@ void cPlayer::Tick(float a_Dt)
if (m_Health > 0) // make sure player is alive
{
m_World->CollectPickupsByPlayer(this);
//Handle Health:
m_FoodTickTimer++;
if(m_FoodTickTimer >= 80)
{
m_FoodTickTimer = 0;
if(m_FoodLevel >= 17)
{
Heal(1);
}else if(m_FoodLevel == 0)
{
TakeDamage(1, NULL);
}
}
//TODO: Increase Exhaustion level http://www.minecraftwiki.net/wiki/Hunger#Exhaustion_level_increase
if(m_FoodExhaustionLevel >= 4.f)
{
m_FoodExhaustionLevel -= 4.f;
if(m_FoodSaturationLevel >= 1.f)
m_FoodSaturationLevel--;
else
m_FoodLevel = MAX(m_FoodLevel -1, 0);
SendHealth();
}
}
cTimer t1;
@ -297,19 +333,12 @@ void cPlayer::Heal( int a_Health )
{
m_Health = (short) MIN(a_Health + m_Health, GetMaxHealth());
cPacket_UpdateHealth Health;
Health.m_Health = m_Health;
Health.m_Food = GetFood();
Health.m_Saturation = GetFoodSaturation();
m_ClientHandle->Send( Health );
SendHealth();
}
}
bool cPlayer::Feed(short a_Food)
bool cPlayer::Feed(short a_Food, float a_Saturation)
{
if (m_FoodLevel >= GetMaxFoodLevel())
{
@ -317,31 +346,31 @@ bool cPlayer::Feed(short a_Food)
}
m_FoodLevel = MIN(a_Food + m_FoodLevel, GetMaxFoodLevel());
m_FoodSaturationLevel = MIN(m_FoodSaturationLevel + a_Saturation, GetMaxFoodSaturationLevel());
cPacket_UpdateHealth Health;
Health.m_Health = m_Health;
Health.m_Food = GetFood();
Health.m_Saturation = GetFoodSaturation();
m_ClientHandle->Send( Health );
SendHealth();
return true;
}
void cPlayer::SendHealth()
{
cPacket_UpdateHealth Health;
Health.m_Health = GetHealth();
Health.m_Food = GetFoodLevel();
Health.m_Saturation = GetFoodSaturationLevel();
if(m_ClientHandle != 0)
m_ClientHandle->Send( Health );
}
void cPlayer::TakeDamage( int a_Damage, cEntity* a_Instigator )
{
if ( !(m_GameMode == 1) ) {
if(m_GameMode != eGameMode_Creative)
{
cPawn::TakeDamage( a_Damage, a_Instigator );
cPacket_UpdateHealth Health;
Health.m_Health = m_Health;
Health.m_Food = GetFood();
Health.m_Saturation = GetFoodSaturation();
//TODO: Causes problems sometimes O.o (E.G. Disconnecting when attacked)
if(m_ClientHandle != 0)
m_ClientHandle->Send( Health );
AddFoodExhaustion(0.3f);
SendHealth();
}
}
@ -914,7 +943,8 @@ bool cPlayer::LoadFromDisk()
}
m_Health = (short)root.get("health", 0 ).asInt();
m_FoodLevel = (short)root.get("food", 0 ).asInt();
m_FoodLevel = (short)root.get("food", m_MaxFoodLevel ).asInt();
m_FoodSaturationLevel = (float)root.get("foodSaturation", m_MaxFoodSaturationLevel ).asDouble();
m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt();
@ -963,6 +993,7 @@ bool cPlayer::SaveToDisk()
root["creativeinventory"] = JSON_CreativeInventory;
root["health"] = m_Health;
root["food"] = m_FoodLevel;
root["foodSaturation"] = m_FoodSaturationLevel;
root["world"] = GetWorld()->GetName();
if(m_GameMode == GetWorld()->GetGameMode())
@ -1028,46 +1059,3 @@ void cPlayer::UseEquippedItem()
bool cPlayer::EatItem(int a_ItemType)
{
// TODO: Handle hunger
switch (a_ItemType)
{
case E_ITEM_APPLE: return Feed(24); // 2 food bars
case E_ITEM_GOLDEN_APPLE: return Feed(60); // 5 food
case E_ITEM_MUSHROOM_SOUP: return Feed(48); // 4 food
case E_ITEM_BREAD: return Feed(30); // 2.5 food
case E_ITEM_RAW_MEAT: return Feed(18); // 1.5 food
case E_ITEM_COOKED_MEAT: return Feed(48); // 4 food
case E_ITEM_RAW_FISH: return Feed(12); // 1 food
case E_ITEM_COOKED_FISH: return Feed(30); // 2.5 food
case E_ITEM_COOKED_CHICKEN: return Feed(36); // 3 food
case E_ITEM_RAW_BEEF: return Feed(18); // 1.5 food
case E_ITEM_STEAK: return Feed(48); // 4 food
case E_ITEM_RAW_CHICKEN:
{
if (!Feed(12)) // 1 food
{
return false;
}
// TODO: A random chance to get food-poisoned
return true;
}
case E_ITEM_ROTTEN_FLESH:
{
if (!Feed(24))
{
return false;
}
// TODO: Food-poisoning
return true;
}
}
return false;
}

View File

@ -83,7 +83,15 @@ public:
void Heal( int a_Health ); //tolua_export
/// Returns true if any food has been consumed, false if player "full"
bool Feed(short a_Food);
bool Feed(short a_Food, float a_Saturation);
short GetMaxFoodLevel() { return m_MaxFoodLevel; }
short GetFoodLevel() { return m_FoodLevel; }
float GetMaxFoodSaturationLevel() { return m_MaxFoodSaturationLevel; }
float GetFoodSaturationLevel() { return m_FoodSaturationLevel; }
void AddFoodExhaustion(float a_Exhaustion) { m_FoodExhaustionLevel += a_Exhaustion; }
void TakeDamage( int a_Damage, cEntity* a_Instigator ); //tolua_export
void KilledBy( cEntity* a_Killer ); //tolua_export
@ -102,8 +110,7 @@ public:
void UseEquippedItem(void);
/// Returns true if the item type is edible && it has been consumed, false otherwise
bool EatItem(int a_ItemType);
void SendHealth();
protected:
virtual void Destroyed();
@ -120,6 +127,13 @@ protected:
bool m_bVisible;
short m_FoodLevel;
short m_MaxFoodLevel;
float m_FoodSaturationLevel;
float m_MaxFoodSaturationLevel;
float m_FoodExhaustionLevel;
char m_FoodTickTimer;
float m_LastGroundHeight;
bool m_bTouchGround;
double m_Stance;

View File

@ -23,6 +23,7 @@
#include "ItemShovel.h"
#include "ItemSword.h"
#include "ItemDoor.h"
#include "ItemFood.h"
#include "../blocks/Block.h"
@ -109,6 +110,23 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemID)
case E_ITEM_WOODEN_DOOR:
return new cItemDoorHandler(a_ItemID);
//FOOD:
case E_ITEM_BREAD:
case E_ITEM_COOKIE:
case E_ITEM_MELON_SLICE:
case E_ITEM_RAW_CHICKEN:
case E_ITEM_COOKED_CHICKEN:
case E_ITEM_RAW_BEEF:
case E_ITEM_RAW_MEAT:
case E_ITEM_STEAK:
case E_ITEM_COOKED_MEAT:
case E_ITEM_RAW_FISH:
case E_ITEM_COOKED_FISH:
case E_ITEM_RED_APPLE:
case E_ITEM_GOLDEN_APPLE:
case E_ITEM_ROTTEN_FLESH:
case E_ITEM_SPIDER_EYE:
return new cItemFoodHandler(a_ItemID);
default:
return new cItemHandler(a_ItemID);
break;
@ -159,16 +177,6 @@ void cItemHandler::OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item
}
int cItemHandler::GetMaxStackSize()
{
return 64;
}
int cItemHandler::GetMaxDamage()
{
return 0;
}
bool cItemHandler::IsTool()
{
return
@ -231,3 +239,30 @@ void cItemHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item,
if(a_Player->GetGameMode() == eGameMode_Survival)
a_Player->GetInventory().RemoveItem(cItem(a_Item->m_ItemID, 1));
}
bool cItemHandler::EatItem(cPlayer *a_Player, cItem *a_Item)
{
FoodInfo Info = GetFoodInfo();
if(Info.FoodLevel > 0 || Info.Saturation > 0.f)
{
bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation);
if(Success && Info.PoisionChance > 0)
{
MTRand r1;
if((r1.randInt(100) - Info.PoisionChance) <= 0)
{ //Unlucky guy :D
//TODO: Make player ill
}
}
return Success;
}
return false;
}
cItemHandler::FoodInfo cItemHandler::GetFoodInfo()
{
return FoodInfo(0, 0.f);
}

View File

@ -13,8 +13,23 @@ public:
virtual bool OnDiggingBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir);
virtual void OnBlockDestroyed(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z);
virtual void OnFoodEaten(cWorld *a_World, cPlayer *a_Player, cItem *a_Item);
virtual int GetMaxStackSize();
virtual int GetMaxDamage();
struct FoodInfo
{
FoodInfo(short a_FoodLevel, float a_Saturation, char a_PoisionChance = 0)
{
FoodLevel = a_FoodLevel;
Saturation = a_Saturation;
PoisionChance = a_PoisionChance;
}
short FoodLevel;
float Saturation;
char PoisionChance; //0 - 100
};
virtual FoodInfo GetFoodInfo();
virtual bool EatItem(cPlayer *a_Player, cItem *a_Item);
virtual void PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, int a_X, int a_Y, int a_Z, char a_Dir);

55
source/items/ItemFood.h Normal file
View File

@ -0,0 +1,55 @@
#pragma once
#include "Item.h"
class cItemFoodHandler : public cItemHandler
{
public:
cItemFoodHandler(int a_ItemID)
: cItemHandler(a_ItemID)
{
}
virtual bool IsFood() override
{
return true;
}
virtual FoodInfo GetFoodInfo() override
{
switch(m_ItemID)
{
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_MEAT:
return FoodInfo(3, 1.8f);
case E_ITEM_STEAK:
case E_ITEM_COOKED_MEAT:
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);
}
return FoodInfo(0, 0.f);
}
};

View File

@ -9,8 +9,7 @@
using namespace Sqrat;
#if USE_SQUIRREL
void BindSquirrel(HSQUIRRELVM vm)
{
RootTable()
@ -91,12 +90,6 @@ void BindSquirrel(HSQUIRRELVM vm)
.Func("GetMetaData", &cPawn::GetMetaData)
.Func("SetMaxHealth", &cPawn::SetMaxHealth)
.Func("GetMaxHealth", &cPawn::GetMaxHealth)
.Func("GetMaxFood", &cPawn::GetMaxFood)
.Func("GetFood", &cPawn::GetFood)
.Func("GetMaxFoodSaturation", &cPawn::GetMaxFoodSaturation)
.Func("GetFoodSaturation", &cPawn::GetFoodSaturation)
.Func("SetMaxFoodLevel", &cPawn::SetMaxFoodLevel)
.Func("GetMaxFoodLevel", &cPawn::SetMaxFoodLevel)
);
RootTable().Bind("cPlayer", DerivedClass<cPlayer, cPawn, NoConstructor>()
@ -137,8 +130,6 @@ void BindSquirrel(HSQUIRRELVM vm)
.Func("MoveToWorld", &cPlayer::MoveToWorld)
.Func("GetLoadedWorldName", &cPlayer::GetLoadedWorldName)
.Func("UseEquippedItem", &cPlayer::UseEquippedItem)
.Func("EatItem", &cPlayer::EatItem)
);
RootTable().Bind("StringArray", Class<SquirrelStringArray>()
@ -175,5 +166,6 @@ void BindSquirrel(HSQUIRRELVM vm)
.Const("WeatherChanged", cPluginManager::HOOK_WEATHER_CHANGED)
.Const("UpdatingSign", cPluginManager::HOOK_UPDATING_SIGN)
.Const("UpdatedSign", cPluginManager::HOOK_UPDATED_SIGN));
}
#endif

View File

@ -1,7 +1,7 @@
#pragma once
#define USE_SQUIRREL 1
#define USE_SQUIRREL 0
#if USE_SQUIRREL

View File

@ -3,6 +3,9 @@
#include "SquirrelFunctions.h"
#include "SquirrelBindings.h"
#if USE_SQUIRREL
static HSQUIRRELVM squirrelvm = NULL;
SQInteger runtimeErrorHandler(HSQUIRRELVM a_VM)
@ -63,3 +66,5 @@ void sqPrint(SQChar * text)
{
LOGINFO("%s", text);
}
#endif