1
0

Merge pull request #1272 from Howaner/Food

Fixed hunger bugs, Implemented golden apple, added jump statistic, added...
This commit is contained in:
Mattes D 2014-08-01 17:43:18 +02:00
commit d2744713bb
8 changed files with 177 additions and 48 deletions

View File

@ -635,6 +635,7 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
if (!m_Player->IsSwimming())
{
m_Player->GetStatManager().AddValue(statJumps, 1);
m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2);
}
}
@ -1121,6 +1122,7 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
return;
}
m_Player->AddFoodExhaustion(0.025);
ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ);
// The ItemHandler is also responsible for spawning the pickups
cChunkInterface ChunkInterface(World->GetChunkMap());
@ -1266,7 +1268,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
else if ((ItemHandler->IsFood() || ItemHandler->IsDrinkable(EquippedDamage)))
{
if ((m_Player->IsSatiated() || m_Player->IsGameModeCreative()) &&
ItemHandler->IsFood())
ItemHandler->IsFood() && (Equipped.m_ItemType != E_ITEM_GOLDEN_APPLE))
{
// The player is satiated or in creative, and trying to eat
return;

View File

@ -309,7 +309,7 @@ void cEntityEffectHunger::OnTick(cPawn & a_Target)
if (a_Target.IsPlayer())
{
cPlayer & Target = (cPlayer &) a_Target;
Target.SetFoodExhaustionLevel(Target.GetFoodExhaustionLevel() + 0.025); // 0.5 per second = 0.025 per tick
Target.AddFoodExhaustion(0.025 * ((double)GetIntensity() + 1.0)); // 0.5 per second = 0.025 per tick
}
}

View File

