Further work on the achievement system

Implemented ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT
Fixed SMSG_CRITERIA_UPDATE structure
Implemented parts of ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL - there are still some unknown additional conditions for this criteria type
Fixed sAchievementStore lookup errors caused by an invalid DBCfmt
This commit is contained in:
arrai 2008-10-28 00:06:52 +01:00
parent 6496f7499e
commit deccb566ae
7 changed files with 138 additions and 18 deletions

View file

@ -20,6 +20,8 @@
#include "Common.h"
#include "Player.h"
#include "WorldPacket.h"
#include "Database/DBCEnums.h"
#include "ObjectMgr.h"
AchievementMgr::AchievementMgr(Player *player)
{
@ -38,6 +40,7 @@ void AchievementMgr::LoadFromDB()
void AchievementMgr::SendAchievementEarned(uint32 achievementId)
{
sLog.outString("AchievementMgr::SendAchievementEarned(%u)", achievementId);
WorldPacket data(SMSG_MESSAGECHAT, 200);
data << uint8(CHAT_MSG_ACHIEVEMENT);
data << uint32(LANG_UNIVERSAL);
@ -60,13 +63,114 @@ void AchievementMgr::SendAchievementEarned(uint32 achievementId)
void AchievementMgr::SendCriteriaUpdate(uint32 criteriaId, uint32 counter)
{
sLog.outString("AchievementMgr::SendCriteriaUpdate(%u, %u)", criteriaId, counter);
WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8);
data << uint32(criteriaId);
data << uint8(counter);
data << uint8(counter);// 2 times?
// the counter is packed like a packed Guid
data.appendPackGUID(counter);
data.append(GetPlayer()->GetPackGUID());
data << uint64(0x0000000); // unknown, same as in SMSG_EARNED_ACHIEVEMENT, static for every player?
data << uint32(0); // unknown, 0
/*
data << uint32(counter);
data << uint32(counter+1);//timer1
data << uint32(counter+2);//timer2
*/
data << uint32(0);
data << uint32(0);
data << uint32(0);
data << uint32(0);
GetPlayer()->SendMessageToSet(&data, true);
}
/**
* this function will be called whenever the user might have done a criteria relevant action
*/
void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, uint32 time)
{
sLog.outString("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time);
AchievementCriteriaEntryList const& achievementCriteriaList = objmgr.GetAchievementCriteriaByType(type);
for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
{
AchievementCriteriaEntry const *achievementCriteria = (*i);
switch (type)
{
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
SetCriteriaProgress(achievementCriteria, miscvalue1);
break;
default:
return;
}
if(IsCompletedCriteria(achievementCriteria))
CompletedCriteria(achievementCriteria);
}
}
bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria)
{
AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
if(!achievement)
return false;
// counter can never complete
if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
return false;
switch(achievementCriteria->requiredType)
{
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
return m_criteriaProgress[achievementCriteria->ID] >= achievementCriteria->reach_level.level;
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
return m_criteriaProgress[achievementCriteria->ID] >= achievementCriteria->buy_bank_slot.numberOfSlots;
}
return false;
}
void AchievementMgr::CompletedCriteria(AchievementCriteriaEntry const* criteria)
{
AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->referredAchievement);
if(!achievement)
return;
// counter can never complete
if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
return;
if(criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL)
{
CompletedAchievement(achievement);
return;
}
// Check if there are also other critiera which have to be fulfilled for that achievement
for (uint32 entryId = 0; entryId<sAchievementCriteriaStore.GetNumRows(); entryId++)
{
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
if(!criteria || criteria->referredAchievement!= achievement->ID)
continue;
// found an outstanding criteria, return
if(!IsCompletedCriteria(criteria))
return;
}
CompletedAchievement(achievement);
}
void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 newValue)
{
sLog.outString("AchievementMgr::SetCriteriaProgress(%u, %u)", entry->ID, newValue);
m_criteriaProgress[entry->ID] = newValue;
SendCriteriaUpdate(entry->ID, newValue);
}
void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
{
sLog.outString("AchievementMgr::CompletedAchievement(%u)", achievement->ID);
if(achievement->flags & ACHIEVEMENT_FLAG_COUNTER || m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end())
return;
SendAchievementEarned(achievement->ID);
m_completedAchievements.insert(achievement->ID);
// TODO: reward titles and items
}

View file

@ -18,7 +18,14 @@
#ifndef __MANGOS_ACHIEVEMENTMGR_H
#define __MANGOS_ACHIEVEMENTMGR_H
#include "Player.h"
#include "Common.h"
#include "Database/DBCEnums.h"
#include "Database/DBCStores.h"
typedef HM_NAMESPACE::hash_map<uint32, uint32> CriteriaProgressMap;
typedef std::set<uint32> CompletedAchievementSet;
class Player;
class AchievementMgr
{
@ -27,13 +34,22 @@ class AchievementMgr
void LoadFromDB();
void SaveToDB();
void SendAchievementEarned(uint32 achievementId);
void SendCriteriaUpdate(uint32 criteriaId, uint32 counter);
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, uint32 time=0);
Player* GetPlayer() { return m_player;}
private:
void SendAchievementEarned(uint32 achievementId);
void SendCriteriaUpdate(uint32 criteriaId, uint32 counter);
void SetCriteriaProgress(AchievementCriteriaEntry const* entry, uint32 newValue);
void CompletedCriteria(AchievementCriteriaEntry const* entry);
void CompletedAchievement(AchievementEntry const* entry);
bool IsCompletedCriteria(AchievementCriteriaEntry const* entry);
Player* m_player;
CriteriaProgressMap m_criteriaProgress;
CompletedAchievementSet m_completedAchievements;
};

