Merge pull request #52 from ravenscroftj/feature/food
A few fixes for the hunger/food system + tests for swimming and submerged in cPlayer.
This commit is contained in:
commit
6f2c099f70
@ -504,9 +504,14 @@ void cClientHandle::HandlePlayerPos(double a_PosX, double a_PosY, double a_PosZ,
|
|||||||
|
|
||||||
// If a jump just started, process food exhaustion:
|
// If a jump just started, process food exhaustion:
|
||||||
if ((a_PosY > m_Player->GetPosY()) && !a_IsOnGround && m_Player->IsOnGround())
|
if ((a_PosY > m_Player->GetPosY()) && !a_IsOnGround && m_Player->IsOnGround())
|
||||||
|
{
|
||||||
|
// we only add this exhaustion if the player is not swimming - otherwise we end up with both jump + swim exhaustion
|
||||||
|
|
||||||
|
if(! m_Player->IsSwimming() )
|
||||||
{
|
{
|
||||||
m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2);
|
m_Player->AddFoodExhaustion(m_Player->IsSprinting() ? 0.8 : 0.2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
m_Player->MoveTo(Pos);
|
m_Player->MoveTo(Pos);
|
||||||
m_Player->SetStance(a_Stance);
|
m_Player->SetStance(a_Stance);
|
||||||
|
@ -50,6 +50,7 @@ public:
|
|||||||
case E_ITEM_ROTTEN_FLESH: return FoodInfo(4, 0.8, 80);
|
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_SPIDER_EYE: return FoodInfo(2, 3.2, 100);
|
||||||
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
|
case E_ITEM_STEAK: return FoodInfo(8, 12.8);
|
||||||
|
case E_ITEM_MUSHROOM_SOUP: return FoodInfo(6, 7.2);
|
||||||
}
|
}
|
||||||
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);
|
||||||
|
@ -181,6 +181,7 @@ cItemHandler *cItemHandler::CreateItemHandler(int a_ItemType)
|
|||||||
case E_ITEM_RED_APPLE:
|
case E_ITEM_RED_APPLE:
|
||||||
case E_ITEM_GOLDEN_APPLE:
|
case E_ITEM_GOLDEN_APPLE:
|
||||||
case E_ITEM_ROTTEN_FLESH:
|
case E_ITEM_ROTTEN_FLESH:
|
||||||
|
case E_ITEM_MUSHROOM_SOUP:
|
||||||
case E_ITEM_SPIDER_EYE:
|
case E_ITEM_SPIDER_EYE:
|
||||||
{
|
{
|
||||||
return new cItemFoodHandler(a_ItemType);
|
return new cItemFoodHandler(a_ItemType);
|
||||||
|
@ -61,6 +61,8 @@ 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_IsSwimming(false)
|
||||||
|
, m_IsSubmerged(false)
|
||||||
, m_EatingFinishTick(-1)
|
, 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",
|
||||||
@ -181,13 +183,16 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
|
|
||||||
super::Tick(a_Dt, a_Chunk);
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
|
||||||
|
// set player swimming state
|
||||||
|
SetSwimState( a_Chunk);
|
||||||
|
|
||||||
// handle air drowning stuff
|
// handle air drowning stuff
|
||||||
HandleAir(a_Chunk);
|
HandleAir();
|
||||||
|
|
||||||
if (m_bDirtyPosition)
|
if (m_bDirtyPosition)
|
||||||
{
|
{
|
||||||
// Apply food exhaustion from movement:
|
// Apply food exhaustion from movement:
|
||||||
ApplyFoodExhaustionFromMovement(a_Chunk);
|
ApplyFoodExhaustionFromMovement();
|
||||||
|
|
||||||
cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this);
|
cRoot::Get()->GetPluginManager()->CallHookPlayerMoving(*this);
|
||||||
BroadcastMovementUpdate(m_ClientHandle);
|
BroadcastMovementUpdate(m_ClientHandle);
|
||||||
@ -400,7 +405,14 @@ void cPlayer::FinishEating(void)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ItemHandler->OnFoodEaten(m_World, this, &Item);
|
ItemHandler->OnFoodEaten(m_World, this, &Item);
|
||||||
|
|
||||||
GetInventory().RemoveOneEquippedItem();
|
GetInventory().RemoveOneEquippedItem();
|
||||||
|
|
||||||
|
//if the food is mushroom soup, return a bowl to the inventory
|
||||||
|
if( Item.m_ItemType == E_ITEM_MUSHROOM_SOUP ) {
|
||||||
|
cItem emptyBowl(E_ITEM_BOWL, 1, 0, "");
|
||||||
|
GetInventory().AddItem(emptyBowl, true, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1319,20 +1331,35 @@ void cPlayer::UseEquippedItem()
|
|||||||
GetInventory().DamageEquippedItem();
|
GetInventory().DamageEquippedItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cPlayer::SetSwimState(cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
|
||||||
void cPlayer::HandleAir(cChunk & a_Chunk)
|
BLOCKTYPE BlockIn;
|
||||||
|
int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||||
|
int RelY = (int)floor(m_LastPosY + 0.1);
|
||||||
|
int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||||
|
|
||||||
|
// first we check if the player is swimming
|
||||||
|
|
||||||
|
// Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
|
||||||
|
VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn));
|
||||||
|
|
||||||
|
m_IsSwimming = IsBlockWater(BlockIn);
|
||||||
|
|
||||||
|
// now we check if the player is submerged
|
||||||
|
|
||||||
|
VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY+1, RelZ, BlockIn));
|
||||||
|
|
||||||
|
m_IsSubmerged = IsBlockWater(BlockIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cPlayer::HandleAir()
|
||||||
{
|
{
|
||||||
// Ref.: http://www.minecraftwiki.net/wiki/Chunk_format
|
// Ref.: http://www.minecraftwiki.net/wiki/Chunk_format
|
||||||
// see if the player is /submerged/ water (block above is water)
|
// see if the player is /submerged/ water (block above is water)
|
||||||
// Get the type of block the player's standing in:
|
// Get the type of block the player's standing in:
|
||||||
BLOCKTYPE BlockIn;
|
|
||||||
int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
|
|
||||||
int RelY = (int)floor(m_LastPosY + 1.1);
|
|
||||||
int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
||||||
// Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
|
|
||||||
VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn));
|
|
||||||
|
|
||||||
if (IsBlockWater(BlockIn))
|
if (IsSubmerged())
|
||||||
{
|
{
|
||||||
// either reduce air level or damage player
|
// either reduce air level or damage player
|
||||||
if(m_AirLevel < 1)
|
if(m_AirLevel < 1)
|
||||||
@ -1419,7 +1446,7 @@ void cPlayer::HandleFood(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::ApplyFoodExhaustionFromMovement(cChunk & a_Chunk)
|
void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||||
{
|
{
|
||||||
if (IsGameModeCreative())
|
if (IsGameModeCreative())
|
||||||
{
|
{
|
||||||
@ -1437,14 +1464,6 @@ void cPlayer::ApplyFoodExhaustionFromMovement(cChunk & a_Chunk)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the type of block the player's standing in:
|
|
||||||
BLOCKTYPE BlockIn;
|
|
||||||
int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width;
|
|
||||||
int RelY = (int)floor(m_LastPosY + 0.1);
|
|
||||||
int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
||||||
// Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk
|
|
||||||
VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn));
|
|
||||||
|
|
||||||
// Apply the exhaustion based on distance travelled:
|
// Apply the exhaustion based on distance travelled:
|
||||||
double BaseExhaustion = Movement.Length();
|
double BaseExhaustion = Movement.Length();
|
||||||
if (IsSprinting())
|
if (IsSprinting())
|
||||||
@ -1452,7 +1471,7 @@ void cPlayer::ApplyFoodExhaustionFromMovement(cChunk & a_Chunk)
|
|||||||
// 0.1 pt per meter sprinted
|
// 0.1 pt per meter sprinted
|
||||||
BaseExhaustion = BaseExhaustion * 0.1;
|
BaseExhaustion = BaseExhaustion * 0.1;
|
||||||
}
|
}
|
||||||
else if (IsBlockWater(BlockIn))
|
else if (IsSwimming())
|
||||||
{
|
{
|
||||||
// 0.015 pt per meter swum
|
// 0.015 pt per meter swum
|
||||||
BaseExhaustion = BaseExhaustion * 0.015;
|
BaseExhaustion = BaseExhaustion * 0.015;
|
||||||
|
@ -253,6 +253,12 @@ public:
|
|||||||
/// Starts or stops sprinting, sends the max speed update to the client, if needed
|
/// Starts or stops sprinting, sends the max speed update to the client, if needed
|
||||||
void SetSprint(bool a_IsSprinting);
|
void SetSprint(bool a_IsSprinting);
|
||||||
|
|
||||||
|
/// Returns whether the player is swimming or not
|
||||||
|
virtual bool IsSwimming(void) const{ return m_IsSwimming; }
|
||||||
|
|
||||||
|
/// Return whether the player is under water or not
|
||||||
|
virtual bool IsSubmerged(void) const{ return m_IsSubmerged; }
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
// cEntity overrides:
|
// cEntity overrides:
|
||||||
@ -260,6 +266,8 @@ public:
|
|||||||
virtual bool IsSprinting(void) const { return m_IsSprinting; }
|
virtual bool IsSprinting(void) const { return m_IsSprinting; }
|
||||||
virtual bool IsRclking (void) const { return IsEating(); }
|
virtual bool IsRclking (void) const { return IsEating(); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef std::map< std::string, bool > PermissionMap;
|
typedef std::map< std::string, bool > PermissionMap;
|
||||||
PermissionMap m_ResolvedPermissions;
|
PermissionMap m_ResolvedPermissions;
|
||||||
@ -335,6 +343,9 @@ protected:
|
|||||||
bool m_IsCrouched;
|
bool m_IsCrouched;
|
||||||
bool m_IsSprinting;
|
bool m_IsSprinting;
|
||||||
|
|
||||||
|
bool m_IsSwimming;
|
||||||
|
bool m_IsSubmerged;
|
||||||
|
|
||||||
/// The world tick in which eating will be finished. -1 if not eating
|
/// The world tick in which eating will be finished. -1 if not eating
|
||||||
Int64 m_EatingFinishTick;
|
Int64 m_EatingFinishTick;
|
||||||
|
|
||||||
@ -347,10 +358,13 @@ protected:
|
|||||||
void HandleFood(void);
|
void HandleFood(void);
|
||||||
|
|
||||||
/// Called in each tick to handle air-related processing i.e. drowning
|
/// Called in each tick to handle air-related processing i.e. drowning
|
||||||
void HandleAir(cChunk & a_Chunk);
|
void HandleAir();
|
||||||
|
|
||||||
|
/// Called once per tick to set IsSwimming and IsSubmerged
|
||||||
|
void SetSwimState(cChunk & a_Chunk);
|
||||||
|
|
||||||
/// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
|
/// Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block)
|
||||||
void ApplyFoodExhaustionFromMovement(cChunk & a_Chunk);
|
void ApplyFoodExhaustionFromMovement();
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user