@ -545,7 +545,7 @@ void cPlayer::SetFoodTickTimer(int a_FoodTickTimer)
void cPlayer::SetFoodExhaustionLevel(double a_FoodExhaustionLevel)
{
m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 4.0));
m_FoodExhaustionLevel = std::max(0.0, std::min(a_FoodExhaustionLevel, 40.0));
}
@ -568,6 +568,18 @@ bool cPlayer::Feed(int a_Food, double a_Saturation)
void cPlayer::AddFoodExhaustion(double a_Exhaustion)
{
if (!IsGameModeCreative())
{
m_FoodExhaustionLevel = std::min(m_FoodExhaustionLevel + a_Exhaustion, 40.0);
}
}
void cPlayer::FoodPoison(int a_NumTicks)
{
AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1);
@ -1979,19 +1991,34 @@ void cPlayer::HandleFood(void)
return;
}
// Apply food exhaustion that has accumulated:
if (m_FoodExhaustionLevel > 4.0)
{
m_FoodExhaustionLevel -= 4.0;
if (m_FoodSaturationLevel > 0.0)
{
m_FoodSaturationLevel = std::max(m_FoodSaturationLevel - 1.0, 0.0);
}
else
{
SetFoodLevel(m_FoodLevel - 1);
}
}
// Heal or damage, based on the food level, using the m_FoodTickTimer:
if ((m_FoodLevel > 17) || (m_FoodLevel <= 0))
if ((m_FoodLevel >= 18) || (m_FoodLevel <= 0))
{
m_FoodTickTimer++;
if (m_FoodTickTimer >= 80)
{
m_FoodTickTimer = 0;
if ((m_FoodLevel > 17) && (GetHealth() < GetMaxHealth()))
if ((m_FoodLevel >= 18) && (GetHealth() < GetMaxHealth()))
{
// Regenerate health from food, incur 3 pts of food exhaustion:
Heal(1);
m_FoodExhaustionLevel += 3.0;
AddFoodExhaustion(3.0);
}
else if ((m_FoodLevel <= 0) && (m_Health > 1))
{
@ -2000,20 +2027,9 @@ void cPlayer::HandleFood(void)
}
}
}
// Apply food exhaustion that has accumulated:
if (m_FoodExhaustionLevel >= 4.0)
else
{
m_FoodExhaustionLevel -= 4.0;
if (m_FoodSaturationLevel >= 1.0)
{
m_FoodSaturationLevel -= 1.0;
}
else
{
SetFoodLevel(m_FoodLevel - 1);
}
m_FoodTickTimer = 0;
}
}
@ -2088,14 +2104,17 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
else if (IsSubmerged())
{
m_Stats.AddValue(statDistDove, Value);
AddFoodExhaustion(0.00015 * (double)Value);
}
else if (IsSwimming())
{
m_Stats.AddValue(statDistSwum, Value);
AddFoodExhaustion(0.00015 * (double)Value);
}
else if (IsOnGround())
{
m_Stats.AddValue(statDistWalked, Value);
AddFoodExhaustion((m_IsSprinting ? 0.001 : 0.0001) * (double)Value);
}
else
{

View File

@ -284,10 +284,7 @@ public:
bool Feed(int a_Food, double a_Saturation);
/** Adds the specified exhaustion to m_FoodExhaustion. Expects only positive values. */
void AddFoodExhaustion(double a_Exhaustion)
{
m_FoodExhaustionLevel += a_Exhaustion;
}
void AddFoodExhaustion(double a_Exhaustion);
/** Starts the food poisoning for the specified amount of ticks */
void FoodPoison(int a_NumTicks);

View File

@ -33,29 +33,69 @@ public:
case E_ITEM_BREAD: return FoodInfo(5, 6);
// Carrots handled in ItemSeeds
case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2);
case E_ITEM_COOKED_FISH: return FoodInfo(5, 6);
case E_ITEM_COOKED_FISH: return FoodInfo(5, 6); // TODO: Add other fish types
case E_ITEM_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
case E_ITEM_COOKIE: return FoodInfo(2, 0.4);
case E_ITEM_GOLDEN_APPLE: return FoodInfo(4, 9.6);
// Golden apple handled in ItemGoldenApple
case E_ITEM_GOLDEN_CARROT: return FoodInfo(6, 14.4);
case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2, 60);
case E_ITEM_POISONOUS_POTATO: return FoodInfo(2, 1.2);
// Potatoes handled in ItemSeeds
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.8);
case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2, 30);
case E_ITEM_RAW_CHICKEN: return FoodInfo(2, 1.2);
case E_ITEM_RAW_FISH: return FoodInfo(2, 1.2);
case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8);
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2);
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
}
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f);
}
virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance) override
{
switch (m_ItemType)
{
case E_ITEM_RAW_CHICKEN:
{
a_EffectType = cEntityEffect::effHunger;
a_EffectDurationTicks = 600;
a_EffectIntensity = 0;
a_Chance = 0.3f;
return true;
}
case E_ITEM_ROTTEN_FLESH:
{
a_EffectType = cEntityEffect::effHunger;
a_EffectDurationTicks = 600;
a_EffectIntensity = 0;
a_Chance = 0.8f;
return true;
}
case E_ITEM_SPIDER_EYE:
{
a_EffectType = cEntityEffect::effPoison;
a_EffectDurationTicks = 100;
a_EffectIntensity = 0;
a_Chance = 1.0f;
return true;
}
case E_ITEM_POISONOUS_POTATO:
{
a_EffectType = cEntityEffect::effPoison;
a_EffectDurationTicks = 100;
a_EffectIntensity = 0;
a_Chance = 0.6f;
return true;
}
}
return false;
}
};

View File

@ -0,0 +1,58 @@
#pragma once
#include "ItemFood.h"
class cItemGoldenAppleHandler :
public cItemFoodHandler
{
typedef cItemFoodHandler super;
public:
cItemGoldenAppleHandler()
: super(E_ITEM_GOLDEN_APPLE)
{
}
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item) override
{
// Feed the player:
FoodInfo Info = GetFoodInfo();
a_Player->Feed(Info.FoodLevel, Info.Saturation);
// Add the effects:
a_Player->AddEntityEffect(cEntityEffect::effAbsorption, 2400, 0);
a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 100, 1);
// When the apple is a 'notch apple', give extra effects:
if (a_Item->m_ItemDamage > 0)
{
a_Player->AddEntityEffect(cEntityEffect::effRegeneration, 600, 4);
a_Player->AddEntityEffect(cEntityEffect::effResistance, 6000, 0);
a_Player->AddEntityEffect(cEntityEffect::effFireResistance, 6000, 0);
}
return true;
}
virtual FoodInfo GetFoodInfo(void) override
{
return FoodInfo(4, 9.6);
}
virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance) override
{
return false;
}
};

