From c7c3724a3ee0e7a77fe9924ad25c36b6ec8fdd14 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 11 May 2014 14:57:06 +0300 Subject: Statistic Manager --- src/Entities/Player.cpp | 21 +++++++++++++++++++-- src/Entities/Player.h | 7 +++++++ 2 files changed, 26 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 6ac11c270..a42fe89cf 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -16,6 +16,8 @@ #include "../Items/ItemHandler.h" #include "../Vector3.h" +#include "../WorldStorage/StatSerializer.h" + #include "inifile/iniFile.h" #include "json/json.h" @@ -131,6 +133,15 @@ cPlayer::~cPlayer(void) SaveToDisk(); +#if 0 + /* Save statistics. */ + cStatSerializer StatSerializer(m_World->GetName(), m_PlayerName, &m_Stats); + if (!StatSerializer.Save()) + { + LOGERROR("Could not save stats for player %s", m_PlayerName.c_str()); + } +#endif + m_World->RemovePlayer( this ); m_ClientHandle = NULL; @@ -871,9 +882,13 @@ void cPlayer::KilledBy(cEntity * a_Killer) } else if (a_Killer->IsPlayer()) { - GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str())); + cPlayer* Killer = (cPlayer*)a_Killer; - m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1); + GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str())); + + Killer->GetStatManager().AddValue(statPlayerKills); + + m_World->GetScoreBoard().AddPlayerScore(Killer->GetName(), cObjective::otPlayerKillCount, 1); } else { @@ -883,6 +898,8 @@ void cPlayer::KilledBy(cEntity * a_Killer) GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str())); } + m_Stats.AddValue(statDeaths); + m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1); } diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 6fc7e2875..82a138290 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -7,6 +7,8 @@ #include "../World.h" #include "../ClientHandle.h" +#include "../Statistics.h" + @@ -174,6 +176,9 @@ public: cTeam * UpdateTeam(void); // tolua_end + + /** Return the associated statistic and achievement manager. */ + cStatManager & GetStatManager() { return m_Stats; } void SetIP(const AString & a_IP); @@ -487,6 +492,8 @@ protected: cTeam * m_Team; + cStatManager m_Stats; + void ResolvePermissions(void); -- cgit v1.2.3 From e3c6c8f3ddffdc368ebbc1a7688de2ca1b97167c Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 11 May 2014 20:30:54 +0300 Subject: Fixed stat serialization --- src/Entities/Player.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index a42fe89cf..1df473eb2 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -133,15 +133,6 @@ cPlayer::~cPlayer(void) SaveToDisk(); -#if 0 - /* Save statistics. */ - cStatSerializer StatSerializer(m_World->GetName(), m_PlayerName, &m_Stats); - if (!StatSerializer.Save()) - { - LOGERROR("Could not save stats for player %s", m_PlayerName.c_str()); - } -#endif - m_World->RemovePlayer( this ); m_ClientHandle = NULL; @@ -1638,6 +1629,12 @@ bool cPlayer::LoadFromDisk() m_Inventory.LoadFromJson(root["inventory"]); m_LoadedWorldName = root.get("world", "world").asString(); + + /* Load the player stats. + * We use the default world name (like bukkit) because stats are shared between dimensions/worlds. + */ + cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); + StatSerializer.Load(); LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"", m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str() @@ -1709,6 +1706,17 @@ bool cPlayer::SaveToDisk() LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str()); return false; } + + /* Save the player stats. + * We use the default world name (like bukkit) because stats are shared between dimensions/worlds. + */ + cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), m_PlayerName, &m_Stats); + if (!StatSerializer.Save()) + { + LOGERROR("Could not save stats for player %s", m_PlayerName.c_str()); + return false; + } + return true; } @@ -1723,7 +1731,10 @@ cPlayer::StringList cPlayer::GetResolvedPermissions() const PermissionMap& ResolvedPermissions = m_ResolvedPermissions; for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr ) { - if( itr->second ) Permissions.push_back( itr->first ); + if (itr->second) + { + Permissions.push_back( itr->first ); + } } return Permissions; -- cgit v1.2.3 From 6cb348395468020ebac978d5a4968953e49d8b90 Mon Sep 17 00:00:00 2001 From: andrew Date: Sun, 11 May 2014 21:41:25 +0300 Subject: Fixed compilation --- src/Entities/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/Entities') diff --git a/src/Entities/CMakeLists.txt b/src/Entities/CMakeLists.txt index c9ca44d38..205cb2cca 100644 --- a/src/Entities/CMakeLists.txt +++ b/src/Entities/CMakeLists.txt @@ -10,3 +10,5 @@ file(GLOB SOURCE ) add_library(Entities ${SOURCE}) + +target_link_libraries(Entities WorldStorage) -- cgit v1.2.3 From b3d2b5b2c94193fd9364b26293b7d96b748ff96d Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 12 May 2014 17:05:09 +0300 Subject: cEntity::Killed(cEntity *) Handler; Achievement triggers; cPlayer::AwardAchievement() --- src/Entities/Entity.cpp | 5 ++++ src/Entities/Entity.h | 3 +++ src/Entities/Pickup.cpp | 10 +++++++ src/Entities/Player.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- src/Entities/Player.h | 11 ++++++++ 5 files changed, 95 insertions(+), 4 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4cf10a219..9eb03acde 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -370,6 +370,11 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) if (m_Health <= 0) { KilledBy(a_TDI.Attacker); + + if (a_TDI.Attacker != NULL) + { + a_TDI.Attacker->Killed(this); + } } return true; } diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index df03d635b..a111b128d 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -299,6 +299,9 @@ public: /// Called when the health drops below zero. a_Killer may be NULL (environmental damage) virtual void KilledBy(cEntity * a_Killer); + /// Called when the entity kills another entity + virtual void Killed(cEntity * a_Victim) {} + /// Heals the specified amount of HPs void Heal(int a_HitPoints); diff --git a/src/Entities/Pickup.cpp b/src/Entities/Pickup.cpp index 497b41683..0fd006485 100644 --- a/src/Entities/Pickup.cpp +++ b/src/Entities/Pickup.cpp @@ -192,6 +192,16 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) int NumAdded = a_Dest->GetInventory().AddItem(m_Item); if (NumAdded > 0) { + // Check achievements + switch (m_Item.m_ItemType) + { + case E_BLOCK_LOG: a_Dest->AwardAchievement(achMineWood); break; + case E_ITEM_LEATHER: a_Dest->AwardAchievement(achKillCow); break; + case E_ITEM_DIAMOND: a_Dest->AwardAchievement(achDiamonds); break; + case E_ITEM_BLAZE_ROD: a_Dest->AwardAchievement(achBlazeRod); break; + default: break; + } + m_Item.m_ItemCount -= NumAdded; m_World->BroadcastCollectPickup(*this, *a_Dest); // Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;) diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 1df473eb2..48bb509b9 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -17,6 +17,7 @@ #include "../Vector3.h" #include "../WorldStorage/StatSerializer.h" +#include "../CompositeChat.h" #include "inifile/iniFile.h" #include "json/json.h" @@ -876,10 +877,6 @@ void cPlayer::KilledBy(cEntity * a_Killer) cPlayer* Killer = (cPlayer*)a_Killer; GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str())); - - Killer->GetStatManager().AddValue(statPlayerKills); - - m_World->GetScoreBoard().AddPlayerScore(Killer->GetName(), cObjective::otPlayerKillCount, 1); } else { @@ -898,6 +895,33 @@ void cPlayer::KilledBy(cEntity * a_Killer) +void cPlayer::Killed(cEntity * a_Victim) +{ + cScoreboard & ScoreBoard = m_World->GetScoreBoard(); + + if (a_Victim->IsPlayer()) + { + m_Stats.AddValue(statPlayerKills); + + ScoreBoard.AddPlayerScore(GetName(), cObjective::otPlayerKillCount, 1); + } + else if (a_Victim->IsMob()) + { + if (((cMonster *)a_Victim)->GetMobFamily() == cMonster::mfHostile) + { + AwardAchievement(achKillMonster); + } + + m_Stats.AddValue(statMobKills); + } + + ScoreBoard.AddPlayerScore(GetName(), cObjective::otTotalKillCount, 1); +} + + + + + void cPlayer::Respawn(void) { m_Health = GetMaxHealth(); @@ -1116,6 +1140,44 @@ void cPlayer::SetIP(const AString & a_IP) +unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) +{ + eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach); + + if (Prerequisite != statInvalid) + { + if (m_Stats.GetValue(Prerequisite) == 0) + { + return 0; + } + } + + StatValue Old = m_Stats.GetValue(a_Ach); + + if (Old > 0) + { + return m_Stats.AddValue(a_Ach); + } + else + { + cCompositeChat Msg; + Msg.AddTextPart(m_PlayerName + " has just earned the achievement "); + Msg.AddTextPart(cStatInfo::GetName(a_Ach)); // TODO 2014-05-12 xdot: Use the proper cCompositeChat submessage type and send the actual title + m_World->BroadcastChat(Msg); + + StatValue New = m_Stats.AddValue(a_Ach); + + /* Achievement Get! */ + m_ClientHandle->SendStatistics(m_Stats); + + return New; + } +} + + + + + void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) { SetPosition(a_PosX, a_PosY, a_PosZ); diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 82a138290..b5c9d75cc 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -179,6 +179,15 @@ public: /** Return the associated statistic and achievement manager. */ cStatManager & GetStatManager() { return m_Stats; } + + /** Awards the player an achievement. + * + * If all prerequisites are met, this method will award the achievement and will broadcast a chat message. + * If the achievement has been already awarded to the player, this method will just increment the stat counter. + * + * Returns the _new_ stat value. (0 = Could not award achievement) + */ + unsigned int AwardAchievement(const eStatistic a_Ach); void SetIP(const AString & a_IP); @@ -311,6 +320,8 @@ public: void AbortEating(void); virtual void KilledBy(cEntity * a_Killer) override; + + virtual void Killed(cEntity * a_Victim) override; void Respawn(void); // tolua_export -- cgit v1.2.3 From aea866f5b10d5ab0226260b4d25c70b1cfd31d2a Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 12 May 2014 21:38:52 +0300 Subject: Movement Statistics --- src/Entities/Entity.cpp | 15 +++++++-- src/Entities/Player.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++------ src/Entities/Player.h | 6 ++++ 3 files changed, 96 insertions(+), 11 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 9eb03acde..c393f89fd 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -312,12 +312,16 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) { + cPlayer * Player = (cPlayer *)a_TDI.Attacker; + // IsOnGround() only is false if the player is moving downwards - if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) + if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain) { a_TDI.FinalDamage += 2; m_World->BroadcastEntityAnimation(*this, 4); // Critical hit } + + Player->GetStatManager().AddValue(statDamageDealt, round(a_TDI.FinalDamage * 10)); } m_Health -= (short)a_TDI.FinalDamage; @@ -580,9 +584,16 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) if (m_AttachedTo != NULL) { - if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5) + Vector3d DeltaPos = m_Pos - m_AttachedTo->GetPosition(); + if (DeltaPos.Length() > 0.5) { SetPosition(m_AttachedTo->GetPosition()); + + if (IsPlayer()) + { + cPlayer * Player = (cPlayer *)this; + Player->UpdateMovementStats(DeltaPos); + } } } else diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 48bb509b9..3df7c4c34 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -194,6 +194,8 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk) return; } } + + m_Stats.AddValue(statMinutesPlayed, 1); if (!a_Chunk.IsValid()) { @@ -835,6 +837,8 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) // Any kind of damage adds food exhaustion AddFoodExhaustion(0.3f); SendHealth(); + + m_Stats.AddValue(statDamageTaken, round(a_TDI.FinalDamage * 10)); return true; } return false; @@ -865,6 +869,8 @@ void cPlayer::KilledBy(cEntity * a_Killer) Pickups.Add(cItem(E_ITEM_RED_APPLE)); } + m_Stats.AddValue(statItemsDropped, Pickups.Size()); + m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10); SaveToDisk(); // Save it, yeah the world is a tough place ! @@ -1262,6 +1268,9 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos ) // TODO: should do some checks to see if player is not moving through terrain // TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too + + Vector3d DeltaPos = a_NewPos - GetPosition(); + UpdateMovementStats(DeltaPos); SetPosition( a_NewPos ); SetStance(a_NewPos.y + 1.62); @@ -1492,10 +1501,7 @@ void cPlayer::TossEquippedItem(char a_Amount) Drops.push_back(DroppedItem); } - 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 + TossItems(Drops); } @@ -1511,6 +1517,7 @@ void cPlayer::TossHeldItem(char a_Amount) 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 - a_Amount; @@ -1521,10 +1528,7 @@ void cPlayer::TossHeldItem(char a_Amount) } } - 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 + TossItems(Drops); } @@ -1536,10 +1540,21 @@ void cPlayer::TossPickup(const cItem & a_Item) cItems Drops; Drops.push_back(a_Item); + TossItems(Drops); +} + + + + + +void cPlayer::TossItems(const cItems & a_Items) +{ + m_Stats.AddValue(statItemsDropped, a_Items.Size()); + 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 + m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player } @@ -1935,6 +1950,59 @@ void cPlayer::HandleFloater() +void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) +{ + StatValue Value = round(a_DeltaPos.Length() * 100); + + if (m_AttachedTo == NULL) + { + int PosX = POSX_TOINT; + int PosY = POSY_TOINT; + int PosZ = POSZ_TOINT; + + BLOCKTYPE Block; + NIBBLETYPE Meta; + if (!m_World->GetBlockTypeMeta(PosX, PosY, PosZ, Block, Meta)) + { + return; + } + + if ((Block == E_BLOCK_LADDER) && (a_DeltaPos.y > 0.0)) // Going up + { + m_Stats.AddValue(statDistClimbed, round(a_DeltaPos.y * 100)); + } + else + { + // TODO 2014-05-12 xdot: Other types + m_Stats.AddValue(statDistWalked, Value); + } + } + else + { + switch (m_AttachedTo->GetEntityType()) + { + case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break; + case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break; + case cEntity::etMonster: + { + cMonster * Monster = (cMonster *)m_AttachedTo; + switch (Monster->GetMobType()) + { + case cMonster::mtPig: m_Stats.AddValue(statDistPig, Value); break; + case cMonster::mtHorse: m_Stats.AddValue(statDistHorse, Value); break; + default: break; + } + break; + } + default: break; + } + } +} + + + + + void cPlayer::ApplyFoodExhaustionFromMovement() { if (IsGameModeCreative()) diff --git a/src/Entities/Player.h b/src/Entities/Player.h index b5c9d75cc..3de5e9c68 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -391,6 +391,9 @@ public: /** If true the player can fly even when he's not in creative. */ void SetCanFly(bool a_CanFly); + /** Update movement-related statistics. */ + void UpdateMovementStats(const Vector3d & a_DeltaPos); + /** Returns wheter the player can fly or not. */ virtual bool CanFly(void) const { return m_CanFly; } // tolua_end @@ -524,6 +527,9 @@ 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); + /** Tosses a list of items. */ + void TossItems(const cItems & a_Items); + /** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */ void ApplyFoodExhaustionFromMovement(); -- cgit v1.2.3 From 466ff2204f18fda5f4f0f0b3e19f671d57747c24 Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 13 May 2014 14:53:15 +0300 Subject: Fixes --- src/Entities/Player.cpp | 21 +++++++++++---------- src/Entities/Player.h | 9 +++------ 2 files changed, 14 insertions(+), 16 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 3df7c4c34..632c41936 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -820,7 +820,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer())) { - cPlayer* Attacker = (cPlayer*) a_TDI.Attacker; + cPlayer * Attacker = (cPlayer *)a_TDI.Attacker; if ((m_Team != NULL) && (m_Team == Attacker->m_Team)) { @@ -880,7 +880,7 @@ void cPlayer::KilledBy(cEntity * a_Killer) } else if (a_Killer->IsPlayer()) { - cPlayer* Killer = (cPlayer*)a_Killer; + cPlayer * Killer = (cPlayer *)a_Killer; GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str())); } @@ -1150,6 +1150,7 @@ unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) { eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach); + // Check if the prerequisites are met if (Prerequisite != statInvalid) { if (m_Stats.GetValue(Prerequisite) == 0) @@ -1166,14 +1167,16 @@ unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach) } else { + // First time, announce it cCompositeChat Msg; Msg.AddTextPart(m_PlayerName + " has just earned the achievement "); - Msg.AddTextPart(cStatInfo::GetName(a_Ach)); // TODO 2014-05-12 xdot: Use the proper cCompositeChat submessage type and send the actual title + Msg.AddTextPart(cStatInfo::GetName(a_Ach)); // TODO 2014-05-12 xdot: Use the proper cCompositeChat part (cAchievement) m_World->BroadcastChat(Msg); + // Increment the statistic StatValue New = m_Stats.AddValue(a_Ach); - /* Achievement Get! */ + // Achievement Get! m_ClientHandle->SendStatistics(m_Stats); return New; @@ -1707,9 +1710,8 @@ bool cPlayer::LoadFromDisk() m_LoadedWorldName = root.get("world", "world").asString(); - /* Load the player stats. - * We use the default world name (like bukkit) because stats are shared between dimensions/worlds. - */ + // Load the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats); StatSerializer.Load(); @@ -1784,9 +1786,8 @@ bool cPlayer::SaveToDisk() return false; } - /* Save the player stats. - * We use the default world name (like bukkit) because stats are shared between dimensions/worlds. - */ + // Save the player stats. + // We use the default world name (like bukkit) because stats are shared between dimensions/worlds. cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), m_PlayerName, &m_Stats); if (!StatSerializer.Save()) { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 3de5e9c68..78b534d83 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -181,12 +181,9 @@ public: cStatManager & GetStatManager() { return m_Stats; } /** Awards the player an achievement. - * - * If all prerequisites are met, this method will award the achievement and will broadcast a chat message. - * If the achievement has been already awarded to the player, this method will just increment the stat counter. - * - * Returns the _new_ stat value. (0 = Could not award achievement) - */ + If all prerequisites are met, this method will award the achievement and will broadcast a chat message. + If the achievement has been already awarded to the player, this method will just increment the stat counter. + Returns the _new_ stat value. (0 = Could not award achievement) */ unsigned int AwardAchievement(const eStatistic a_Ach); void SetIP(const AString & a_IP); -- cgit v1.2.3 From a651c865e40ad80b52ddf69004b40a580e7069ea Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sun, 18 May 2014 22:49:27 +0200 Subject: There's no "round" function in MSVC2008. --- src/Entities/Entity.cpp | 2 +- src/Entities/Player.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index c393f89fd..31ad66779 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -321,7 +321,7 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI) m_World->BroadcastEntityAnimation(*this, 4); // Critical hit } - Player->GetStatManager().AddValue(statDamageDealt, round(a_TDI.FinalDamage * 10)); + Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); } m_Health -= (short)a_TDI.FinalDamage; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 632c41936..c3b763278 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -838,7 +838,7 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI) AddFoodExhaustion(0.3f); SendHealth(); - m_Stats.AddValue(statDamageTaken, round(a_TDI.FinalDamage * 10)); + m_Stats.AddValue(statDamageTaken, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5)); return true; } return false; @@ -1953,7 +1953,7 @@ void cPlayer::HandleFloater() void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) { - StatValue Value = round(a_DeltaPos.Length() * 100); + StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5); if (m_AttachedTo == NULL) { @@ -1970,7 +1970,7 @@ void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) if ((Block == E_BLOCK_LADDER) && (a_DeltaPos.y > 0.0)) // Going up { - m_Stats.AddValue(statDistClimbed, round(a_DeltaPos.y * 100)); + m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5)); } else { -- cgit v1.2.3 From 6167c79e7a822cb14431985a82f4cc5b463e556f Mon Sep 17 00:00:00 2001 From: Tiger Wang Date: Sun, 18 May 2014 22:41:42 +0100 Subject: Implemented cacti damage + Implemented cacti damage * Fixed pickup tossing (PR #994 bug) --- src/Entities/Entity.cpp | 23 +++++++++++++++++++++++ src/Entities/Entity.h | 3 +++ 2 files changed, 26 insertions(+) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 4cf10a219..b7cb2c3d9 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -601,6 +601,10 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk) m_TicksSinceLastVoidDamage = 0; } + if (IsMob() || IsPlayer() || IsPickup() || IsExpOrb()) + { + DetectCacti(); + } if (IsMob() || IsPlayer()) { // Set swimming state @@ -998,6 +1002,25 @@ void cEntity::TickInVoid(cChunk & a_Chunk) +void cEntity::DetectCacti() +{ + int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; + if ( + ((X + 1) - GetPosX() < 0.3) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS) || + ((GetPosX() - (X - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS) || + ((Z + 1) - GetPosZ() < 0.3) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS) || + ((GetPosZ() - (Z - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS) || + (((Y > 0) && (Y < cChunkDef::Height)) && ((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS))) + ) + { + TakeDamage(dtCactus, NULL, 1, 0); + } +} + + + + + void cEntity::SetSwimState(cChunk & a_Chunk) { int RelY = (int)floor(GetPosY() + 0.1); diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h index df03d635b..d5e7cf5c1 100644 --- a/src/Entities/Entity.h +++ b/src/Entities/Entity.h @@ -317,6 +317,9 @@ public: /// Updates the state related to this entity being on fire virtual void TickBurning(cChunk & a_Chunk); + + /** Detects the time for application of cacti damage */ + virtual void DetectCacti(void); /// Handles when the entity is in the void virtual void TickInVoid(cChunk & a_Chunk); -- cgit v1.2.3 From 70cf4a5eafaf91f9b6d0b71f607270b7df86e6d9 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 19 May 2014 07:31:53 +0100 Subject: Fixed clanging errors. Please @tigerw make sure this is correct. --- src/Entities/Entity.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index b7cb2c3d9..1a91639ac 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1006,14 +1006,14 @@ void cEntity::DetectCacti() { int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; if ( - ((X + 1) - GetPosX() < 0.3) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS) || - ((GetPosX() - (X - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS) || - ((Z + 1) - GetPosZ() < 0.3) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS) || - ((GetPosZ() - (Z - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS) || + (((X + 1) - GetPosX() < 0.3) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || + (((GetPosX() - (X - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || + (((Z + 1) - GetPosZ() < 0.3) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS)) || + (((GetPosZ() - (Z - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS)) || (((Y > 0) && (Y < cChunkDef::Height)) && ((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS))) ) { - TakeDamage(dtCactus, NULL, 1, 0); + TakeDamage(dtCactusContact, NULL, 1, 0); } } -- cgit v1.2.3 From dc39d88d3f5951479084c1ea4d51079015777f01 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 19 May 2014 10:35:21 +0100 Subject: Should have fixed assumptions about entity width. @madmaxoft can you comment? --- src/Entities/Entity.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 1a91639ac..71b9f63a7 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1005,11 +1005,12 @@ void cEntity::TickInVoid(cChunk & a_Chunk) void cEntity::DetectCacti() { int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; + float w = m_Width / 2 if ( - (((X + 1) - GetPosX() < 0.3) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || - (((GetPosX() - (X - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || - (((Z + 1) - GetPosZ() < 0.3) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS)) || - (((GetPosZ() - (Z - 1)) - 1 < 0.3) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS)) || + (((X + 1) - GetPosX() < w) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || + (((GetPosX() - (X - 1)) - 1 < w) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || + (((Z + 1) - GetPosZ() < w) && (GetWorld()->GetBlock(X, Y, Z + 1) == E_BLOCK_CACTUS)) || + (((GetPosZ() - (Z - 1)) - 1 < w) && (GetWorld()->GetBlock(X, Y, Z - 1) == E_BLOCK_CACTUS)) || (((Y > 0) && (Y < cChunkDef::Height)) && ((GetPosY() - Y < 1) && (GetWorld()->GetBlock(X, Y, Z) == E_BLOCK_CACTUS))) ) { -- cgit v1.2.3 From 6de0257bbe1f0c676e9cc1401298f08b96b54e73 Mon Sep 17 00:00:00 2001 From: Alexander Harkness Date: Mon, 19 May 2014 13:31:19 +0100 Subject: Derp --- src/Entities/Entity.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 71b9f63a7..aa671bf35 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1005,7 +1005,7 @@ void cEntity::TickInVoid(cChunk & a_Chunk) void cEntity::DetectCacti() { int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; - float w = m_Width / 2 + float w = m_Width / 2; if ( (((X + 1) - GetPosX() < w) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || (((GetPosX() - (X - 1)) - 1 < w) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || -- cgit v1.2.3 From 07baf9bdd3b04e3aec6e77f367eb38c0547f54ca Mon Sep 17 00:00:00 2001 From: andrew Date: Tue, 20 May 2014 15:52:59 +0300 Subject: Cleaned up cPlayer::UpdateMovementStats; Wither achievements --- src/Entities/Player.cpp | 71 +++++++++++++++++++++++++++++++++++++++---------- src/Entities/Player.h | 3 +++ 2 files changed, 60 insertions(+), 14 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index c3b763278..0eacb67f9 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -456,8 +456,18 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) else { float Dist = (float)(m_LastGroundHeight - floor(GetPosY())); + + if (Dist >= 2.0) // At least two blocks - TODO: Use m_LastJumpHeight instead of m_LastGroundHeight above + { + // Increment statistic + m_Stats.AddValue(statDistFallen, (StatValue)floor(Dist * 100 + 0.5)); + } + int Damage = (int)(Dist - 3.f); - if (m_LastJumpHeight > m_LastGroundHeight) Damage++; + if (m_LastJumpHeight > m_LastGroundHeight) + { + Damage++; + } m_LastJumpHeight = (float)GetPosY(); if (Damage > 0) @@ -1951,32 +1961,65 @@ void cPlayer::HandleFloater() +bool cPlayer::IsClimbing(void) const +{ + int PosX = POSX_TOINT; + int PosY = POSY_TOINT; + int PosZ = POSZ_TOINT; + + if ((PosY < 0) || (PosY >= cChunkDef::Height)) + { + return false; + } + + BLOCKTYPE Block = m_World->GetBlock(PosX, PosY, PosZ); + switch (Block) + { + case E_BLOCK_LADDER: + case E_BLOCK_VINES: + { + return true; + } + default: return false; + } +} + + + + + void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos) { StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5); if (m_AttachedTo == NULL) { - int PosX = POSX_TOINT; - int PosY = POSY_TOINT; - int PosZ = POSZ_TOINT; - - BLOCKTYPE Block; - NIBBLETYPE Meta; - if (!m_World->GetBlockTypeMeta(PosX, PosY, PosZ, Block, Meta)) + if (IsClimbing()) { - return; + if (a_DeltaPos.y > 0.0) // Going up + { + m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5)); + } } - - if ((Block == E_BLOCK_LADDER) && (a_DeltaPos.y > 0.0)) // Going up + else if (IsSubmerged()) { - m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5)); + m_Stats.AddValue(statDistDove, Value); } - else + else if (IsSwimming()) + { + m_Stats.AddValue(statDistSwum, Value); + } + else if (IsOnGround()) { - // TODO 2014-05-12 xdot: Other types m_Stats.AddValue(statDistWalked, Value); } + else + { + if (Value >= 25) // Ignore small/slow movement + { + m_Stats.AddValue(statDistFlown, Value); + } + } } else { diff --git a/src/Entities/Player.h b/src/Entities/Player.h index 78b534d83..b7cb27d6c 100644 --- a/src/Entities/Player.h +++ b/src/Entities/Player.h @@ -127,6 +127,9 @@ public: inline const cItem & GetEquippedItem(void) const { return GetInventory().GetEquippedItem(); } // tolua_export + /** Returns whether the player is climbing (ladders, vines e.t.c). */ + bool IsClimbing(void) const; + virtual void TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ) override; // tolua_begin -- cgit v1.2.3 From 941cb88ae456f0d8b91f6b5dc835c2536eef15f6 Mon Sep 17 00:00:00 2001 From: Mattes D Date: Fri, 23 May 2014 12:33:30 +0200 Subject: Fixed datatype conversion warning. --- src/Entities/Entity.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Entities') diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp index 15f456332..2567b7adc 100644 --- a/src/Entities/Entity.cpp +++ b/src/Entities/Entity.cpp @@ -1018,10 +1018,10 @@ void cEntity::TickInVoid(cChunk & a_Chunk) -void cEntity::DetectCacti() +void cEntity::DetectCacti(void) { int X = POSX_TOINT, Y = POSY_TOINT, Z = POSZ_TOINT; - float w = m_Width / 2; + double w = m_Width / 2; if ( (((X + 1) - GetPosX() < w) && (GetWorld()->GetBlock(X + 1, Y, Z) == E_BLOCK_CACTUS)) || (((GetPosX() - (X - 1)) - 1 < w) && (GetWorld()->GetBlock(X - 1, Y, Z) == E_BLOCK_CACTUS)) || -- cgit v1.2.3