diff --git a/VC2010/MCServer.vcxproj b/VC2010/MCServer.vcxproj index 1bbf7617c..e085d6a32 100644 --- a/VC2010/MCServer.vcxproj +++ b/VC2010/MCServer.vcxproj @@ -638,6 +638,7 @@ + diff --git a/VC2010/MCServer.vcxproj.filters b/VC2010/MCServer.vcxproj.filters index b93c2a334..38014365c 100644 --- a/VC2010/MCServer.vcxproj.filters +++ b/VC2010/MCServer.vcxproj.filters @@ -1640,6 +1640,9 @@ Items + + Items + diff --git a/source/cClientHandle.cpp b/source/cClientHandle.cpp index 76aaf2724..5bbf0f512 100644 --- a/source/cClientHandle.cpp +++ b/source/cClientHandle.cpp @@ -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,14 +852,7 @@ 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()) { return; @@ -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); diff --git a/source/cPawn.cpp b/source/cPawn.cpp index 0037e56e4..9fe34059b 100644 --- a/source/cPawn.cpp +++ b/source/cPawn.cpp @@ -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; -} - - - - diff --git a/source/cPawn.h b/source/cPawn.h index 2c4444174..dbf60d59e 100644 --- a/source/cPawn.h +++ b/source/cPawn.h @@ -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; diff --git a/source/cPlayer.cpp b/source/cPlayer.cpp index 9e54b7c44..b7b7919fd 100644 --- a/source/cPlayer.cpp +++ b/source/cPlayer.cpp @@ -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()); - - cPacket_UpdateHealth Health; - Health.m_Health = m_Health; - Health.m_Food = GetFood(); - Health.m_Saturation = GetFoodSaturation(); - m_ClientHandle->Send( Health ); + m_FoodSaturationLevel = MIN(m_FoodSaturationLevel + a_Saturation, GetMaxFoodSaturationLevel()); + + 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; -} - - - - diff --git a/source/cPlayer.h b/source/cPlayer.h index ef85a1d4e..c1420023e 100644 --- a/source/cPlayer.h +++ b/source/cPlayer.h @@ -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; diff --git a/source/items/Item.cpp b/source/items/Item.cpp index 3dd0a4218..ce72cf8b3 100644 --- a/source/items/Item.cpp +++ b/source/items/Item.cpp @@ -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 @@ -230,4 +238,31 @@ void cItemHandler::PlaceBlock(cWorld *a_World, cPlayer *a_Player, cItem *a_Item, Handler->PlaceBlock(a_World, a_Player, GetBlockMeta(a_Item->m_ItemHealth), a_X, a_Y, a_Z, a_Dir); 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); } \ No newline at end of file diff --git a/source/items/Item.h b/source/items/Item.h index 96f957fcf..0a38ce3c0 100644 --- a/source/items/Item.h +++ b/source/items/Item.h @@ -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); diff --git a/source/items/ItemFood.h b/source/items/ItemFood.h new file mode 100644 index 000000000..8998fd503 --- /dev/null +++ b/source/items/ItemFood.h @@ -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); + } + +}; \ No newline at end of file diff --git a/source/squirrelbindings/SquirrelBindings.cpp b/source/squirrelbindings/SquirrelBindings.cpp index f0291b39b..c24b82c70 100644 --- a/source/squirrelbindings/SquirrelBindings.cpp +++ b/source/squirrelbindings/SquirrelBindings.cpp @@ -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() @@ -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() @@ -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)); +} -} \ No newline at end of file +#endif \ No newline at end of file diff --git a/source/squirrelbindings/SquirrelBindings.h b/source/squirrelbindings/SquirrelBindings.h index 1b71f5e86..d5aee170a 100644 --- a/source/squirrelbindings/SquirrelBindings.h +++ b/source/squirrelbindings/SquirrelBindings.h @@ -1,7 +1,7 @@ #pragma once -#define USE_SQUIRREL 1 +#define USE_SQUIRREL 0 #if USE_SQUIRREL diff --git a/source/squirrelbindings/SquirrelFunctions.cpp b/source/squirrelbindings/SquirrelFunctions.cpp index 88871369d..b965c63ab 100644 --- a/source/squirrelbindings/SquirrelFunctions.cpp +++ b/source/squirrelbindings/SquirrelFunctions.cpp @@ -3,6 +3,9 @@ #include "SquirrelFunctions.h" #include "SquirrelBindings.h" + +#if USE_SQUIRREL + static HSQUIRRELVM squirrelvm = NULL; SQInteger runtimeErrorHandler(HSQUIRRELVM a_VM) @@ -62,4 +65,6 @@ void CloseSquirrelVM() void sqPrint(SQChar * text) { LOGINFO("%s", text); -} \ No newline at end of file +} + +#endif \ No newline at end of file