1
0
Fork 0

cEntity::Killed(cEntity *) Handler; Achievement triggers; cPlayer::AwardAchievement()

This commit is contained in:
andrew 2014-05-12 17:05:09 +03:00
parent 6cb3483954
commit b3d2b5b2c9
8 changed files with 143 additions and 10 deletions

View File

@ -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;
}

View File

@ -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);

View File

@ -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 ;)

View File

@ -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);

View File

@ -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

View File

@ -1879,11 +1879,7 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
case 2:
{
// Open Inventory achievement
cStatManager & Manager = m_Client->GetPlayer()->GetStatManager();
Manager.AddValue(achOpenInv);
SendStatistics(Manager);
m_Client->GetPlayer()->AwardAchievement(achOpenInv);
break;
}
}

View File

@ -496,6 +496,8 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
DraggingItem = Result;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
HandleCraftItem(Result, a_Player);
}
else if (DraggingItem.IsEqual(Result))
{
@ -505,6 +507,8 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
DraggingItem.m_ItemCount += Result.m_ItemCount;
Recipe.ConsumeIngredients(Grid);
Grid.CopyToItems(PlayerSlots);
HandleCraftItem(Result, a_Player);
}
}
@ -594,6 +598,27 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Player)
{
switch (a_Result.m_ItemType)
{
case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(achCraftWorkbench); break;
case E_BLOCK_FURNACE: a_Player.AwardAchievement(achCraftFurnace); break;
case E_BLOCK_CAKE: a_Player.AwardAchievement(achBakeCake); break;
case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(achCraftEnchantTable); break;
case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(achBookshelf); break;
case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(achCraftPickaxe); break;
case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(achCraftSword); break;
case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(achCraftBetterPick); break;
case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(achCraftHoe); break;
case E_ITEM_BREAD: a_Player.AwardAchievement(achMakeBread); break;
default: break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaAnvil:
@ -1393,7 +1418,7 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
{
// Something has changed in the window, broadcast the entire window to all clients
ASSERT(a_ItemGrid == &(m_Furnace->GetContents()));
m_ParentWindow.BroadcastWholeWindow();
}
@ -1401,6 +1426,21 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player)
{
/** TODO 2014-05-12 xdot: Figure out when to call this method. */
switch (a_Result.m_ItemType)
{
case E_ITEM_IRON: a_Player.AwardAchievement(achAcquireIron); break;
case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(achCookFish); break;
default: break;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cSlotAreaInventoryBase:

View File

@ -254,6 +254,9 @@ protected:
/// Retrieves the recipe for the specified player from the map, or creates one if not found
cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player);
/// Called after an item has been crafted to handle statistics e.t.c.
void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player);
} ;
@ -397,6 +400,9 @@ protected:
// cItemGrid::cListener overrides:
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
/// Called after an item has been smelted to handle statistics e.t.c.
void HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player);
} ;