View file

@ -805,6 +805,7 @@ void WorldSession::HandleBuyBankSlotOpcode(WorldPacket& /*recvPacket*/)
if (_player->GetMoney() < price)
return;
_player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT, slot);
_player->SetByteValue(PLAYER_BYTES_2, 2, slot);
_player->ModifyMoney(-int32(price));
}

View file

@ -744,6 +744,7 @@ class ObjectMgr
bool RemoveVendorItem(uint32 entry,uint32 item);
bool IsVendorItemValid( uint32 vendor_entry, uint32 item, uint32 maxcount, uint32 ptime, uint32 ExtendedCost, Player* pl = NULL, std::set<uint32>* skip_vendors = NULL ) const;
void LoadAchievementCriteriaList();
AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type);
protected:
uint32 m_auctionid;
@ -810,7 +811,6 @@ class ObjectMgr
int DBCLocaleIndex;
AchievementCriteriaEntryList const& GetAchievementCriteriaByType(AchievementCriteriaTypes type);
private:
void LoadScripts(ScriptMapMap& scripts, char const* tablename);
void ConvertCreatureAddonAuras(CreatureDataAddon* addon, char const* table, char const* guidEntryStr);

View file

@ -246,7 +246,7 @@ const int32 Player::ReputationRank_Length[MAX_REPUTATION_RANK] = {36000, 3000, 3
UpdateMask Player::updateVisualBits;
Player::Player (WorldSession *session): Unit()
Player::Player (WorldSession *session): Unit(), m_achievementMgr(this)
{
m_transport = 0;
@ -421,7 +421,6 @@ Player::Player (WorldSession *session): Unit()
m_contestedPvPTimer = 0;
m_declinedname = NULL;
m_achievementMgr = NULL;
}
Player::~Player ()
@ -468,7 +467,6 @@ Player::~Player ()
itr->second.save->RemovePlayer(this);
delete m_declinedname;
delete m_achievementMgr;
}
void Player::CleanupsBeforeDelete()
@ -2146,6 +2144,7 @@ void Player::GiveLevel(uint32 level)
Pet* pet = GetPet();
if(pet && pet->getPetType()==SUMMON_PET)
pet->GivePetLevel(level);
GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL, level);
}
void Player::InitTalentForLevel()
@ -13974,8 +13973,7 @@ bool Player::LoadFromDB( uint32 guid, SqlQueryHolder *holder )
m_social = sSocialMgr.LoadFromDB(holder->GetResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow());
m_achievementMgr = new AchievementMgr(this);
m_achievementMgr->LoadFromDB();
m_achievementMgr.LoadFromDB();
if(!_LoadHomeBind(holder->GetResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
return false;
@ -15196,7 +15194,7 @@ void Player::SaveToDB()
// save pet (hunter pet level and experience and all type pets health/mana).
if(Pet* pet = GetPet())
pet->SavePetToDB(PET_SAVE_AS_CURRENT);
m_achievementMgr->SaveToDB();
m_achievementMgr.SaveToDB();
}
// fast save function for item/money cheating preventing - save only inventory and money state

View file

@ -32,6 +32,7 @@
#include "WorldSession.h"
#include "Pet.h"
#include "Util.h" // for Tokens typedef
#include "AchievementMgr.h"
#include<string>
#include<vector>
@ -2055,7 +2056,7 @@ class MANGOS_DLL_SPEC Player : public Unit
DeclinedName const* GetDeclinedNames() const { return m_declinedname; }
AchievementMgr *GetAchievementMgr() { return m_achievementMgr; }
AchievementMgr& GetAchievementMgr() { return m_achievementMgr; }
protected:
/*********************************************************/
@ -2286,7 +2287,7 @@ class MANGOS_DLL_SPEC Player : public Unit
WorldLocation m_teleport_dest;
DeclinedName *m_declinedname;
AchievementMgr *m_achievementMgr;
AchievementMgr m_achievementMgr;
private:
// internal common parts for CanStore/StoreItem functions
uint8 _CanStoreItem_InSpecificSlot( uint8 bag, uint8 slot, ItemPosCountVec& dest, ItemPrototype const *pProto, uint32& count, bool swap, Item *pSrcItem ) const;

View file

@ -16,8 +16,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
const char Achievementfmt[]="iiixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixxixxxxxxxxxxxxxxxxxxx";
const char AchievementCriteriafmt[]="iiiiiiiiixxxxxxxxxxxxxxxxxiixix";
const char Achievementfmt[]="niixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxiixxixxxxxxxxxxxxxxxxxxx";
const char AchievementCriteriafmt[]="niiiiiiiixxxxxxxxxxxxxxxxxiixix";
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
const char AreaTriggerEntryfmt[]="niffffffff";
const char BankBagSlotPricesEntryfmt[]="ni";