aboutsummaryrefslogtreecommitdiff
path: root/src/game/AchievementMgr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/game/AchievementMgr.cpp')
-rw-r--r--src/game/AchievementMgr.cpp373
1 files changed, 262 insertions, 111 deletions
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp
index 44df14bf15b..c4a634c15c0 100644
--- a/src/game/AchievementMgr.cpp
+++ b/src/game/AchievementMgr.cpp
@@ -27,8 +27,13 @@
#include "GameEvent.h"
#include "World.h"
#include "SpellMgr.h"
+#include "ProgressBar.h"
-const CriteriaCastSpellRequirement AchievementMgr::criteriaCastSpellRequirements[CRITERIA_CAST_SPELL_REQ_COUNT] =
+#include "Policies/SingletonImp.h"
+
+INSTANTIATE_SINGLETON_1(AchievementGlobalMgr);
+
+const CriteriaCastSpellRequirement AchievementGlobalMgr::m_criteriaCastSpellRequirements[CRITERIA_CAST_SPELL_REQ_COUNT] =
{
{5272, 3057, 0, 0},
{5273, 2784, 0, 0},
@@ -76,68 +81,6 @@ const CriteriaCastSpellRequirement AchievementMgr::criteriaCastSpellRequirements
{6320, 0, CLASS_PALADIN, RACE_DRAENEI},
{6321, 0, CLASS_HUNTER, RACE_DWARF},
{6662, 31261, 0, 0}
- };
-
-const AchievementReward AchievementMgr::achievementRewards[ACHIEVEMENT_REWARD_COUNT] =
- {
- // achievementId, horde titleid, alliance titleid, itemid
- {45, 0, 0, 43348},
- {46, 78, 78, 0},
- {230, 72, 72, 0},
- {456, 139, 139, 0},
- {614, 0, 0, 44223},
- {619, 0, 0, 44224},
- {714, 47, 47, 0},
- {762, 130, 130, 0},
- {870, 127, 126, 0},
- {871, 144, 144, 0},
- {876, 0, 0, 43349},
- {907, 48, 48, 0},
- {913, 74, 74, 0},
- {942, 79, 79, 0},
- {943, 79, 79, 0},
- {945, 131, 131, 0},
- {948, 130, 130, 0},
- {953, 132, 132, 0},
- {978, 81, 81, 0},
- {1015, 77, 77, 0},
- {1021, 0, 0, 40643},
- {1038, 75, 75, 0},
- {1039, 76, 76, 0},
- {1163, 128, 128, 0},
- {1174, 82, 82, 0},
- {1175, 72, 72, 0},
- {1250, 0, 0, 40653},
- {1400, 120, 120, 0},
- {1402, 122, 122, 0},
- {1516, 83, 83, 0},
- {1563, 84, 84, 0},
- {1656, 124, 124, 0},
- {1657, 124, 124, 0},
- {1658, 129, 129, 0},
- {1681, 125, 125, 43300},
- {1682, 125, 125, 43300},
- {1683, 133, 133, 0},
- {1684, 133, 133, 0},
- {1691, 134, 134, 0},
- {1692, 134, 134, 0},
- {1693, 135, 135, 0},
- {1707, 135, 135, 0},
- {1784, 84, 84, 0},
- {1793, 137, 137, 0},
- {1956, 0, 0, 43824},
- {2051, 140, 140, 0},
- {2054, 121, 121, 0},
- {2096, 0, 0, 44430},
- {2136, 0, 0, 0},// <- TODO: find item for spell 59961
- {2137, 0, 0, 0},// <- TODO: find item for spell 60021
- {2138, 0, 0, 0},// <- TODO: find item for spell 59976
- {2143, 0, 0, 44178},
- {2144, 0, 0, 0},// <- TODO: find item for spell 60024
- {2145, 0, 0, 0},// <- TODO: find item for spell 60024
- {2186, 141, 141, 0},
- {2187, 142, 142, 0},
- {2188, 143, 143, 0}
};
AchievementMgr::AchievementMgr(Player *player)
@@ -364,7 +307,7 @@ void AchievementMgr::CheckAllAchievementCriteria()
void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1, uint32 miscvalue2, Unit *unit, uint32 time)
{
sLog.outDetail("AchievementMgr::UpdateAchievementCriteria(%u, %u, %u, %u)", type, miscvalue1, miscvalue2, time);
- AchievementCriteriaEntryList const& achievementCriteriaList = objmgr.GetAchievementCriteriaByType(type);
+ AchievementCriteriaEntryList const& achievementCriteriaList = achievementmgr.GetAchievementCriteriaByType(type);
for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
{
AchievementCriteriaEntry const *achievementCriteria = (*i);
@@ -523,19 +466,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
{
if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID)
continue;
- // those requirements couldn't be found in the dbc
- const CriteriaCastSpellRequirement *requirement = NULL;
- for (uint32 i=0; i<CRITERIA_CAST_SPELL_REQ_COUNT; i++)
- {
- if (criteriaCastSpellRequirements[i].achievementCriteriaId == achievementCriteria->ID)
- {
- requirement = &criteriaCastSpellRequirements[i];
- break;
- }
- }
-
- if (requirement)
+ // those requirements couldn't be found in the dbc
+ if (CriteriaCastSpellRequirement const* requirement = AchievementGlobalMgr::GetCriteriaCastSpellRequirement(achievementCriteria))
{
if (!unit)
continue;
@@ -549,6 +482,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
if (requirement->playerClass && (unit->GetTypeId() != TYPEID_PLAYER || unit->getClass()!=requirement->playerClass))
continue;
}
+
SetCriteriaProgress(achievementCriteria, 1, true);
break;
}
@@ -653,7 +587,7 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve
if(achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
{
// someone on this realm has already completed that achievement
- if(objmgr.allCompletedAchievements.find(achievement->ID)!=objmgr.allCompletedAchievements.end())
+ if(achievementmgr.IsRealmCompleted(achievement))
return false;
}
@@ -838,55 +772,58 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
// don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement
// TODO: where do set this instead?
if(!(achievement->flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL))
- objmgr.allCompletedAchievements.insert(achievement->ID);
+ achievementmgr.SetRealmCompleted(achievement);
UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT);
- // reward items and titles
- // TODO: rewards should be send by mail
- AchievementReward const* reward = NULL;
- for (uint32 i=0; i<ACHIEVEMENT_REWARD_COUNT; i++)
- {
- if (achievementRewards[i].achievementId == achievement->ID)
- {
- reward = &achievementRewards[i];
- break;
- }
- }
+ // reward items and titles if any
+ AchievementReward const* reward = achievementmgr.GetAchievementReward(achievement);
+
+ // no rewards
+ if(!reward)
+ return;
- if (reward)
+ // titles
+ if(uint32 titleId = reward->titleId[GetPlayer()->GetTeam() == HORDE?0:1])
{
- uint32 titleId = reward->titleId[GetPlayer()->GetTeam() == HORDE?0:1];
if(CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
GetPlayer()->SetTitle(titleEntry);
+ }
- if (reward->itemId)
+ // mail
+ if(reward->sender)
+ {
+ Item* item = reward->itemId ? Item::CreateItem(reward->itemId,1,GetPlayer ()) : NULL;
+
+ MailItemsInfo mi;
+ if(item)
{
- ItemPrototype const *pProto = objmgr.GetItemPrototype( reward->itemId );
+ // save new item before send
+ item->SaveToDB(); // save for prevent lost at next mail load, if send fail then item will deleted
- if(!pProto)
- {
- GetPlayer()->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
- return;
- }
+ // item
+ mi.AddItem(item->GetGUIDLow(), item->GetEntry(), item);
+ }
- ItemPosCountVec dest;
- uint32 no_space = 0;
- uint8 msg = GetPlayer()->CanStoreNewItem( NULL_BAG, NULL_SLOT, dest, reward->itemId, 1, &no_space );
+ int loc_idx = GetPlayer()->GetSession()->GetSessionDbLocaleIndex();
- if( msg != EQUIP_ERR_OK )
- {
- GetPlayer()->SendEquipError( msg, NULL, NULL );
- return;
- }
- Item* pItem = GetPlayer()->StoreNewItem( dest, reward->itemId, true);
-
- if(!pItem)
+ // subject and text
+ std::string subject = reward->subject;
+ std::string text = reward->text;
+ if ( loc_idx >= 0 )
+ {
+ if(AchievementRewardLocale const* loc = achievementmgr.GetAchievementRewardLocale(achievement))
{
- GetPlayer()->SendEquipError( EQUIP_ERR_ITEM_NOT_FOUND, NULL, NULL );
- return;
+ if (loc->subject.size() > size_t(loc_idx) && !loc->subject[loc_idx].empty())
+ subject = loc->subject[loc_idx];
+ if (loc->text.size() > size_t(loc_idx) && !loc->text[loc_idx].empty())
+ text = loc->text[loc_idx];
}
}
+
+ uint32 itemTextId = objmgr.CreateItemText( text );
+
+ WorldSession::SendMailTo(GetPlayer(), MAIL_CREATURE, MAIL_STATIONERY_NORMAL, reward->sender, GetPlayer()->GetGUIDLow(), subject, itemTextId , &mi, 0, 0, MAIL_CHECK_MASK_NONE);
}
}
@@ -932,3 +869,217 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket *data)
*data << int32(-1);
}
+
+//==========================================================
+AchievementCriteriaEntryList const& AchievementGlobalMgr::GetAchievementCriteriaByType(AchievementCriteriaTypes type)
+{
+ return m_AchievementCriteriasByType[type];
+}
+
+void AchievementGlobalMgr::LoadAchievementCriteriaList()
+{
+ for (uint32 entryId = 0; entryId<sAchievementCriteriaStore.GetNumRows(); entryId++)
+ {
+ AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
+ if(!criteria)
+ continue;
+
+ m_AchievementCriteriasByType[criteria->requiredType].push_back(criteria);
+ }
+}
+
+
+void AchievementGlobalMgr::LoadCompletedAchievements()
+{
+ QueryResult *result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
+
+ if(!result)
+ return;
+
+ do
+ {
+ Field *fields = result->Fetch();
+ m_allCompletedAchievements.insert(fields[0].GetUInt32());
+ } while(result->NextRow());
+
+ delete result;
+}
+
+void AchievementGlobalMgr::LoadRewards()
+{
+ m_achievementRewards.clear(); // need for reload case
+
+ // 0 1 2 3 4 5 6
+ QueryResult *result = WorldDatabase.Query("SELECT entry, title_A, title_H, item, sender, subject, text FROM achievement_reward");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 achievement rewards. DB table `achievement_reward` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+ if (!sAchievementStore.LookupEntry(entry))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` has wrong achievement (Entry: %u), ignore", entry);
+ continue;
+ }
+
+ AchievementReward reward;
+ reward.titleId[0] = fields[1].GetUInt32();
+ reward.titleId[1] = fields[2].GetUInt32();
+ reward.itemId = fields[3].GetUInt32();
+ reward.sender = fields[4].GetUInt32();
+ reward.subject = fields[5].GetCppString();
+ reward.text = fields[6].GetCppString();
+
+ if ((reward.titleId[0]==0)!=(reward.titleId[1]==0))
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has title (A: %u H: %u) only for one from teams.", entry, reward.titleId[0], reward.titleId[1]);
+
+ // must be title or mail at least
+ if (!reward.titleId[0] && !reward.titleId[1] && !reward.sender)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have title or item reward data, ignore.", entry);
+ continue;
+ }
+
+ if (reward.titleId[0])
+ {
+ CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[0]);
+ if (!titleEntry)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[0]);
+ reward.titleId[0] = 0;
+ }
+ }
+
+ if (reward.titleId[1])
+ {
+ CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.titleId[1]);
+ if (!titleEntry)
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0", entry, reward.titleId[1]);
+ reward.titleId[1] = 0;
+ }
+ }
+
+ //check mail data before item for report including wrong item case
+ if (reward.sender)
+ {
+ if (!objmgr.GetCreatureTemplate(reward.sender))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid creature entry %u as sender, mail reward skipped.", entry, reward.sender);
+ reward.sender = 0;
+ }
+ }
+ else
+ {
+ if (reward.itemId)
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have item reward, item will not rewarded", entry);
+
+ if (!reward.subject.empty())
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have mail subject.", entry);
+
+ if (!reward.text.empty())
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) not have sender data but have mail text.", entry);
+ }
+
+ if (reward.itemId)
+ {
+ if (!objmgr.GetItemPrototype(reward.itemId))
+ {
+ sLog.outErrorDb( "Table `achievement_reward` (Entry: %u) has invalid item id %u, reward mail will be without item.", entry, reward.itemId);
+ reward.itemId = 0;
+ }
+ }
+
+ m_achievementRewards[entry] = reward;
+
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u achievement reward locale strings", m_achievementRewardLocales.size() );
+}
+
+void AchievementGlobalMgr::LoadRewardLocales()
+{
+ m_achievementRewardLocales.clear(); // need for reload case
+
+ QueryResult *result = WorldDatabase.Query("SELECT entry,subject_loc1,text_loc1,subject_loc2,text_loc2,subject_loc3,text_loc3,subject_loc4,text_loc4,subject_loc5,text_loc5,subject_loc6,text_loc6,subject_loc7,text_loc7,subject_loc8,text_loc8 FROM locales_achievement_reward");
+
+ if(!result)
+ {
+ barGoLink bar(1);
+
+ bar.step();
+
+ sLog.outString("");
+ sLog.outString(">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty.");
+ return;
+ }
+
+ barGoLink bar(result->GetRowCount());
+
+ do
+ {
+ Field *fields = result->Fetch();
+ bar.step();
+
+ uint32 entry = fields[0].GetUInt32();
+
+ if(m_achievementRewards.find(entry)==m_achievementRewards.end())
+ {
+ sLog.outErrorDb( "Table `locales_achievement_reward` (Entry: %u) has locale strings for not existed achievement reward .", entry);
+ continue;
+ }
+
+ AchievementRewardLocale& data = m_achievementRewardLocales[entry];
+
+ for(int i = 1; i < MAX_LOCALE; ++i)
+ {
+ std::string str = fields[1+2*(i-1)].GetCppString();
+ if(!str.empty())
+ {
+ int idx = objmgr.GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.subject.size() <= idx)
+ data.subject.resize(idx+1);
+
+ data.subject[idx] = str;
+ }
+ }
+ str = fields[1+2*(i-1)+1].GetCppString();
+ if(!str.empty())
+ {
+ int idx = objmgr.GetOrNewIndexForLocale(LocaleConstant(i));
+ if(idx >= 0)
+ {
+ if(data.text.size() <= idx)
+ data.text.resize(idx+1);
+
+ data.text[idx] = str;
+ }
+ }
+ }
+ } while (result->NextRow());
+
+ delete result;
+
+ sLog.outString();
+ sLog.outString( ">> Loaded %u achievement reward locale strings", m_achievementRewardLocales.size() );
+}