1
0

Fixed hunger bugs, Implemented golden apple, added jump statistic, added correct food effects.

This commit is contained in:
Howaner 2014-07-31 23:04:00 +02:00
parent 5a1f9e5044
commit 84462ba8b2
8 changed files with 177 additions and 48 deletions

View File

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

View File

@ -309,7 +309,7 @@ void cEntityEffectHunger::OnTick(cPawn & a_Target)
if (a_Target.IsPlayer()) if (a_Target.IsPlayer())
{ {
cPlayer & Target = (cPlayer &) a_Target; 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) 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) void cPlayer::FoodPoison(int a_NumTicks)
{ {
AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1); AddEntityEffect(cEntityEffect::effHunger, a_NumTicks, 0, 1);
@ -1979,19 +1991,34 @@ void cPlayer::HandleFood(void)
return; 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: // 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++; m_FoodTickTimer++;
if (m_FoodTickTimer >= 80) if (m_FoodTickTimer >= 80)
{ {
m_FoodTickTimer = 0; 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: // Regenerate health from food, incur 3 pts of food exhaustion:
Heal(1); Heal(1);
m_FoodExhaustionLevel += 3.0; AddFoodExhaustion(3.0);
} }
else if ((m_FoodLevel <= 0) && (m_Health > 1)) else if ((m_FoodLevel <= 0) && (m_Health > 1))
{ {
@ -2000,20 +2027,9 @@ void cPlayer::HandleFood(void)
} }
} }
} }
else
// Apply food exhaustion that has accumulated:
if (m_FoodExhaustionLevel >= 4.0)
{ {
m_FoodExhaustionLevel -= 4.0; m_FoodTickTimer = 0;
if (m_FoodSaturationLevel >= 1.0)
{
m_FoodSaturationLevel -= 1.0;
}
else
{
SetFoodLevel(m_FoodLevel - 1);
}
} }
} }
@ -2088,14 +2104,17 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
else if (IsSubmerged()) else if (IsSubmerged())
{ {
m_Stats.AddValue(statDistDove, Value); m_Stats.AddValue(statDistDove, Value);
AddFoodExhaustion(0.00015 * (double)Value);
} }
else if (IsSwimming()) else if (IsSwimming())
{ {
m_Stats.AddValue(statDistSwum, Value); m_Stats.AddValue(statDistSwum, Value);
AddFoodExhaustion(0.00015 * (double)Value);
} }
else if (IsOnGround()) else if (IsOnGround())
{ {
m_Stats.AddValue(statDistWalked, Value); m_Stats.AddValue(statDistWalked, Value);
AddFoodExhaustion((m_IsSprinting ? 0.001 : 0.0001) * (double)Value);
} }
else else
{ {

View File

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

View File

@ -33,29 +33,69 @@ public:
case E_ITEM_BREAD: return FoodInfo(5, 6); case E_ITEM_BREAD: return FoodInfo(5, 6);
// Carrots handled in ItemSeeds // Carrots handled in ItemSeeds
case E_ITEM_COOKED_CHICKEN: return FoodInfo(6, 7.2); 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_COOKED_PORKCHOP: return FoodInfo(8, 12.8);
case E_ITEM_COOKIE: return FoodInfo(2, 0.4); 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_GOLDEN_CARROT: return FoodInfo(6, 14.4);
case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2); case E_ITEM_MELON_SLICE: return FoodInfo(2, 1.2);
case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.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 // Potatoes handled in ItemSeeds
case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8); case E_ITEM_PUMPKIN_PIE: return FoodInfo(8, 4.8);
case E_ITEM_RAW_BEEF: return FoodInfo(3, 1.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_FISH: return FoodInfo(2, 1.2);
case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8); case E_ITEM_RAW_PORKCHOP: return FoodInfo(3, 1.8);
case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4); case E_ITEM_RED_APPLE: return FoodInfo(4, 2.4);
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80); case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8);
case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2, 100); case E_ITEM_SPIDER_EYE: return FoodInfo(2, 3.2);
case E_ITEM_STEAK: return FoodInfo(8, 12.8); case E_ITEM_STEAK: return FoodInfo(8, 12.8);
} }
LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType); LOGWARNING("%s: Unknown food item (%d), returning zero nutrition", __FUNCTION__, m_ItemType);
return FoodInfo(0, 0.f); 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 "ItemFishingRod.h"
#include "ItemFlowerPot.h" #include "ItemFlowerPot.h"
#include "ItemFood.h" #include "ItemFood.h"
#include "ItemGoldenApple.h"
#include "ItemItemFrame.h" #include "ItemItemFrame.h"
#include "ItemHoe.h" #include "ItemHoe.h"
#include "ItemLeaves.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_BED: return new cItemBedHandler(a_ItemType);
case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType); case E_ITEM_BOAT: return new cItemBoatHandler(a_ItemType);
case E_ITEM_BOTTLE_O_ENCHANTING: return new cItemBottleOEnchantingHandler(); 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_BREWING_STAND: return new cItemBrewingStandHandler(a_ItemType);
case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType); case E_ITEM_CAKE: return new cItemCakeHandler(a_ItemType);
case E_ITEM_CAULDRON: return new cItemCauldronHandler(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_FISHING_ROD: return new cItemFishingRodHandler(a_ItemType);
case E_ITEM_FLINT_AND_STEEL: return new cItemLighterHandler(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_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_BLOCK_LILY_PAD: return new cItemLilypadHandler(a_ItemType);
case E_ITEM_MAP: return new cItemMapHandler(); case E_ITEM_MAP: return new cItemMapHandler();
case E_ITEM_MILK: return new cItemMilkHandler(); 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_FISH:
case E_ITEM_COOKED_PORKCHOP: case E_ITEM_COOKED_PORKCHOP:
case E_ITEM_COOKIE: case E_ITEM_COOKIE:
case E_ITEM_GOLDEN_APPLE:
case E_ITEM_GOLDEN_CARROT: case E_ITEM_GOLDEN_CARROT:
case E_ITEM_MELON_SLICE: case E_ITEM_MELON_SLICE:
case E_ITEM_MUSHROOM_SOUP: case E_ITEM_MUSHROOM_SOUP:
@ -618,29 +619,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) bool cItemHandler::EatItem(cPlayer * a_Player, cItem * a_Item)
{ {
UNUSED(a_Item); UNUSED(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 consumed and there's chance of foodpoisoning, do it: // Give effects
if (Success && (Info.PoisonChance > 0)) cEntityEffect::eType EffectType;
int EffectDurationTicks;
short EffectIntensity;
float Chance;
if (Success && GetEatEffect(EffectType, EffectDurationTicks, EffectIntensity, Chance))
{ {
cFastRandom r1; 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 Success;
} }
return false; return false;
} }

View File

@ -3,6 +3,7 @@
#include "../Defines.h" #include "../Defines.h"
#include "../Item.h" #include "../Item.h"
#include "../Entities/EntityEffect.h"
@ -71,23 +72,24 @@ public:
struct FoodInfo struct FoodInfo
{ {
double Saturation;
int FoodLevel; 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) : FoodInfo(int a_FoodLevel, double a_Saturation, int a_PoisonChance = 0) :
Saturation(a_Saturation),
FoodLevel(a_FoodLevel), 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(); 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 */ /** 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 */ /** Indicates if this item is a tool */
virtual bool IsTool(void); virtual bool IsTool(void);