View File

@ -25,6 +25,7 @@
#include "ItemFishingRod.h"
#include "ItemFlowerPot.h"
#include "ItemFood.h"
#include "ItemGoldenApple.h"
#include "ItemItemFrame.h"
#include "ItemHoe.h"
#include "ItemLeaves.h"
@ -106,7 +107,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_BED: return new cItemBedHandler(a_ItemType);
case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType);
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler();
case E_ITEM_BOW: return new cItemBowHandler;
case E_ITEM_BOW: return new cItemBowHandler();
case E_ITEM_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(a_ItemType);
@ -120,6 +121,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(a_ItemType);
case E_ITEM_FLOWER_POT: return new cItemFlowerPotHandler(a_ItemType);
case E_ITEM_GOLDEN_APPLE: return new cItemGoldenAppleHandler();
case E_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_MILK: return new cItemMilkHandler();
@ -212,7 +214,6 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
case E_ITEM_COOKED_FISH:
case E_ITEM_COOKED_PORKCHOP:
case E_ITEM_COOKIE:
case E_ITEM_GOLDEN_APPLE:
case E_ITEM_GOLDEN_CARROT:
case E_ITEM_MELON_SLICE:
case E_ITEM_MUSHROOM_SOUP:
@ -619,29 +620,39 @@ bool cItemHandler::GetPlacementBlockTypeMeta(
bool cItemHandler::GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance)
{
return false;
}
bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{
UNUSED(a_Item);
FoodInfo Info = GetFoodInfo();
FoodInfo Info = GetFoodInfo();
if ((Info.FoodLevel > 0) || (Info.Saturation > 0.f))
{
bool Success = a_Player->Feed(Info.FoodLevel, Info.Saturation);
// If consumed and there's chance of foodpoisoning, do it:
if (Success && (Info.PoisonChance > 0))
// Give effects
cEntityEffect::eType EffectType;
int EffectDurationTicks;
short EffectIntensity;
float Chance;
if (Success && GetEatEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance))
{
cFastRandom r1;
if ((r1.NextInt(100, a_Player->GetUniqueID()) - Info.PoisonChance) <= 0)
if (r1.NextFloat() < Chance)
{
a_Player->FoodPoison(600); // Give the player food poisoning for 30 seconds.
a_Player->AddEntityEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance);
}
}
return Success;
}
return false;
}

View File

@ -3,6 +3,7 @@
#include "../Defines.h"
#include "../Item.h"
#include "../Entities/EntityEffect.h"
@ -71,23 +72,24 @@ public:
struct FoodInfo
{
double Saturation;
int FoodLevel;
int PoisonChance; // 0 - 100, in percent. 0 = no chance of poisoning, 100 = sure poisoning
double Saturation;
FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
Saturation(a_Saturation),
FoodLevel(a_FoodLevel),
PoisonChance(a_PoisonChance)
Saturation(a_Saturation)
{
}
} ;
/** Returns the FoodInfo for this item. (FoodRecovery, Saturation and PoisionChance) */
/** Returns the FoodInfo for this item. (FoodRecovery and Saturation) */
virtual FoodInfo GetFoodInfo();
/** If this function returns true, it sets the arguments to a effect who will be activated when you eat the item. */
virtual bool GetEatEffect(cEntityEffect::eType & a_EffectType, int & a_EffectDurationTicks, short & a_EffectIntensity, float & a_Chance);
/** Lets the player eat a selected item. Returns true if the player ate the item */
virtual bool EatItem(cPlayer *a_Player, cItem *a_Item);
virtual bool EatItem(cPlayer * a_Player, cItem * a_Item);
/** Indicates if this item is a tool */
virtual bool IsTool(void);