diff options
Diffstat (limited to 'src/Entities')
-rw-r--r-- | src/Entities/Entity.cpp | 134 | ||||
-rw-r--r-- | src/Entities/Entity.h | 38 | ||||
-rw-r--r-- | src/Entities/Pickup.cpp | 67 | ||||
-rw-r--r-- | src/Entities/Player.cpp | 302 | ||||
-rw-r--r-- | src/Entities/Player.h | 47 |
5 files changed, 352 insertions, 236 deletions
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 565c78dfd..e22f689d9 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -4,9 +4,7 @@ #include "../World.h" #include "../Server.h" #include "../Root.h" -#include "../Vector3d.h" #include "../Matrix4f.h" -#include "../ReferenceManager.h" #include "../ClientHandle.h" #include "../Chunk.h" #include "../Simulator/FluidSimulator.h" @@ -32,8 +30,6 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_MaxHealth(1) , m_AttachedTo(NULL) , m_Attachee(NULL) - , m_Referencers(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCERS)) - , m_References(new cReferenceManager(cReferenceManager::RFMNGR_REFERENCES)) , m_bDirtyHead(true) , m_bDirtyOrientation(true) , m_bDirtyPosition(true) @@ -61,6 +57,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d , m_Mass (0.001) // Default 1g , m_Width(a_Width) , m_Height(a_Height) + , m_IsSubmerged(false) + , m_IsSwimming(false) { cCSLock Lock(m_CSCount); m_EntityCount++; @@ -73,7 +71,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d cEntity::~cEntity() { - ASSERT(!m_World->HasEntity(m_UniqueID)); // Before deleting, the entity needs to have been removed from the world + // Before deleting, the entity needs to have been removed from the world, if ever added + ASSERT((m_World == NULL) || !m_World->HasEntity(m_UniqueID)); /* // DEBUG: @@ -99,8 +98,6 @@ cEntity::~cEntity() LOGWARNING("ERROR: Entity deallocated without being destroyed"); ASSERT(!"Entity deallocated without being destroyed or unlinked"); } - delete m_Referencers; - delete m_References; } @@ -534,7 +531,17 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) { TickInVoid(a_Chunk); } - else { m_TicksSinceLastVoidDamage = 0; } + else + m_TicksSinceLastVoidDamage = 0; + + if (IsMob() || IsPlayer()) + { + // Set swimming state + SetSwimState(a_Chunk); + + // Handle drowning + HandleAir(); + } } @@ -912,6 +919,87 @@ void cEntity::TickInVoid(cChunk & a_Chunk) +void cEntity::SetSwimState(cChunk & a_Chunk) +{ + int RelY = (int)floor(m_LastPosY + 0.1); + if ((RelY < 0) || (RelY >= cChunkDef::Height - 1)) + { + m_IsSwimming = false; + m_IsSubmerged = false; + return; + } + + BLOCKTYPE BlockIn; + int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; + int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; + + // Check if the player is swimming: + // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk + if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn)) + { + // This sometimes happens on Linux machines + // Ref.: http://forum.mc-server.org/showthread.php?tid=1244 + LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}", + RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ() + ); + m_IsSwimming = false; + m_IsSubmerged = false; + return; + } + m_IsSwimming = IsBlockWater(BlockIn); + + // Check if the player is submerged: + VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY + 1, RelZ, BlockIn)); + m_IsSubmerged = IsBlockWater(BlockIn); +} + + + + + +void cEntity::HandleAir(void) +{ + // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format + // See if the entity is /submerged/ water (block above is water) + // Get the type of block the entity is standing in: + + if (IsSubmerged()) + { + SetSpeedY(1); // Float in the water + + // Either reduce air level or damage player + if (m_AirLevel < 1) + { + if (m_AirTickTimer < 1) + { + // Damage player + TakeDamage(dtDrowning, NULL, 1, 1, 0); + // Reset timer + m_AirTickTimer = DROWNING_TICKS; + } + else + { + m_AirTickTimer -= 1; + } + } + else + { + // Reduce air supply + m_AirLevel -= 1; + } + } + else + { + // Set the air back to maximum + m_AirLevel = MAX_AIR_LEVEL; + m_AirTickTimer = DROWNING_TICKS; + } +} + + + + + /// Called when the entity starts burning void cEntity::OnStartedBurning(void) { @@ -1429,33 +1517,3 @@ void cEntity::SetPosZ(double a_PosZ) - -////////////////////////////////////////////////////////////////////////// -// Reference stuffs -void cEntity::AddReference(cEntity * & a_EntityPtr) -{ - m_References->AddReference(a_EntityPtr); - a_EntityPtr->ReferencedBy(a_EntityPtr); -} - - - - - -void cEntity::ReferencedBy(cEntity * & a_EntityPtr) -{ - m_Referencers->AddReference(a_EntityPtr); -} - - - - - -void cEntity::Dereference(cEntity * & a_EntityPtr) -{ - m_Referencers->Dereference(a_EntityPtr); -} - - - - diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index 91463bfd6..b2edfc2b4 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -4,6 +4,7 @@ #include "../Item.h" #include "../Vector3d.h" #include "../Vector3f.h" +#include "../Vector3i.h" @@ -28,12 +29,16 @@ return super::GetClass(); \ } +#define POSX_TOINT (int)floor(GetPosX()) +#define POSY_TOINT (int)floor(GetPosY()) +#define POSZ_TOINT (int)floor(GetPosZ()) +#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT) + class cWorld; -class cReferenceManager; class cClientHandle; class cPlayer; class cChunk; @@ -110,6 +115,8 @@ public: BURN_TICKS_PER_DAMAGE = 20, ///< How many ticks to wait between damaging an entity when it is burning BURN_DAMAGE = 1, ///< How much damage to deal when the entity is burning BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire + MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have + DROWNING_TICKS = 20, ///< Number of ticks per heart of damage } ; cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height); @@ -344,7 +351,14 @@ public: virtual bool IsRiding (void) const {return false; } virtual bool IsSprinting(void) const {return false; } virtual bool IsRclking (void) const {return false; } - virtual bool IsInvisible(void) const {return false; } + virtual bool IsInvisible(void) const { return false; } + + /** 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; } + /** Gets remaining air of a monster */ + int GetAirLevel(void) const { return m_AirLevel; } // tolua_end @@ -373,9 +387,6 @@ protected: /// The entity which is attached to this entity (rider), NULL if none cEntity * m_Attachee; - cReferenceManager* m_Referencers; - cReferenceManager* m_References; - // Flags that signal that we haven't updated the clients with the latest. bool m_bDirtyHead; bool m_bDirtyOrientation; @@ -415,11 +426,18 @@ protected: virtual void Destroyed(void) {} // Called after the entity has been destroyed void SetWorld(cWorld * a_World) { m_World = a_World; } - - friend class cReferenceManager; - void AddReference( cEntity*& a_EntityPtr ); - void ReferencedBy( cEntity*& a_EntityPtr ); - void Dereference( cEntity*& a_EntityPtr ); + + /** Called in each tick to handle air-related processing i.e. drowning */ + virtual void HandleAir(); + /** Called once per tick to set IsSwimming and IsSubmerged */ + virtual void SetSwimState(cChunk & a_Chunk); + + /** If an entity is currently swimming in or submerged under water */ + bool m_IsSwimming, m_IsSubmerged; + + /** Air level of a mobile */ + int m_AirLevel; + int m_AirTickTimer; private: // Measured in degrees, [-180, +180) diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 001e386a7..bfe162b69 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -6,19 +6,58 @@ #endif #include "Pickup.h" +#include "Player.h" #include "../ClientHandle.h" -#include "../Inventory.h" #include "../World.h" -#include "../Simulator/FluidSimulator.h" #include "../Server.h" -#include "Player.h" #include "../Bindings/PluginManager.h" -#include "../Item.h" #include "../Root.h" #include "../Chunk.h" -#include "../Vector3d.h" -#include "../Vector3f.h" + + + +class cPickupCombiningCallback : + public cEntityCallback +{ +public: + cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) : + m_Position(a_Position), + m_Pickup(a_Pickup), + m_FoundMatchingPickup(false) + { + } + + virtual bool Item(cEntity * a_Entity) override + { + if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() == m_Pickup->GetUniqueID()) || a_Entity->IsDestroyed()) + { + return false; + } + + Vector3d EntityPos = a_Entity->GetPosition(); + double Distance = (EntityPos - m_Position).Length(); + + if ((Distance < 1.2) && ((cPickup *)a_Entity)->GetItem().IsEqual(m_Pickup->GetItem())) + { + m_Pickup->GetItem().AddCount(((cPickup *)a_Entity)->GetItem().m_ItemCount); + a_Entity->Destroy(); + m_FoundMatchingPickup = true; + } + return false; + } + + inline bool FoundMatchingPickup() + { + return m_FoundMatchingPickup; + } + +protected: + bool m_FoundMatchingPickup; + + Vector3d m_Position; + cPickup * m_Pickup; +}; @@ -26,10 +65,10 @@ cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */) : cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2) - , m_Timer( 0.f ) + , m_Timer(0.f) , m_Item(a_Item) - , m_bCollected( false ) - , m_bIsPlayerCreated( IsPlayerCreated ) + , m_bCollected(false) + , m_bIsPlayerCreated(IsPlayerCreated) { SetGravity(-10.5f); SetMaxHealth(5); @@ -89,6 +128,16 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk) return; } } + + if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me + { + cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); + m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries + if (PickupCombiningCallback.FoundMatchingPickup()) + { + m_World->BroadcastEntityMetadata(*this); + } + } } } } diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c1f2456eb..82e31ae65 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -7,7 +7,6 @@ #include "../UI/Window.h" #include "../UI/WindowOwner.h" #include "../World.h" -#include "Pickup.h" #include "../Bindings/PluginManager.h" #include "../BlockEntities/BlockEntity.h" #include "../GroupManager.h" @@ -27,8 +26,6 @@ #include "inifile/iniFile.h" #include "json/json.h" -#define float2int(x) ((x)<0 ? ((int)(x))-1 : (int)(x)) - @@ -36,8 +33,6 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) : super(etPlayer, 0.6, 1.8) - , m_AirLevel( MAX_AIR_LEVEL ) - , m_AirTickTimer(DROWNING_TICKS) , m_bVisible(true) , m_FoodLevel(MAX_FOOD_LEVEL) , m_FoodSaturationLevel(5) @@ -74,6 +69,7 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) , m_IsChargingBow(false) , m_BowCharge(0) , m_FloaterID(-1) + , m_Team(NULL) { LOGD("Created a player object for \"%s\" @ \"%s\" at %p, ID %d", a_PlayerName.c_str(), a_Client->GetIPString().c_str(), @@ -107,9 +103,23 @@ cPlayer::cPlayer(cClientHandle* a_Client, const AString & a_PlayerName) a_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ() ); } + m_LastJumpHeight = (float)(GetPosY()); m_LastGroundHeight = (float)(GetPosY()); m_Stance = GetPosY() + 1.62; + + if (m_GameMode == gmNotSet) + { + cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName()); + if (World == NULL) + { + World = cRoot::Get()->GetDefaultWorld(); + } + if (World->IsGameModeCreative()) + { + m_CanFly = true; + } + } cRoot::Get()->GetServer()->PlayerCreated(this); } @@ -196,12 +206,6 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) super::Tick(a_Dt, a_Chunk); - // Set player swimming state - SetSwimState(a_Chunk); - - // Handle air drowning stuff - HandleAir(); - // Handle charging the bow: if (m_IsChargingBow) { @@ -434,7 +438,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) cWorld * World = GetWorld(); if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height)) { - BLOCKTYPE BlockType = World->GetBlock(float2int(GetPosX()), float2int(GetPosY()), float2int(GetPosZ())); + BLOCKTYPE BlockType = World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())); if (BlockType != E_BLOCK_AIR) { m_bTouchGround = true; @@ -459,12 +463,10 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) if (Damage > 0) { - if (!IsGameModeCreative()) - { - TakeDamage(dtFalling, NULL, Damage, Damage, 0); - } + // cPlayer makes sure damage isn't applied in creative, no need to check here + TakeDamage(dtFalling, NULL, Damage, Damage, 0); - // Mojang uses floor() to get X and Z positions, instead of just casting it to an (int) + // Fall particles GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */); } @@ -786,10 +788,24 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) { if (IsGameModeCreative()) { - // No damage / health in creative mode + // No damage / health in creative mode if not void damage return; } } + + if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) + { + cPlayer* Attacker = (cPlayer*) a_TDI.Attacker; + + if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) + { + if (!m_Team->AllowsFriendlyFire()) + { + // Friendly fire is disabled + return; + } + } + } super::DoTakeDamage(a_TDI); @@ -836,6 +852,25 @@ void cPlayer::KilledBy(cEntity * a_Killer) GetWorld()->BroadcastChat(Printf("%s[DEATH] %s%s was killed by a %s", cChatColor::Red.c_str(), cChatColor::White.c_str(), GetName().c_str(), KillerClass.c_str())); } + + class cIncrementCounterCB + : public cObjectiveCallback + { + AString m_Name; + public: + cIncrementCounterCB(const AString & a_Name) : m_Name(a_Name) {} + + virtual bool Item(cObjective * a_Objective) override + { + a_Objective->AddScore(m_Name, 1); + return true; + } + } IncrementCounter (GetName()); + + cScoreboard & Scoreboard = m_World->GetScoreBoard(); + + // Update scoreboard objectives + Scoreboard.ForEachObjectiveWith(cObjective::E_TYPE_DEATH_COUNT, IncrementCounter); } @@ -916,6 +951,50 @@ bool cPlayer::IsGameModeAdventure(void) const +void cPlayer::SetTeam(cTeam * a_Team) +{ + if (m_Team == a_Team) + { + return; + } + + if (m_Team) + { + m_Team->RemovePlayer(GetName()); + } + + m_Team = a_Team; + + if (m_Team) + { + m_Team->AddPlayer(GetName()); + } +} + + + + + +cTeam * cPlayer::UpdateTeam(void) +{ + if (m_World == NULL) + { + SetTeam(NULL); + } + else + { + cScoreboard & Scoreboard = m_World->GetScoreBoard(); + + SetTeam(Scoreboard.QueryPlayerTeam(GetName())); + } + + return m_Team; +} + + + + + void cPlayer::OpenWindow(cWindow * a_Window) { if (a_Window != m_CurrentWindow) @@ -1342,59 +1421,68 @@ AString cPlayer::GetColor(void) const -void cPlayer::TossItem( - bool a_bDraggingItem, - char a_Amount /* = 1 */, - short a_CreateType /* = 0 */, - short a_CreateHealth /* = 0 */ -) +void cPlayer::TossEquippedItem(char a_Amount) { cItems Drops; - if (a_CreateType != 0) + cItem DroppedItem(GetInventory().GetEquippedItem()); + if (!DroppedItem.IsEmpty()) { - // Just create item without touching the inventory (used in creative mode) - Drops.push_back(cItem(a_CreateType, a_Amount, a_CreateHealth)); + char NewAmount = a_Amount; + if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount) + { + NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there + } + + GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount); + + DroppedItem.m_ItemCount = NewAmount; + Drops.push_back(DroppedItem); } - else + + double vX = 0, vY = 0, vZ = 0; + EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); + vY = -vY * 2 + 1.f; + m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player +} + + + + + +void cPlayer::TossHeldItem(char a_Amount) +{ + cItems Drops; + cItem & Item = GetDraggingItem(); + if (!Item.IsEmpty()) { - // Drop an item from the inventory: - if (a_bDraggingItem) + char OriginalItemAmount = Item.m_ItemCount; + Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount); + Drops.push_back(Item); + if (OriginalItemAmount > a_Amount) { - cItem & Item = GetDraggingItem(); - if (!Item.IsEmpty()) - { - char OriginalItemAmount = Item.m_ItemCount; - Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount); - Drops.push_back(Item); - if (OriginalItemAmount > a_Amount) - { - Item.m_ItemCount = OriginalItemAmount - (char)a_Amount; - } - else - { - Item.Empty(); - } - } + Item.m_ItemCount = OriginalItemAmount - a_Amount; } else { - // Else drop equipped item - cItem DroppedItem(GetInventory().GetEquippedItem()); - if (!DroppedItem.IsEmpty()) - { - char NewAmount = a_Amount; - if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount) - { - NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there - } - - GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount); - - DroppedItem.m_ItemCount = NewAmount; - Drops.push_back(DroppedItem); - } + Item.Empty(); } } + + double vX = 0, vY = 0, vZ = 0; + EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); + vY = -vY * 2 + 1.f; + m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player +} + + + + + +void cPlayer::TossPickup(const cItem & a_Item) +{ + cItems Drops; + Drops.push_back(a_Item); + double vX = 0, vY = 0, vZ = 0; EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; @@ -1543,27 +1631,12 @@ bool cPlayer::LoadFromDisk() m_CurrentXp = (short) root.get("xpCurrent", 0).asInt(); m_IsFlying = root.get("isflying", 0).asBool(); - //SetExperience(root.get("experience", 0).asInt()); - m_GameMode = (eGameMode) root.get("gamemode", eGameMode_NotSet).asInt(); if (m_GameMode == eGameMode_Creative) { m_CanFly = true; } - else if (m_GameMode == eGameMode_NotSet) - { - cWorld * World = cRoot::Get()->GetWorld(GetLoadedWorldName()); - if (World == NULL) - { - World = cRoot::Get()->GetDefaultWorld(); - } - - if (World->GetGameMode() == eGameMode_Creative) - { - m_CanFly = true; - } - } m_Inventory.LoadFromJson(root["inventory"]); @@ -1680,85 +1753,6 @@ void cPlayer::UseEquippedItem(void) -void cPlayer::SetSwimState(cChunk & a_Chunk) -{ - int RelY = (int)floor(m_LastPosY + 0.1); - if ((RelY < 0) || (RelY >= cChunkDef::Height - 1)) - { - m_IsSwimming = false; - m_IsSubmerged = false; - return; - } - - BLOCKTYPE BlockIn; - int RelX = (int)floor(m_LastPosX) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = (int)floor(m_LastPosZ) - a_Chunk.GetPosZ() * cChunkDef::Width; - - // Check if the player is swimming: - // Use Unbounded, because we're being called *after* processing super::Tick(), which could have changed our chunk - if (!a_Chunk.UnboundedRelGetBlockType(RelX, RelY, RelZ, BlockIn)) - { - // This sometimes happens on Linux machines - // Ref.: http://forum.mc-server.org/showthread.php?tid=1244 - LOGD("SetSwimState failure: RelX = %d, RelZ = %d, LastPos = {%.02f, %.02f}, Pos = %.02f, %.02f}", - RelX, RelY, m_LastPosX, m_LastPosZ, GetPosX(), GetPosZ() - ); - m_IsSwimming = false; - m_IsSubmerged = false; - return; - } - m_IsSwimming = IsBlockWater(BlockIn); - - // Check if the player is submerged: - VERIFY(a_Chunk.UnboundedRelGetBlockType(RelX, RelY + 1, RelZ, BlockIn)); - m_IsSubmerged = IsBlockWater(BlockIn); -} - - - - - -void cPlayer::HandleAir(void) -{ - // Ref.: http://www.minecraftwiki.net/wiki/Chunk_format - // see if the player is /submerged/ water (block above is water) - // Get the type of block the player's standing in: - - if (IsSubmerged()) - { - // either reduce air level or damage player - if (m_AirLevel < 1) - { - if (m_AirTickTimer < 1) - { - // damage player - TakeDamage(dtDrowning, NULL, 1, 1, 0); - // reset timer - m_AirTickTimer = DROWNING_TICKS; - } - else - { - m_AirTickTimer -= 1; - } - } - else - { - // reduce air supply - m_AirLevel -= 1; - } - } - else - { - // set the air back to maximum - m_AirLevel = MAX_AIR_LEVEL; - m_AirTickTimer = DROWNING_TICKS; - } -} - - - - - void cPlayer::HandleFood(void) { // Ref.: http://www.minecraftwiki.net/wiki/Hunger diff --git a/src/Entities/Player.h b/src/Entities/Player.h index bf3ca08e8..50f7560d6 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -13,6 +13,7 @@ class cGroup; class cWindow; class cClientHandle; +class cTeam; @@ -30,8 +31,6 @@ public: MAX_HEALTH = 20, MAX_FOOD_LEVEL = 20, EATING_TICKS = 30, ///< Number of ticks it takes to eat an item - MAX_AIR_LEVEL = 300, - DROWNING_TICKS = 10, //number of ticks per heart of damage } ; // tolua_end @@ -153,6 +152,15 @@ public: AString GetIP(void) const { return m_IP; } // tolua_export + /// Returns the associated team, NULL if none + cTeam * GetTeam(void) { return m_Team; } // tolua_export + + /// Sets the player team, NULL if none + void SetTeam(cTeam * a_Team); + + /// Forces the player to query the scoreboard for his team + cTeam * UpdateTeam(void); + // tolua_end void SetIP(const AString & a_IP); @@ -214,7 +222,14 @@ public: /// Returns the full color code to use for this player, based on their primary group or set in m_Color AString GetColor(void) const; - void TossItem(bool a_bDraggingItem, char a_Amount = 1, short a_CreateType = 0, short a_CreateHealth = 0); + /** tosses the item in the selected hotbar slot */ + void TossEquippedItem(char a_Amount = 1); + + /** tosses the item held in hand (when in UI windows) */ + void TossHeldItem(char a_Amount = 1); + + /** tosses a pickup newly created from a_Item */ + void TossPickup(const cItem & a_Item); /// Heals the player by the specified amount of HPs (positive only); sends health update void Heal(int a_Health); @@ -224,8 +239,6 @@ public: int GetFoodTickTimer (void) const { return m_FoodTickTimer; } double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; } - - int GetAirLevel (void) const { return m_AirLevel; } /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); } @@ -336,12 +349,6 @@ public: /// If true the player can fly even when he's not in creative. void SetCanFly(bool a_CanFly); - /// 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; } - /// Returns wheter the player can fly or not. virtual bool CanFly(void) const { return m_CanFly; } // tolua_end @@ -372,12 +379,6 @@ protected: XP_TO_LEVEL30 = 825 } ; - /// Player's air level (for swimming) - int m_AirLevel; - - /// used to time ticks between damage taken via drowning/suffocation - int m_AirTickTimer; - bool m_bVisible; // Food-related variables: @@ -414,7 +415,7 @@ protected: float m_LastBlockActionTime; int m_LastBlockActionCnt; eGameMode m_GameMode; - std::string m_IP; + AString m_IP; /// The item being dragged by the cursor while in a UI window cItem m_DraggingItem; @@ -456,6 +457,8 @@ protected: int m_FloaterID; + cTeam* m_Team; + void ResolvePermissions(void); @@ -463,7 +466,7 @@ protected: virtual void Destroyed(void); - /// Filters out damage for creative mode + /// Filters out damage for creative mode/friendly fire virtual void DoTakeDamage(TakeDamageInfo & TDI) override; /// Called in each tick to handle food-related processing @@ -471,12 +474,6 @@ protected: /// Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. void HandleFloater(void); - - /// Called in each tick to handle air-related processing i.e. drowning - 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) void ApplyFoodExhaustionFromMovement(); |