diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index 170e1a8c4..c490c9dd8 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -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; entryIdreferredAchievement!= 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 +} + diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index 7e7b6ccf2..a374b7d7c 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -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 CriteriaProgressMap; +typedef std::set 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; + }; diff --git a/src/game/ItemHandler.cpp b/src/game/ItemHandler.cpp index 46855179f..3a6083b0d 100644 --- a/src/game/ItemHandler.cpp +++ b/src/game/ItemHandler.cpp @@ -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)); } diff --git a/src/game/ObjectMgr.h b/src/game/ObjectMgr.h index bdf15399a..b75918419 100644 --- a/src/game/ObjectMgr.h +++ b/src/game/ObjectMgr.h @@ -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* 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); diff --git a/src/game/Player.cpp b/src/game/Player.cpp index a7811759c..da02a58e5 100644 --- a/src/game/Player.cpp +++ b/src/game/Player.cpp @@ -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 diff --git a/src/game/Player.h b/src/game/Player.h index 4d6c883e0..c94242cbb 100644 --- a/src/game/Player.h +++ b/src/game/Player.h @@ -32,6 +32,7 @@ #include "WorldSession.h" #include "Pet.h" #include "Util.h" // for Tokens typedef +#include "AchievementMgr.h" #include #include @@ -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; diff --git a/src/shared/Database/DBCfmt.cpp b/src/shared/Database/DBCfmt.cpp index 2bb6375a1..a4738330c 100644 --- a/src/shared/Database/DBCfmt.cpp +++ b/src/shared/Database/DBCfmt.cpp @@ -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";