TrinityCore
Loading...
Searching...
No Matches
AchievementMgr.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "AchievementMgr.h"
19#include "AchievementPackets.h"
20#include "ArenaTeamMgr.h"
21#include "Battleground.h"
22#include "CellImpl.h"
23#include "ChatTextBuilder.h"
24#include "DatabaseEnv.h"
25#include "DBCEnums.h"
26#include "DisableMgr.h"
27#include "GameEventMgr.h"
28#include "GameTime.h"
29#include "GridNotifiersImpl.h"
30#include "Guild.h"
31#include "GuildMgr.h"
32#include "InstanceScript.h"
33#include "Item.h"
34#include "Language.h"
35#include "Log.h"
36#include "Mail.h"
37#include "Map.h"
38#include "MapManager.h"
39#include "ObjectMgr.h"
40#include "Player.h"
41#include "RBAC.h"
42#include "ReputationMgr.h"
43#include "ScriptMgr.h"
44#include "SpellInfo.h"
45#include "SpellMgr.h"
46#include "World.h"
47#include "WorldSession.h"
48#include "WowTime.h"
49
51{
53 {
54 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` for criteria (Entry: {}) contains a wrong data type ({}), ignored.", criteria->ID, dataType);
55 return false;
56 }
57
58 switch (criteria->Type)
59 {
65 case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list
80 case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements
81 case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements
87 break;
88 default:
90 {
91 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for a non-supported criteria type (Entry: {} Type: {}), ignored.", criteria->ID, criteria->Type);
92 return false;
93 }
94 break;
95 }
96
97 switch (dataType)
98 {
102 return true;
104 if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id))
105 {
106 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE ({}) contains a non-existing creature id in value1 ({}), ignored.",
107 criteria->ID, criteria->Type, dataType, creature.id);
108 return false;
109 }
110 return true;
112 if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
113 {
114 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE ({}) contains a non-existing class in value1 ({}), ignored.",
115 criteria->ID, criteria->Type, dataType, classRace.class_id);
116 return false;
117 }
118 if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
119 {
120 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE ({}) contains a non-existing race in value2 ({}), ignored.",
121 criteria->ID, criteria->Type, dataType, classRace.race_id);
122 return false;
123 }
124 return true;
126 if (health.percent < 1 || health.percent > 100)
127 {
128 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH ({}) contains a wrong percent value in value1 ({}), ignored.",
129 criteria->ID, criteria->Type, dataType, health.percent);
130 return false;
131 }
132 return true;
134 if (player_dead.own_team_flag > 1)
135 {
136 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD ({}) contains a wrong boolean value1 ({}).",
137 criteria->ID, criteria->Type, dataType, player_dead.own_team_flag);
138 return false;
139 }
140 return true;
143 {
144 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(aura.spell_id);
145 if (!spellEntry)
146 {
147 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a wrong spell id in value1 ({}), ignored.",
148 criteria->ID, criteria->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id);
149 return false;
150 }
151 if (aura.effect_idx >= 3)
152 {
153 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a wrong spell effect index in value2 ({}), ignored.",
154 criteria->ID, criteria->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.effect_idx);
155 return false;
156 }
157 if (!spellEntry->GetEffect(SpellEffIndex(aura.effect_idx)).ApplyAuraName)
158 {
159 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a non-aura spell effect (ID: {} Effect: {}), ignored.",
160 criteria->ID, criteria->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA?"ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA":"ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA"), dataType, aura.spell_id, aura.effect_idx);
161 return false;
162 }
163 return true;
164 }
166 if (!sAreaTableStore.LookupEntry(area.id))
167 {
168 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA ({}) contains a wrong area id in value1 ({}), ignored.",
169 criteria->ID, criteria->Type, dataType, area.id);
170 return false;
171 }
172 return true;
174 if (value.compType >= COMP_TYPE_MAX)
175 {
176 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE ({}) contains a wrong ComparisionType in value2 ({}), ignored.",
177 criteria->ID, criteria->Type, dataType, value.compType);
178 return false;
179 }
180 return true;
182 if (level.minlevel > STRONG_MAX_LEVEL)
183 {
184 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL ({}) contains a wrong minlevel in value1 ({}), ignored.",
185 criteria->ID, criteria->Type, dataType, level.minlevel);
186 return false;
187 }
188 return true;
190 if (gender.gender > GENDER_NONE)
191 {
192 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER ({}) contains a wrong gender value in value1 ({}), ignored.",
193 criteria->ID, criteria->Type, dataType, gender.gender);
194 return false;
195 }
196 return true;
198 if (!ScriptId)
199 {
200 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT ({}) does not have a ScriptName set, ignored.",
201 criteria->ID, criteria->Type, dataType);
202 return false;
203 }
204 return true;
206 if (difficulty.difficulty >= MAX_DIFFICULTY)
207 {
208 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY ({}) contains a wrong difficulty value in value1 ({}), ignored.",
209 criteria->ID, criteria->Type, dataType, difficulty.difficulty);
210 return false;
211 }
212 return true;
214 if (map_players.maxcount <= 0)
215 {
216 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT ({}) contains a wrong max players count in value1 ({}), ignored.",
217 criteria->ID, criteria->Type, dataType, map_players.maxcount);
218 return false;
219 }
220 return true;
222 if (team.team != ALLIANCE && team.team != HORDE)
223 {
224 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM ({}) contains an unknown team value in value1 ({}), ignored.",
225 criteria->ID, criteria->Type, dataType, team.team);
226 return false;
227 }
228 return true;
230 if (drunk.state >= MAX_DRUNKEN)
231 {
232 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK ({}) contains an unknown drunken state value in value1 ({}), ignored.",
233 criteria->ID, criteria->Type, dataType, drunk.state);
234 return false;
235 }
236 return true;
238 if (!sHolidaysStore.LookupEntry(holiday.id))
239 {
240 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY ({}) contains an unknown holiday entry in value1 ({}), ignored.",
241 criteria->ID, criteria->Type, dataType, holiday.id);
242 return false;
243 }
244 return true;
246 {
247 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
248 if (game_event.id < 1 || game_event.id >= events.size())
249 {
250 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT ({}) has unknown game_event in value1 ({}), ignored.",
251 criteria->ID, criteria->Type, dataType, game_event.id);
252 return false;
253 }
254 return true;
255 }
257 return true; // not check correctness node indexes
260 if (equipped_item.item_quality >= MAX_ITEM_QUALITY)
261 {
262 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains an unknown quality state value in value1 ({}), ignored.",
263 criteria->ID, criteria->Type, (dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY"), dataType, equipped_item.item_quality);
264 return false;
265 }
266 return true;
268 if (!sMapStore.LookupEntry(map_id.mapId))
269 {
270 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID ({}) contains an unknown map id in value1 ({}), ignored.",
271 criteria->ID, criteria->Type, dataType, map_id.mapId);
272 return false;
273 }
274 return true;
276 if (!classRace.class_id && !classRace.race_id)
277 {
278 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE ({}) should not have 0 in either value field. Ignored.",
279 criteria->ID, criteria->Type, dataType);
280 return false;
281 }
282 if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
283 {
284 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE ({}) contains a non-existing class entry in value1 ({}), ignored.",
285 criteria->ID, criteria->Type, dataType, classRace.class_id);
286 return false;
287 }
288 if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
289 {
290 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE ({}) contains a non-existing race entry in value2 ({}), ignored.",
291 criteria->ID, criteria->Type, dataType, classRace.race_id);
292 return false;
293 }
294 return true;
296 if (!sCharTitlesStore.LookupEntry(known_title.title_id))
297 {
298 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE ({}) contains an unknown title_id in value1 ({}), ignore.",
299 criteria->ID, criteria->Type, dataType, known_title.title_id);
300 return false;
301 }
302 return true;
303 default:
304 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) contains data of a non-supported data type ({}), ignored.", criteria->ID, criteria->Type, dataType);
305 return false;
306 }
307}
308
309bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
310{
311 switch (dataType)
312 {
314 return true;
316 if (!target || target->GetTypeId() != TYPEID_UNIT)
317 return false;
318 return target->GetEntry() == creature.id;
320 if (!target || target->GetTypeId() != TYPEID_PLAYER)
321 return false;
322 if (classRace.class_id && classRace.class_id != target->ToPlayer()->GetClass())
323 return false;
324 if (classRace.race_id && classRace.race_id != target->ToPlayer()->GetRace())
325 return false;
326 return true;
328 if (source->GetTypeId() != TYPEID_PLAYER)
329 return false;
330 if (classRace.class_id && classRace.class_id != source->ToPlayer()->GetClass())
331 return false;
332 if (classRace.race_id && classRace.race_id != source->ToPlayer()->GetRace())
333 return false;
334 return true;
336 if (!target || target->GetTypeId() != TYPEID_PLAYER)
337 return false;
338 return !target->ToPlayer()->HealthAbovePct(health.percent);
340 if (!target || target->GetTypeId() != TYPEID_PLAYER)
341 return false;
342 if (Player const* player = target->ToPlayer())
343 if (!player->IsAlive() && player->GetDeathTimer() != 0)
344 // flag set == must be same team, not set == different team
345 return (player->GetTeam() == source->GetTeam()) == (player_dead.own_team_flag != 0);
346 return false;
348 return source->HasAuraEffect(aura.spell_id, aura.effect_idx);
350 {
351 uint32 zone_id, area_id;
352 source->GetZoneAndAreaId(zone_id, area_id);
353 return area.id == zone_id || area.id == area_id;
354 }
356 {
357 if (!target)
358 return false;
359 Unit const* unitTarget = target->ToUnit();
360 if (!unitTarget)
361 return false;
362 return unitTarget->HasAuraEffect(aura.spell_id, aura.effect_idx);
363 }
365 return CompareValues(ComparisionType(value.compType), miscValue1, value.value);
367 {
368 if (!target)
369 return false;
370 Unit const* unitTarget = target->ToUnit();
371 if (!unitTarget)
372 return false;
373 return unitTarget->GetLevel() >= level.minlevel;
374 }
376 {
377 if (!target)
378 return false;
379 Unit const* unitTarget = target->ToUnit();
380 if (!unitTarget)
381 return false;
382 return unitTarget->GetGender() == static_cast<::Gender>(gender.gender);
383 }
385 {
386 Unit const* unitTarget = nullptr;
387 if (target)
388 unitTarget = target->ToUnit();
389 return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(unitTarget));
390 }
392 if (source->GetMap()->IsRaid())
393 {
394 bool requires25ManRaid = difficulty.difficulty == RAID_DIFFICULTY_25MAN_NORMAL || difficulty.difficulty == RAID_DIFFICULTY_25MAN_HEROIC;
395 if (source->GetMap()->Is25ManRaid() != requires25ManRaid)
396 return false;
397 }
398 return source->GetMap()->GetSpawnMode() >= difficulty.difficulty;
400 return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
402 if (!target || target->GetTypeId() != TYPEID_PLAYER)
403 return false;
404 return target->ToPlayer()->GetTeam() == team.team;
410 return IsEventActive(game_event.id);
412 {
413 Battleground* bg = source->GetBattleground();
414 if (!bg)
415 return false;
416
418 return score >= bg_loss_team_score.min_score && score <= bg_loss_team_score.max_score;
419 }
421 {
422 if (!source->IsInWorld())
423 return false;
424 Map* map = source->GetMap();
425 if (!map->IsDungeon())
426 {
427 TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT ({}) for achievement criteria {} in a non-dungeon/non-raid map {}",
428 dataType, criteria_id, map->GetId());
429 return false;
430 }
431 InstanceScript* instance = map->ToInstanceMap()->GetInstanceScript();
432 if (!instance)
433 {
434 TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT ({}) for achievement criteria {} in map {}, but the map does not have an instance script.",
435 dataType, criteria_id, map->GetId());
436 return false;
437 }
438
439 Unit const* unitTarget = nullptr;
440 if (target)
441 unitTarget = target->ToUnit();
442 return instance->CheckAchievementCriteriaMeet(criteria_id, source, unitTarget, miscValue1);
443 }
445 {
446 AchievementCriteriaEntry const* entry = sAchievementCriteriaStore.AssertEntry(criteria_id);
447
448 uint32 itemId = (entry->Type == ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM ? miscValue2 : miscValue1);
449 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
450 if (!itemTemplate)
451 return false;
452 return itemTemplate->GetBaseItemLevel() >= equipped_item.item_level && itemTemplate->GetQuality() >= equipped_item.item_quality;
453 }
455 return source->GetMapId() == map_id.mapId;
457 {
458 time_t birthday_start = time_t(sWorld->getIntConfig(CONFIG_BIRTHDAY_TIME));
459 tm birthday_tm;
460 localtime_r(&birthday_start, &birthday_tm);
461
462 // exactly N birthday
463 birthday_tm.tm_year += birthday_login.nth_birthday;
464
465 time_t birthday = mktime(&birthday_tm);
466 time_t now = GameTime::GetGameTime();
467 return now <= birthday + DAY && now >= birthday;
468 }
470 {
471 if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(known_title.title_id))
472 return source->HasTitle(titleInfo->MaskID);
473 return false;
474 }
476 {
477 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1);
478 if (!pProto)
479 return false;
480 return pProto->GetQuality() == item.item_quality;
481 }
482 default:
483 break;
484 }
485 return false;
486}
487
488bool AchievementCriteriaDataSet::Meets(Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
489{
490 for (AchievementCriteriaData const& criteriadata : storage)
491 if (!criteriadata.Meets(criteria_id, source, target, miscValue1, miscValue2))
492 return false;
493
494 return true;
495}
496
497AchievementMgr::AchievementMgr(Player* player) : m_player(player), m_achievementPoints(0)
498{
499}
500
502
504{
505 for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : m_completedAchievements)
506 {
508 achievementDeleted.AchievementID = completedAchievement.first;
509 m_player->SendDirectMessage(achievementDeleted.Write());
510 }
511
512 for (std::pair<uint32 const, CriteriaProgress> const& criteriaprogress : m_criteriaProgress)
513 SendCriteriaProgressRemoved(criteriaprogress.first);
514
517 m_criteriaProgress.clear();
519
520 // re-fill data
522}
523
524void AchievementMgr::ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete)
525{
526 TC_LOG_DEBUG("achievement", "AchievementMgr::ResetAchievementCriteria({}, {}, {})", condition, value, evenIfCriteriaComplete);
527
528 // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission
530 return;
531
532 AchievementCriteriaEntryList const* achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByCondition(condition, value);
533 if (!achievementCriteriaList)
534 return;
535
536 for (AchievementCriteriaEntry const* achievementCriteria : *achievementCriteriaList)
537 {
538 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->AchievementID);
539 if (!achievement)
540 continue;
541
542 // don't update already completed criteria if not forced or achievement already complete
543 if ((IsCompletedCriteria(achievementCriteria, achievement) && !evenIfCriteriaComplete) || HasAchieved(achievement->ID))
544 continue;
545
546 RemoveCriteriaProgress(achievementCriteria);
547 }
548}
549
551{
552 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
553
555 stmt->setUInt32(0, guid.GetCounter());
556 trans->Append(stmt);
557
558 stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS);
559 stmt->setUInt32(0, guid.GetCounter());
560 trans->Append(stmt);
561
562 CharacterDatabase.CommitTransaction(trans);
563}
564
566{
567 if (!m_completedAchievements.empty())
568 {
569 for (std::pair<uint32 const, CompletedAchievementData>& completedAchievement : m_completedAchievements)
570 {
571 if (!completedAchievement.second.changed)
572 continue;
573
575 stmt->setUInt16(0, completedAchievement.first);
576 stmt->setUInt32(1, GetPlayer()->GetGUID().GetCounter());
577 trans->Append(stmt);
578
579 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT);
580 stmt->setUInt32(0, GetPlayer()->GetGUID().GetCounter());
581 stmt->setUInt16(1, completedAchievement.first);
582 stmt->setUInt32(2, uint32(completedAchievement.second.date));
583 trans->Append(stmt);
584
585 completedAchievement.second.changed = false;
586 }
587 }
588
589 if (!m_criteriaProgress.empty())
590 {
591 for (std::pair<uint32 const, CriteriaProgress>& criteriaProgres : m_criteriaProgress)
592 {
593 if (!criteriaProgres.second.changed)
594 continue;
595
597 stmt->setUInt32(0, GetPlayer()->GetGUID().GetCounter());
598 stmt->setUInt16(1, criteriaProgres.first);
599 trans->Append(stmt);
600
601 if (criteriaProgres.second.counter)
602 {
603 stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS);
604 stmt->setUInt32(0, GetPlayer()->GetGUID().GetCounter());
605 stmt->setUInt16(1, criteriaProgres.first);
606 stmt->setUInt32(2, criteriaProgres.second.counter);
607 stmt->setUInt32(3, uint32(criteriaProgres.second.date));
608 trans->Append(stmt);
609 }
610
611 criteriaProgres.second.changed = false;
612 }
613 }
614}
615
617{
618 if (achievementResult)
619 {
620 do
621 {
622 Field* fields = achievementResult->Fetch();
623 uint32 achievementid = fields[0].GetUInt16();
624
625 // must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements()
626 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementid);
627 if (!achievement)
628 continue;
629
631 ca.date = time_t(fields[1].GetUInt32());
632 ca.changed = false;
633
634 m_achievementPoints += achievement->Points;
635
636 // title achievement rewards are retroactive
637 if (AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement))
638 if (uint32 titleId = reward->TitleId[Player::TeamForRace(GetPlayer()->GetRace()) == ALLIANCE ? 0 : 1])
639 if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
640 GetPlayer()->SetTitle(titleEntry);
641
642 } while (achievementResult->NextRow());
643 }
644
645 if (criteriaResult)
646 {
647 do
648 {
649 Field* fields = criteriaResult->Fetch();
650 uint32 id = fields[0].GetUInt16();
651 uint32 counter = fields[1].GetUInt32();
652 time_t date = time_t(fields[2].GetUInt32());
653
654 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(id);
655 if (!criteria)
656 {
657 // Removing non-existing criteria data for all characters
658 TC_LOG_ERROR("achievement", "Non-existing achievement criteria {} data has been removed from the table `character_achievement_progress`.", id);
659
661
662 stmt->setUInt16(0, uint16(id));
663
664 CharacterDatabase.Execute(stmt);
665
666 continue;
667 }
668
669 if (criteria->StartTimer && time_t(date + criteria->StartTimer) < GameTime::GetGameTime())
670 continue;
671
672 CriteriaProgress& progress = m_criteriaProgress[id];
673 progress.counter = counter;
674 progress.date = date;
675 progress.changed = false;
676 } while (criteriaResult->NextRow());
677 }
678}
679
681{
682 if (GetPlayer()->GetSession()->PlayerLoading())
683 return;
684
685 // Don't send for achievements with ACHIEVEMENT_FLAG_HIDDEN
686 if (achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN)
687 return;
688
689 TC_LOG_DEBUG("achievement", "AchievementMgr::SendAchievementEarned({})", achievement->ID);
690
691 if (Guild* guild = sGuildMgr->GetGuildById(GetPlayer()->GetGuildId()))
692 {
695 guild->BroadcastWorker(_localizer, GetPlayer());
696 }
697
699 {
700 uint32 team = GetPlayer()->GetTeam();
701
702 // broadcast realm first reached
704 serverFirstAchievement.Name = m_player->GetName();
705 serverFirstAchievement.PlayerGUID = m_player->GetGUID();
706 serverFirstAchievement.AchievementID = achievement->ID;
707 serverFirstAchievement.DisplayLink = true; // display name as clickable link in chat
708 sWorld->SendGlobalMessage(serverFirstAchievement.Write(), nullptr, team);
709
710 serverFirstAchievement.Clear();
711 serverFirstAchievement.DisplayLink = false; // display name as plain string in chat
712 sWorld->SendGlobalMessage(serverFirstAchievement.Write(), nullptr, team == ALLIANCE ? HORDE : ALLIANCE);
713 }
714 // if player is in world he can tell his friends about new achievement
715 else if (GetPlayer()->IsInWorld())
716 {
721 }
722
723 auto achievementEarnedBuilder = [&](Player const* receiver)
724 {
726 achievementEarned.Earner = GetPlayer()->GetGUID();
727 achievementEarned.AchievementID = achievement->ID;
728 achievementEarned.Time = *GameTime::GetUtcWowTime();
729 achievementEarned.Time += receiver->GetSession()->GetTimezoneOffset();
730 achievementEarned.Initial = receiver->HasAtLoginFlag(AT_LOGIN_FIRST);
731 receiver->SendDirectMessage(achievementEarned.Write());
732 };
733
734 float dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY);
735 Trinity::PlayerDistWorker notifier(GetPlayer(), dist, achievementEarnedBuilder);
736 Cell::VisitWorldObjects(GetPlayer(), notifier, dist);
737}
738
739void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const
740{
742 criteriaUpdate.CriteriaID = entry->ID;
743 criteriaUpdate.Quantity = progress->counter;
744 criteriaUpdate.PlayerGUID = GetPlayer()->GetGUID();
745 criteriaUpdate.Flags = 0;
746 if (entry->StartTimer)
747 criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client
748
749 criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(progress->date);
750 criteriaUpdate.CurrentTime += GetPlayer()->GetSession()->GetTimezoneOffset();
751 criteriaUpdate.ElapsedTime = timeElapsed;
752 criteriaUpdate.CreationTime = 0;
753
754 GetPlayer()->SendDirectMessage(criteriaUpdate.Write());
755}
756
758{
760 criteriaDeleted.CriteriaID = criteriaId;
761 GetPlayer()->SendDirectMessage(criteriaDeleted.Write());
762}
763
768{
769 // suppress sending packets
770 for (uint32 i = 0; i < ACHIEVEMENT_CRITERIA_TYPE_TOTAL; ++i)
772}
773
774static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
775
779void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, WorldObject* ref /*= nullptr*/)
780{
782 {
783 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Wrong criteria type {}", type);
784 return;
785 }
786
787 // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission
789 {
790 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: [Player {} {}] {}, {} ({}), {}, {}"
791 , m_player->GetName(), m_player->IsGameMaster() ? "GM mode on" : "disallowed by RBAC", m_player->GetGUID().ToString(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
792 return;
793 }
794
795 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: {}, {} ({}), {}, {}"
796 , m_player->GetGUID().ToString(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
797
798 AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, miscValue1);
799 for (AchievementCriteriaEntry const* achievementCriteria : achievementCriteriaList)
800 {
801 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->AchievementID);
802 if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, ref))
803 continue;
804
805 switch (type)
806 {
807 // special cases, db data is checked later
811 break;
812 default:
813 if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
814 if (!data->Meets(GetPlayer(), ref, miscValue1, miscValue2))
815 continue;
816 break;
817 }
818
819 switch (type)
820 {
821 // std. case: increment at 1
835 case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
851 case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
860 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
861 break;
862 // std case: increment at miscValue1
872 case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: /* FIXME: for online player only currently */
876 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
877 break;
878 // std case: increment at miscValue2
884 SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
885 break;
886 // std case: high value at miscValue1
888 case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
893 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
894 break;
895 // std. case: set at 1
903 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_SET);
904 break;
905
906 // specialized cases
908 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetLevel());
909 break;
911 if (uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->Asset.SkillID))
912 SetCriteriaProgress(achievementCriteria, skillvalue);
913 break;
915 if (uint32 maxSkillvalue = GetPlayer()->GetPureMaxSkillValue(achievementCriteria->Asset.SkillID))
916 SetCriteriaProgress(achievementCriteria, maxSkillvalue);
917 break;
919 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetRewardedQuestCount());
920 break;
922 {
923 time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime();
924 CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
925
926 if (!miscValue1) // Login case.
927 {
928 // reset if player missed one day.
929 if (progress && progress->date < (nextDailyResetTime - 2 * DAY))
930 SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET);
931 continue;
932 }
933
934 ProgressType progressType;
935 if (!progress)
936 // 1st time. Start count.
937 progressType = PROGRESS_SET;
938 else if (progress->date < (nextDailyResetTime - 2 * DAY))
939 // last progress is older than 2 days. Player missed 1 day => Restart count.
940 progressType = PROGRESS_SET;
941 else if (progress->date < (nextDailyResetTime - DAY))
942 // last progress is between 1 and 2 days. => 1st time of the day.
943 progressType = PROGRESS_ACCUMULATE;
944 else
945 // last progress is within the day before the reset => Already counted today.
946 continue;
947
948 SetCriteriaProgress(achievementCriteria, 1, progressType);
949 break;
950 }
952 {
953 uint32 counter = 0;
954
955 RewardedQuestSet const& rewQuests = GetPlayer()->getRewardedQuests();
956 for (uint32 rewQuest : rewQuests)
957 {
958 Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest);
959 if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->Asset.ZoneID)
960 ++counter;
961 }
962 SetCriteriaProgress(achievementCriteria, counter);
963 break;
964 }
966 // miscValue1 is the ingame fallheight*100 as stored in dbc
967 SetCriteriaProgress(achievementCriteria, miscValue1);
968 break;
970 // additional requirements
971 if (achievementCriteria->AdditionalRequirements[0].Type == ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE)
972 {
973 // those requirements couldn't be found in the dbc
974 AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
975 if (!data || !data->Meets(GetPlayer(), ref, miscValue1))
976 {
977 // reset the progress as we have a win without the requirement.
978 SetCriteriaProgress(achievementCriteria, 0);
979 continue;
980 }
981 }
982
983 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
984 break;
986 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetBankBagSlotCount());
987 break;
989 {
990 int32 reputation = GetPlayer()->GetReputationMgr().GetReputation(achievementCriteria->Asset.FactionID);
991 if (reputation > 0)
992 SetCriteriaProgress(achievementCriteria, reputation);
993 break;
994 }
996 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetExaltedFactionCount());
997 break;
1000 {
1001 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
1002 if (!proto)
1003 continue;
1004
1005 // check item level via achievement_criteria_data
1006 AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
1007 if (!data || !data->Meets(GetPlayer(), nullptr, proto->GetBaseItemLevel()))
1008 continue;
1009
1010 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
1011 break;
1012 }
1014 {
1015 uint32 spellCount = 0;
1016 for (std::pair<uint32 const, PlayerSpell> const& spellIter : GetPlayer()->GetSpellMap())
1017 {
1018 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter.first);
1019 for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
1020 {
1021 if (skillIter->second->SkillLine == achievementCriteria->Asset.SkillID)
1022 {
1023 // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
1024 ++spellCount;
1025 break;
1026 }
1027 }
1028 }
1029 SetCriteriaProgress(achievementCriteria, spellCount);
1030 break;
1031 }
1033 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount());
1034 break;
1036 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetHonoredFactionCount());
1037 break;
1039 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetVisibleFactionCount());
1040 break;
1042 {
1043 uint32 spellCount = 0;
1044 for (std::pair<uint32 const, PlayerSpell> const& spellIter : GetPlayer()->GetSpellMap())
1045 {
1046 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter.first);
1047 for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
1048 {
1049 if (skillIter->second->SkillLine == achievementCriteria->Asset.SkillID)
1050 {
1051 // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
1052 ++spellCount;
1053 break;
1054 }
1055 }
1056 }
1057 SetCriteriaProgress(achievementCriteria, spellCount);
1058 break;
1059 }
1061 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS));
1062 break;
1064 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetMoney(), PROGRESS_HIGHEST);
1065 break;
1067 if (!miscValue1)
1069 else
1070 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
1071 break;
1073 {
1074 uint32 reqTeamType = achievementCriteria->Asset.TeamType;
1075
1076 if (miscValue1)
1077 {
1078 if (miscValue2 != reqTeamType)
1079 continue;
1080
1081 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
1082 }
1083 else // login case
1084 {
1085 for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
1086 {
1087 uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot);
1088 if (!teamId)
1089 continue;
1090
1091 ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
1092 if (!team || team->GetType() != reqTeamType)
1093 continue;
1094
1095 SetCriteriaProgress(achievementCriteria, team->GetStats().Rating, PROGRESS_HIGHEST);
1096 break;
1097 }
1098 }
1099 break;
1100 }
1102 {
1103 uint32 reqTeamType = achievementCriteria->Asset.TeamType;
1104
1105 if (miscValue1)
1106 {
1107 if (miscValue2 != reqTeamType)
1108 continue;
1109
1110 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
1111 }
1112 else // login case
1113 {
1114 for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
1115 {
1116 uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot);
1117 if (!teamId)
1118 continue;
1119
1120 ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
1121 if (!team || team->GetType() != reqTeamType)
1122 continue;
1123
1124 if (ArenaTeamMember const* member = team->GetMember(GetPlayer()->GetGUID()))
1125 {
1126 SetCriteriaProgress(achievementCriteria, member->PersonalRating, PROGRESS_HIGHEST);
1127 break;
1128 }
1129 }
1130 }
1131
1132 break;
1133 }
1134 // std case: does not exist in DBC, not triggered in code as result
1141 break;
1142 // FIXME: not triggered in code as result, need to implement
1146 break; // Not implemented yet :(
1147 }
1148
1149 if (IsCompletedCriteria(achievementCriteria, achievement))
1150 CompletedCriteriaFor(achievement);
1151
1152 // check again the completeness for SUMM and REQ COUNT achievements,
1153 // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
1154 if (achievement->Flags & ACHIEVEMENT_FLAG_SUMM)
1155 if (IsCompletedAchievement(achievement))
1156 CompletedAchievement(achievement);
1157
1158 if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(achievement->ID))
1159 for (AchievementEntry const* achievement : *achRefList)
1160 if (IsCompletedAchievement(achievement))
1161 CompletedAchievement(achievement);
1162 }
1163}
1164
1165bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement)
1166{
1167 if (!achievement)
1168 return false;
1169
1170 // counter can never complete
1171 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER)
1172 return false;
1173
1175 {
1176 // someone on this realm has already completed that achievement
1177 if (sAchievementMgr->IsRealmCompleted(achievement))
1178 return false;
1179 }
1180
1181 CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
1182 if (!progress)
1183 return false;
1184
1185 switch (AchievementCriteriaTypes(achievementCriteria->Type))
1186 {
1233 return progress->counter >= achievementCriteria->Quantity;
1238 return progress->counter >= 1;
1240 return progress->counter >= (achievementCriteria->Quantity * 75);
1242 return progress->counter >= 9000;
1244 return achievementCriteria->Quantity && progress->counter >= achievementCriteria->Quantity;
1246 return true;
1247 // handle all statistic-only criteria here
1282 default:
1283 break;
1284 }
1285
1286 return false;
1287}
1288
1290{
1291 // counter can never complete
1292 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER)
1293 return;
1294
1295 // already completed and stored
1296 if (HasAchieved(achievement->ID))
1297 return;
1298
1299 if (IsCompletedAchievement(achievement))
1300 CompletedAchievement(achievement);
1301}
1302
1304{
1305 // counter can never complete
1306 if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER)
1307 return false;
1308
1309 // for achievement with referenced achievement criterias get from referenced and counter from self
1310 uint32 achievementForTestId = entry->SharesCriteria ? entry->SharesCriteria : entry->ID;
1311 uint32 achievementForTestCount = entry->MinimumCriteria;
1312
1313 AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementForTestId);
1314 if (!cList)
1315 return false;
1316 uint32 count = 0;
1317
1318 // For SUMM achievements, we have to count the progress of each criteria of the achievement.
1319 // Oddly, the target count is NOT contained in the achievement, but in each individual criteria
1320 if (entry->Flags & ACHIEVEMENT_FLAG_SUMM)
1321 {
1322 for (AchievementCriteriaEntry const* criteria : *cList)
1323 {
1324 CriteriaProgress const* progress = GetCriteriaProgress(criteria);
1325 if (!progress)
1326 continue;
1327
1328 count += progress->counter;
1329
1330 // for counters, field4 contains the main count requirement
1331 if (count >= criteria->Quantity)
1332 return true;
1333 }
1334 return false;
1335 }
1336
1337 // Default case - need complete all or
1338 bool completed_all = true;
1339 for (AchievementCriteriaEntry const* criteria : *cList)
1340 {
1341 bool completed = IsCompletedCriteria(criteria, entry);
1342
1343 // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL
1344 if (completed)
1345 ++count;
1346 else
1347 completed_all = false;
1348
1349 // completed as have req. count of completed criterias
1350 if (achievementForTestCount > 0 && achievementForTestCount <= count)
1351 return true;
1352 }
1353
1354 // all criterias completed requirement
1355 if (completed_all && achievementForTestCount == 0)
1356 return true;
1357
1358 return false;
1359}
1360
1362{
1363 CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
1364
1365 if (iter == m_criteriaProgress.end())
1366 return nullptr;
1367
1368 return &(iter->second);
1369}
1370
1372{
1373 // Don't allow to cheat - doing timed achievements without timer active
1374 TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID);
1375 if (entry->StartTimer && timedIter == m_timedAchievements.end())
1376 return;
1377
1378 TC_LOG_DEBUG("achievement", "AchievementMgr::SetCriteriaProgress({}, {}) for {}", entry->ID, changeValue, m_player->GetGUID().ToString());
1379
1380 CriteriaProgress* progress = GetCriteriaProgress(entry);
1381 if (!progress)
1382 {
1383 // not create record for 0 counter but allow it for timed achievements
1384 // we will need to send 0 progress to client to start the timer
1385 if (changeValue == 0 && !entry->StartTimer)
1386 return;
1387
1388 progress = &m_criteriaProgress[entry->ID];
1389 progress->counter = changeValue;
1390 }
1391 else
1392 {
1393 uint32 newValue = 0;
1394 switch (ptype)
1395 {
1396 case PROGRESS_SET:
1397 newValue = changeValue;
1398 break;
1400 {
1401 // avoid overflow
1402 uint32 max_value = std::numeric_limits<uint32>::max();
1403 newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value;
1404 break;
1405 }
1406 case PROGRESS_HIGHEST:
1407 newValue = progress->counter < changeValue ? changeValue : progress->counter;
1408 break;
1409 }
1410
1411 // not update (not mark as changed) if counter will have same value
1412 if (progress->counter == newValue && !entry->StartTimer)
1413 return;
1414
1415 progress->counter = newValue;
1416 }
1417
1418 progress->changed = true;
1419 progress->date = GameTime::GetGameTime(); // set the date to the latest update.
1420
1421 uint32 timeElapsed = 0;
1422 bool timedCompleted = false;
1423
1424 if (entry->StartTimer)
1425 {
1426 // has to exist, otherwise we wouldn't be here
1427 timedCompleted = IsCompletedCriteria(entry, sAchievementStore.LookupEntry(entry->AchievementID));
1428 // Client expects this in packet
1429 timeElapsed = entry->StartTimer - (timedIter->second/IN_MILLISECONDS);
1430
1431 // Remove the timer, we wont need it anymore
1432 if (timedCompleted)
1433 m_timedAchievements.erase(timedIter);
1434 }
1435
1436 SendCriteriaUpdate(entry, progress, timeElapsed, timedCompleted);
1437}
1438
1440{
1441 if (!criteria)
1442 return;
1443
1444 auto criteriaProgress = m_criteriaProgress.find(criteria->ID);
1445 if (criteriaProgress == m_criteriaProgress.end())
1446 return;
1447
1449
1450 m_criteriaProgress.erase(criteriaProgress);
1451}
1452
1454{
1455 if (!m_timedAchievements.empty())
1456 {
1457 for (TimedAchievementMap::iterator itr = m_timedAchievements.begin(); itr != m_timedAchievements.end();)
1458 {
1459 // Time is up, remove timer and reset progress
1460 if (itr->second <= timeDiff)
1461 {
1462 AchievementCriteriaEntry const* entry = sAchievementCriteriaStore.LookupEntry(itr->first);
1464 m_timedAchievements.erase(itr++);
1465 }
1466 else
1467 {
1468 itr->second -= timeDiff;
1469 ++itr;
1470 }
1471 }
1472 }
1473}
1474
1476{
1477 for (AchievementCriteriaEntry const* criteria : sAchievementMgr->GetTimedAchievementCriteriaByType(type))
1478 {
1479 if (criteria->StartAsset != entry)
1480 continue;
1481
1482 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
1483 if (m_timedAchievements.find(criteria->ID) == m_timedAchievements.end() && !IsCompletedCriteria(criteria, achievement))
1484 {
1485 // Start the timer
1486 if (criteria->StartTimer * IN_MILLISECONDS > timeLost)
1487 {
1488 m_timedAchievements[criteria->ID] = criteria->StartTimer * IN_MILLISECONDS - timeLost;
1489
1490 // and at client too
1491 SetCriteriaProgress(criteria, 0, PROGRESS_SET);
1492 }
1493 }
1494 }
1495}
1496
1498{
1499 for (AchievementCriteriaEntry const* criteria : sAchievementMgr->GetTimedAchievementCriteriaByType(type))
1500 {
1501 if (criteria->StartAsset != entry)
1502 continue;
1503
1504 TimedAchievementMap::iterator timedIter = m_timedAchievements.find(criteria->ID);
1505 // We don't have timer for this achievement
1506 if (timedIter == m_timedAchievements.end())
1507 continue;
1508
1509 // remove progress
1510 RemoveCriteriaProgress(criteria);
1511
1512 // Remove the timer
1513 m_timedAchievements.erase(timedIter);
1514 }
1515}
1516
1518{
1519 // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission
1521 return;
1522
1523 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID))
1524 return;
1525
1526 TC_LOG_INFO("achievement", "AchievementMgr::CompletedAchievement({}). Player: {} {}",
1527 achievement->ID, m_player->GetGUID().ToString(), m_player->GetName());
1528
1529 SendAchievementEarned(achievement);
1532 ca.changed = true;
1533
1535 sAchievementMgr->SetRealmCompleted(achievement);
1536
1537 m_achievementPoints += achievement->Points;
1538
1541
1542 // reward items and titles if any
1543 AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement);
1544
1545 // no rewards
1546 if (!reward)
1547 return;
1548
1549 // titles
1554 if (uint32 titleId = reward->TitleId[achievement->ID == 1793 ? GetPlayer()->GetNativeGender() : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)])
1555 if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
1556 GetPlayer()->SetTitle(titleEntry);
1557
1558 // mail
1559 if (reward->SenderCreatureId)
1560 {
1561 MailDraft draft(reward->MailTemplateId);
1562
1563 if (!reward->MailTemplateId)
1564 {
1565 // subject and text
1566 std::string subject = reward->Subject;
1567 std::string text = reward->Body;
1568
1570 if (localeConstant != LOCALE_enUS)
1571 {
1572 if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement))
1573 {
1574 ObjectMgr::GetLocaleString(loc->Subject, localeConstant, subject);
1575 ObjectMgr::GetLocaleString(loc->Text, localeConstant, text);
1576 }
1577 }
1578
1579 draft = MailDraft(subject, text);
1580 }
1581
1582 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1583
1584 Item* item = reward->ItemId ? Item::CreateItem(reward->ItemId, 1, GetPlayer()) : nullptr;
1585 if (item)
1586 {
1587 // save new item before send
1588 item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted
1589
1590 // item
1591 draft.AddItem(item);
1592 }
1593
1595 CharacterDatabase.CommitTransaction(trans);
1596 }
1597}
1598
1600{
1602 BuildAllDataPacket(GetPlayer(), &achievementData.Data);
1603 GetPlayer()->SendDirectMessage(achievementData.Write());
1604}
1605
1607{
1609 inspectedAchievements.Player = GetPlayer()->GetGUID();
1610 BuildAllDataPacket(player, &inspectedAchievements.Data);
1611 player->SendDirectMessage(inspectedAchievements.Write());
1612}
1613
1618{
1619 data->Earned.reserve(m_completedAchievements.size());
1620 for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : m_completedAchievements)
1621 {
1622 // Skip hidden achievements
1623 AchievementEntry const* achievement = sAchievementStore.LookupEntry(completedAchievement.first);
1624 if (!achievement || achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN)
1625 continue;
1626
1627 WorldPackets::Achievement::EarnedAchievement& earned = data->Earned.emplace_back();
1628 earned.Id = completedAchievement.first;
1629 earned.Date.SetUtcTimeFromUnixTime(completedAchievement.second.date);
1630 earned.Date += receiver->GetSession()->GetTimezoneOffset();
1631 }
1632
1633 data->Progress.reserve(m_criteriaProgress.size());
1634 for (std::pair<uint32 const, CriteriaProgress> const& criteriaProgres : m_criteriaProgress)
1635 {
1636 WorldPackets::Achievement::CriteriaProgress& progress = data->Progress.emplace_back();
1637 progress.Id = criteriaProgres.first;
1638 progress.Quantity = criteriaProgres.second.counter;
1639 progress.Player = GetPlayer()->GetGUID();
1640 progress.Flags = 0;
1641 progress.Date.SetUtcTimeFromUnixTime(criteriaProgres.second.date);
1642 progress.Date += receiver->GetSession()->GetTimezoneOffset();
1643 progress.TimeFromStart = Seconds::zero().count();
1644 progress.TimeFromCreate = Seconds::zero().count();
1645 }
1646}
1647
1648bool AchievementMgr::HasAchieved(uint32 achievementId) const
1649{
1650 return m_completedAchievements.find(achievementId) != m_completedAchievements.end();
1651}
1652
1653bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref)
1654{
1656 {
1657 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Disabled",
1659 return false;
1660 }
1661
1662 if (achievement->InstanceID != -1 && GetPlayer()->GetMapId() != uint32(achievement->InstanceID))
1663 {
1664 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {} Achievement {}) Wrong map",
1665 criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type), achievement->ID);
1666 return false;
1667 }
1668
1669 if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeam() != HORDE) ||
1670 (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
1671 {
1672 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {} Achievement {}) Wrong faction",
1673 criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type), achievement->ID);
1674 return false;
1675 }
1676
1677 if (!RequirementsSatisfied(criteria, achievement, miscValue1, miscValue2, ref))
1678 {
1679 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Requirements have not been satisfied",
1681 return false;
1682 }
1683
1684 if (!ConditionsSatisfied(criteria))
1685 {
1686 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Conditions have not been satisfied",
1688 return false;
1689 }
1690
1691 // Don't update realm first achievements if the player's account isn't allowed to do so
1693 if (GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_REALM_FIRST_ACHIEVEMENTS))
1694 return false;
1695
1696 // don't update already completed criteria
1697 if (IsCompletedCriteria(criteria, achievement))
1698 return false;
1699
1700 return true;
1701}
1702
1704{
1705 for (auto AdditionalRequirement : criteria->AdditionalRequirements)
1706 {
1707 if (!AdditionalRequirement.Type)
1708 continue;
1709
1710 switch (AdditionalRequirement.Type)
1711 {
1713 if (GetPlayer()->GetMapId() != AdditionalRequirement.Asset)
1714 return false;
1715 break;
1717 if (GetPlayer()->GetGroup())
1718 return false;
1719 break;
1720 default:
1721 break;
1722 }
1723 }
1724
1725 return true;
1726}
1727
1728bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref) const
1729{
1730 switch (AchievementCriteriaTypes(achievementCriteria->Type))
1731 {
1768 if (!miscValue1)
1769 return false;
1770 break;
1784 break;
1785
1786 // specialized cases
1788 if ((miscValue1 && achievementCriteria->Asset.AchievementID != miscValue1) || (!miscValue1 && m_completedAchievements.find(achievementCriteria->Asset.AchievementID) == m_completedAchievements.end()))
1789 return false;
1790 break;
1794 if (!miscValue1 || achievementCriteria->Asset.MapID != GetPlayer()->GetMapId())
1795 return false;
1796 break;
1799 if (!miscValue1 || achievementCriteria->Asset.CreatureID != miscValue1)
1800 return false;
1801 break;
1804 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SkillID)
1805 return false;
1806 break;
1808 if (miscValue1 && miscValue1 != achievementCriteria->Asset.ZoneID)
1809 return false;
1810 break;
1812 if (!miscValue1)
1813 return false;
1814 for (uint8 j = 0; j < MAX_ARENA_SLOT; ++j)
1815 {
1816 if (achievIdByArenaSlot[j] == achievement->ID)
1817 {
1819 if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
1820 return false;
1821 break;
1822 }
1823 }
1824 break;
1826 {
1827 if (!miscValue1)
1828 return false;
1829
1830 Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
1831 if (!map || !map->IsDungeon())
1832 return false;
1833
1834 //FIXME: work only for instances where max == min for players
1835 if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->Asset.GroupSize)
1836 return false;
1837 break;
1838 }
1840 if (!miscValue1)
1841 return false;
1842 // if team check required: must kill by opposition faction
1843 if (achievement->ID == 318 && miscValue2 == GetPlayer()->GetTeam())
1844 return false;
1845 break;
1847 if (!miscValue1 || miscValue2 != achievementCriteria->Asset.DamageType)
1848 return false;
1849 break;
1851 // if miscvalues != 0, it contains the questID.
1852 if (miscValue1)
1853 {
1854 if (miscValue1 != achievementCriteria->Asset.QuestID)
1855 return false;
1856 }
1857 else
1858 {
1859 // login case.
1860 if (!GetPlayer()->GetQuestRewardStatus(achievementCriteria->Asset.QuestID))
1861 return false;
1862 }
1863 break;
1868 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.SpellID)
1869 return false;
1870 break;
1872 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SpellID)
1873 return false;
1874 if (!GetPlayer()->HasSpell(achievementCriteria->Asset.SpellID))
1875 return false;
1876 break;
1878 // miscValue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored)
1879 // miscValue2=count of item loot
1880 if (!miscValue1 || !miscValue2)
1881 return false;
1882 if (miscValue1 != achievementCriteria->Asset.LootType)
1883 return false;
1884 break;
1886 if (miscValue1 && achievementCriteria->Asset.ItemID != miscValue1)
1887 return false;
1888 break;
1892 if (!miscValue1)
1893 return false;
1894 if (miscValue1 != achievementCriteria->Asset.ItemID)
1895 return false;
1896 break;
1898 {
1899 WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->Asset.WorldMapOverlayID);
1900 if (!worldOverlayEntry)
1901 return false;
1902
1903 bool matchFound = false;
1904 for (uint32 j : worldOverlayEntry->AreaID)
1905 {
1906 AreaTableEntry const* area = sAreaTableStore.LookupEntry(j);
1907 if (!area)
1908 break;
1909
1910 uint32 playerIndexOffset = uint32(area->AreaBit) / 32;
1911 if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)
1912 continue;
1913
1914 uint32 mask = 1 << (uint32(area->AreaBit) % 32);
1915 if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
1916 {
1917 matchFound = true;
1918 break;
1919 }
1920 }
1921
1922 if (!matchFound)
1923 return false;
1924 break;
1925 }
1927 if (miscValue1 && miscValue1 != achievementCriteria->Asset.FactionID)
1928 return false;
1929 break;
1931 // miscValue1 = itemSlot
1932 // miscValue2 = itemid
1933 if (!miscValue2)
1934 return false;
1935 if (miscValue1 != achievementCriteria->Asset.ItemSlot)
1936 return false;
1937 break;
1940 // miscValue1 = itemid
1941 // miscValue2 = diced value
1942 if (!miscValue1)
1943 return false;
1944 if (miscValue2 != achievementCriteria->Asset.RollValue)
1945 return false;
1946 break;
1948 // miscValue1 = emote
1949 if (!miscValue1)
1950 return false;
1951 if (miscValue1 != achievementCriteria->Asset.EmoteID)
1952 return false;
1953 break;
1956 if (!miscValue1)
1957 return false;
1958
1960 {
1961 if (GetPlayer()->GetMapId() != achievementCriteria->AdditionalRequirements[0].Asset)
1962 return false;
1963
1964 // map specific case (BG in fact) expected player targeted damage/heal
1965 if (!ref || ref->GetTypeId() != TYPEID_PLAYER)
1966 return false;
1967 }
1968 break;
1971 if (!miscValue1)
1972 return false;
1973 if (miscValue1 != achievementCriteria->Asset.GameObjectID)
1974 return false;
1975 break;
1978 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SkillID)
1979 return false;
1980 break;
1983 {
1984 if (!miscValue1)
1985 return false;
1986 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
1987 if (!proto || proto->GetQuality() < ITEM_QUALITY_EPIC)
1988 return false;
1989 break;
1990 }
1992 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.ClassID)
1993 return false;
1994 break;
1996 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.RaceID)
1997 return false;
1998 break;
2000 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.ObjectiveId)
2001 return false;
2002 break;
2004 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.AreaID)
2005 return false;
2006 break;
2008 if (miscValue1 != achievementCriteria->Asset.MapID)
2009 return false;
2010 break;
2011 default:
2012 break;
2013 }
2014
2015 return true;
2016}
2017
2022
2024{
2025 switch (type)
2026 {
2028 return "KILL_CREATURE";
2030 return "TYPE_WIN_BG";
2032 return "REACH_LEVEL";
2034 return "REACH_SKILL_LEVEL";
2036 return "COMPLETE_ACHIEVEMENT";
2038 return "COMPLETE_QUEST_COUNT";
2040 return "COMPLETE_DAILY_QUEST_DAILY";
2042 return "COMPLETE_QUESTS_IN_ZONE";
2044 return "DAMAGE_DONE";
2046 return "COMPLETE_DAILY_QUEST";
2048 return "COMPLETE_BATTLEGROUND";
2050 return "DEATH_AT_MAP";
2052 return "DEATH";
2054 return "DEATH_IN_DUNGEON";
2056 return "COMPLETE_RAID";
2058 return "KILLED_BY_CREATURE";
2060 return "KILLED_BY_PLAYER";
2062 return "FALL_WITHOUT_DYING";
2064 return "DEATHS_FROM";
2066 return "COMPLETE_QUEST";
2068 return "BE_SPELL_TARGET";
2070 return "CAST_SPELL";
2072 return "BG_OBJECTIVE_CAPTURE";
2074 return "HONORABLE_KILL_AT_AREA";
2076 return "WIN_ARENA";
2078 return "PLAY_ARENA";
2080 return "LEARN_SPELL";
2082 return "HONORABLE_KILL";
2084 return "OWN_ITEM";
2086 return "WIN_RATED_ARENA";
2088 return "HIGHEST_TEAM_RATING";
2090 return "HIGHEST_PERSONAL_RATING";
2092 return "LEARN_SKILL_LEVEL";
2094 return "USE_ITEM";
2096 return "LOOT_ITEM";
2098 return "EXPLORE_AREA";
2100 return "OWN_RANK";
2102 return "BUY_BANK_SLOT";
2104 return "GAIN_REPUTATION";
2106 return "GAIN_EXALTED_REPUTATION";
2108 return "VISIT_BARBER_SHOP";
2110 return "EQUIP_EPIC_ITEM";
2112 return "ROLL_NEED_ON_LOOT";
2114 return "GREED_ON_LOOT";
2116 return "HK_CLASS";
2118 return "HK_RACE";
2120 return "DO_EMOTE";
2122 return "HEALING_DONE";
2124 return "GET_KILLING_BLOWS";
2126 return "EQUIP_ITEM";
2128 return "MONEY_FROM_VENDORS";
2130 return "GOLD_SPENT_FOR_TALENTS";
2132 return "NUMBER_OF_TALENT_RESETS";
2134 return "MONEY_FROM_QUEST_REWARD";
2136 return "GOLD_SPENT_FOR_TRAVELLING";
2138 return "GOLD_SPENT_AT_BARBER";
2140 return "GOLD_SPENT_FOR_MAIL";
2142 return "LOOT_MONEY";
2144 return "USE_GAMEOBJECT";
2146 return "GAIN_AURA";
2148 return "SPECIAL_PVP_KILL";
2150 return "FISH_IN_GAMEOBJECT";
2152 return "ON_LOGIN";
2154 return "LEARN_SKILLLINE_SPELLS";
2156 return "WIN_DUEL";
2158 return "LOSE_DUEL";
2160 return "KILL_CREATURE_TYPE";
2162 return "GOLD_EARNED_BY_AUCTIONS";
2164 return "CREATE_AUCTION";
2166 return "HIGHEST_AUCTION_BID";
2168 return "WON_AUCTIONS";
2170 return "HIGHEST_AUCTION_SOLD";
2172 return "HIGHEST_GOLD_VALUE_OWNED";
2174 return "GAIN_REVERED_REPUTATION";
2176 return "GAIN_HONORED_REPUTATION";
2178 return "KNOWN_FACTIONS";
2180 return "LOOT_EPIC_ITEM";
2182 return "RECEIVE_EPIC_ITEM";
2184 return "ROLL_NEED";
2186 return "ROLL_GREED";
2188 return "HIGHEST_HEALTH";
2190 return "HIGHEST_POWER";
2192 return "HIGHEST_STAT";
2194 return "HIGHEST_SPELLPOWER";
2196 return "HIGHEST_ARMOR";
2198 return "HIGHEST_RATING";
2200 return "HIT_DEALT";
2202 return "HIT_RECEIVED";
2204 return "TOTAL_DAMAGE_RECEIVED";
2206 return "HIGHEST_HEAL_CAST";
2208 return "TOTAL_HEALING_RECEIVED";
2210 return "HIGHEST_HEALING_RECEIVED";
2212 return "QUEST_ABANDONED";
2214 return "FLIGHT_PATHS_TAKEN";
2216 return "LOOT_TYPE";
2218 return "CAST_SPELL2";
2220 return "LEARN_SKILL_LINE";
2222 return "EARN_HONORABLE_KILL";
2224 return "ACCEPTED_SUMMONINGS";
2226 return "EARN_ACHIEVEMENT_POINTS";
2228 return "USE_LFD_TO_GROUP_WITH_PLAYERS";
2229 }
2230 return "MISSING_TYPE";
2231}
2232
2234
2240
2242{
2243 switch (type)
2244 {
2276 return true;
2277 default:
2278 break;
2279 }
2280 return false;
2281}
2282
2284{
2285 if (miscValue && IsAchievementCriteriaTypeStoredByMiscValue(type))
2286 {
2287 auto itr = _achievementCriteriasByMiscalue[type].find(miscValue);
2288 if (itr != _achievementCriteriasByMiscalue[type].end())
2289 return itr->second;
2290
2291 return EmptyCriteriaList;
2292 }
2293
2294 return _achievementCriteriasByType[type];
2295}
2296
2298{
2299 auto itr = _allCompletedAchievements.find(achievement->ID);
2300 if (itr == _allCompletedAchievements.end())
2301 return false;
2302
2303 if (itr->second == SystemTimePoint ::min())
2304 return false;
2305
2306 if (itr->second == SystemTimePoint::max())
2307 return true;
2308
2309 // Allow completing the realm first kill for entire minute after first person did it
2310 // it may allow more than one group to achieve it (highly unlikely)
2311 // but apparently this is how blizz handles it as well
2312 if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
2313 return (GameTime::GetSystemTime() - itr->second) > Minutes(1);
2314
2315 return true;
2316}
2317
2319{
2320 if (IsRealmCompleted(achievement))
2321 return;
2322
2324}
2325
2326//==========================================================
2328
2330{
2331 uint32 oldMSTime = getMSTime();
2332
2333 if (sAchievementCriteriaStore.GetNumRows() == 0)
2334 {
2335 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement criteria.");
2336 return;
2337 }
2338
2339 uint32 loaded = 0;
2340 for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
2341 {
2342 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
2343 if (!criteria)
2344 continue;
2345
2346 if (!sAchievementStore.LookupEntry(criteria->AchievementID))
2347 {
2348 TC_LOG_DEBUG("server.loading", "Achievement {} referenced by criteria {} doesn't exist, criteria not loaded.", criteria->AchievementID, criteria->ID);
2349 continue;
2350 }
2351
2352 ASSERT(criteria->Type < ACHIEVEMENT_CRITERIA_TYPE_TOTAL, "ACHIEVEMENT_CRITERIA_TYPE_TOTAL must be greater than or equal to %u but is currently equal to %u",
2353 criteria->Type + 1, ACHIEVEMENT_CRITERIA_TYPE_TOTAL);
2354
2355 _achievementCriteriasByType[criteria->Type].push_back(criteria);
2356 _achievementCriteriaListByAchievement[criteria->AchievementID].push_back(criteria);
2358 {
2360 _achievementCriteriasByMiscalue[criteria->Type][criteria->Asset.ID].push_back(criteria);
2361 else
2362 {
2363 WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(criteria->Asset.WorldMapOverlayID);
2364 if (!worldOverlayEntry)
2365 break;
2366
2367 for (uint8 j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
2368 {
2369 if (worldOverlayEntry->AreaID[j])
2370 {
2371 bool valid = true;
2372 for (uint8 i = 0; i < j; ++i)
2373 if (worldOverlayEntry->AreaID[j] == worldOverlayEntry->AreaID[i])
2374 valid = false;
2375 if (valid)
2376 _achievementCriteriasByMiscalue[criteria->Type][worldOverlayEntry->AreaID[j]].push_back(criteria);
2377 }
2378 }
2379 }
2380 }
2381
2382 for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i)
2383 {
2385 {
2387 "ACHIEVEMENT_CRITERIA_CONDITION_MAX must be greater than or equal to %u but is currently equal to %u",
2389
2390 if (i == 0
2391 || criteria->AdditionalRequirements[i].Type != criteria->AdditionalRequirements[i - 1].Type
2392 || criteria->AdditionalRequirements[i].Asset != criteria->AdditionalRequirements[i - 1].Asset)
2393 _achievementCriteriasByCondition[criteria->AdditionalRequirements[i].Type][criteria->AdditionalRequirements[i].Asset].push_back(criteria);
2394 }
2395 }
2396
2397 if (criteria->StartTimer)
2398 {
2399 ASSERT(criteria->StartEvent < ACHIEVEMENT_TIMED_TYPE_MAX, "ACHIEVEMENT_TIMED_TYPE_MAX must be greater than or equal to %u but is currently equal to %u",
2400 criteria->StartEvent + 1, ACHIEVEMENT_TIMED_TYPE_MAX);
2401 _achievementCriteriasByTimedType[criteria->StartEvent].push_back(criteria);
2402 }
2403
2404 ++loaded;
2405 }
2406
2407 TC_LOG_INFO("server.loading", ">> Loaded {} achievement criteria in {} ms.", loaded, GetMSTimeDiffToNow(oldMSTime));
2408}
2409
2411{
2412 uint32 oldMSTime = getMSTime();
2413
2414 if (sAchievementStore.GetNumRows() == 0)
2415 {
2416 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement references.");
2417 return;
2418 }
2419
2420 uint32 count = 0;
2421
2422 for (uint32 entryId = 0; entryId < sAchievementStore.GetNumRows(); ++entryId)
2423 {
2424 AchievementEntry const* achievement = sAchievementStore.LookupEntry(entryId);
2425 if (!achievement || !achievement->SharesCriteria)
2426 continue;
2427
2428 _achievementListByReferencedId[achievement->SharesCriteria].push_back(achievement);
2429 ++count;
2430 }
2431
2432 // Once Bitten, Twice Shy (10 player) - Icecrown Citadel
2433 if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(4539))
2434 const_cast<AchievementEntry*>(achievement)->InstanceID = 631; // Correct map requirement (currently has Ulduar)
2435
2436 TC_LOG_INFO("server.loading", ">> Loaded {} achievement references in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
2437}
2438
2440{
2441 uint32 oldMSTime = getMSTime();
2442
2443 _criteriaDataMap.clear(); // need for reload case
2444
2445 QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data");
2446
2447 if (!result)
2448 {
2449 TC_LOG_INFO("server.loading", ">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty.");
2450 return;
2451 }
2452
2453 uint32 count = 0;
2454
2455 do
2456 {
2457 Field* fields = result->Fetch();
2458 uint32 criteria_id = fields[0].GetUInt32();
2459
2460 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id);
2461
2462 if (!criteria)
2463 {
2464 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for non-existing criteria (Entry: {}). Ignored.", criteria_id);
2465 continue;
2466 }
2467
2468 uint32 dataType = fields[1].GetUInt8();
2469 std::string scriptName = fields[4].GetString();
2470 uint32 scriptId = 0;
2471 if (!scriptName.empty())
2472 {
2474 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains a ScriptName for non-scripted data type (Entry: {}, type {}), useless data.", criteria_id, dataType);
2475 else
2476 scriptId = sObjectMgr->GetScriptId(scriptName);
2477 }
2478
2479 AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId);
2480
2481 if (!data.IsValid(criteria))
2482 continue;
2483
2484 // this will allocate empty data set storage
2485 AchievementCriteriaDataSet& dataSet = _criteriaDataMap[criteria_id];
2486 dataSet.SetCriteriaId(criteria_id);
2487
2488 // add real data only for not NONE data types
2490 dataSet.Add(data);
2491
2492 // counting data by and data types
2493 ++count;
2494 }
2495 while (result->NextRow());
2496
2497 // post loading checks
2498 for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
2499 {
2500 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
2501 if (!criteria)
2502 continue;
2503
2504 switch (criteria->Type)
2505 {
2522 // achievement requires db data
2523 break;
2525 {
2526 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
2527 if (!achievement)
2528 continue;
2529
2530 // There are many achievements with these criteria, use hardcoded check at this moment to pick a simple case
2531 if (achievement->ID == 1282)
2532 break;
2533
2534 continue;
2535 }
2536 case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: // need skip generic cases
2538 continue;
2539 break;
2540 case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases
2541 if (criteria->Quantity == 0)
2542 continue;
2543 break;
2544 case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: // skip statistics
2545 if (criteria->Quantity == 0)
2546 continue;
2547 break;
2548 case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases
2549 if (criteria->Quantity != 1)
2550 continue;
2551 break;
2553 case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements
2554 {
2555 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
2556 if (!achievement)
2557 continue;
2558 if (achievement->Category != CATEGORY_CHILDRENS_WEEK && achievement->ID != 1785)
2559 continue;
2560 break;
2561 }
2562 default: // type not use DB data, ignore
2563 continue;
2564 }
2565
2567 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` does not contain expected data for criteria (Entry: {} Type: {}) for achievement {}.", criteria->ID, criteria->Type, criteria->AchievementID);
2568 }
2569
2570 TC_LOG_INFO("server.loading", ">> Loaded {} additional achievement criteria data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2571}
2572
2574{
2575 uint32 oldMSTime = getMSTime();
2576
2577 // Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer
2578 // while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added
2579 // instead the only potential race will happen on value associated with the key
2580 for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
2581 if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
2583 _allCompletedAchievements[achievement->ID] = SystemTimePoint::min();
2584
2585 QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
2586
2587 if (!result)
2588 {
2589 TC_LOG_INFO("server.loading", ">> Loaded 0 realm first completed achievements. DB table `character_achievement` is empty.");
2590 return;
2591 }
2592
2593 do
2594 {
2595 Field* fields = result->Fetch();
2596
2597 uint16 achievementId = fields[0].GetUInt16();
2598 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId);
2599 if (!achievement)
2600 {
2601 // Remove non-existing achievements from all characters
2602 TC_LOG_ERROR("achievement", "Non-existing achievement {} data has been removed from the table `character_achievement`.", achievementId);
2603
2605 stmt->setUInt16(0, uint16(achievementId));
2606 CharacterDatabase.Execute(stmt);
2607
2608 continue;
2609 }
2611 _allCompletedAchievements[achievementId] = SystemTimePoint::max();
2612 }
2613 while (result->NextRow());
2614
2615 TC_LOG_INFO("server.loading", ">> Loaded {} realm first completed achievements in {} ms.", (unsigned long)_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
2616}
2617
2619{
2620 uint32 oldMSTime = getMSTime();
2621
2622 _achievementRewards.clear(); // need for reload case
2623
2624 // 0 1 2 3 4 5 6 7
2625 QueryResult result = WorldDatabase.Query("SELECT ID, TitleA, TitleH, ItemID, Sender, Subject, Body, MailTemplateID FROM achievement_reward");
2626
2627 if (!result)
2628 {
2629 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement rewards. DB table `achievement_reward` is empty.");
2630 return;
2631 }
2632
2633 do
2634 {
2635 Field* fields = result->Fetch();
2636 uint32 id = fields[0].GetUInt32();
2637 AchievementEntry const* achievement = sAchievementStore.LookupEntry(id);
2638 if (!achievement)
2639 {
2640 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement ID ({}), ignored.", id);
2641 continue;
2642 }
2643
2644 AchievementReward reward;
2645 reward.TitleId[0] = fields[1].GetUInt32();
2646 reward.TitleId[1] = fields[2].GetUInt32();
2647 reward.ItemId = fields[3].GetUInt32();
2648 reward.SenderCreatureId = fields[4].GetUInt32();
2649 reward.Subject = fields[5].GetString();
2650 reward.Body = fields[6].GetString();
2651 reward.MailTemplateId = fields[7].GetUInt32();
2652
2653 // must be title or mail at least
2654 if (!reward.TitleId[0] && !reward.TitleId[1] && !reward.SenderCreatureId)
2655 {
2656 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not contain title or item reward data. Ignored.", id);
2657 continue;
2658 }
2659
2660 if (achievement->Faction == ACHIEVEMENT_FACTION_ANY && (!reward.TitleId[0] ^ !reward.TitleId[1]))
2661 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) contains the title (A: {} H: {}) for only one team.", id, reward.TitleId[0], reward.TitleId[1]);
2662
2663 if (reward.TitleId[0])
2664 {
2665 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[0]);
2666 if (!titleEntry)
2667 {
2668 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: {}) contains an invalid title id ({}) in `title_A`, set to 0", id, reward.TitleId[0]);
2669 reward.TitleId[0] = 0;
2670 }
2671 }
2672
2673 if (reward.TitleId[1])
2674 {
2675 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[1]);
2676 if (!titleEntry)
2677 {
2678 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: {}) contains an invalid title id ({}) in `title_H`, set to 0", id, reward.TitleId[1]);
2679 reward.TitleId[1] = 0;
2680 }
2681 }
2682
2683 //check mail data before item for report including wrong item case
2684 if (reward.SenderCreatureId)
2685 {
2686 if (!sObjectMgr->GetCreatureTemplate(reward.SenderCreatureId))
2687 {
2688 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) contains an invalid creature ID {} as sender, mail reward skipped.", id, reward.SenderCreatureId);
2689 reward.SenderCreatureId = 0;
2690 }
2691 }
2692 else
2693 {
2694 if (reward.ItemId)
2695 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but contains an item reward. Item will not be rewarded.", id);
2696
2697 if (!reward.Subject.empty())
2698 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but contains a mail subject.", id);
2699
2700 if (!reward.Body.empty())
2701 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but contains mail text.", id);
2702
2703 if (reward.MailTemplateId)
2704 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but has a MailTemplate.", id);
2705 }
2706
2707 if (reward.MailTemplateId)
2708 {
2709 if (!sMailTemplateStore.LookupEntry(reward.MailTemplateId))
2710 {
2711 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) is using an invalid MailTemplate ({}).", id, reward.MailTemplateId);
2712 reward.MailTemplateId = 0;
2713 }
2714 else if (!reward.Subject.empty() || !reward.Body.empty())
2715 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) is using MailTemplate ({}) and mail subject/text.", id, reward.MailTemplateId);
2716 }
2717
2718 if (reward.ItemId)
2719 {
2720 if (!sObjectMgr->GetItemTemplate(reward.ItemId))
2721 {
2722 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) contains an invalid item id {}, reward mail will not contain the rewarded item.", id, reward.ItemId);
2723 reward.ItemId = 0;
2724 }
2725 }
2726
2727 _achievementRewards[id] = reward;
2728 } while (result->NextRow());
2729
2730 TC_LOG_INFO("server.loading", ">> Loaded {} achievement rewards in {} ms.", uint32(_achievementRewards.size()), GetMSTimeDiffToNow(oldMSTime));
2731}
2732
2734{
2735 uint32 oldMSTime = getMSTime();
2736
2737 _achievementRewardLocales.clear(); // need for reload case
2738
2739 // 0 1 2 3
2740 QueryResult result = WorldDatabase.Query("SELECT ID, Locale, Subject, Body FROM achievement_reward_locale");
2741
2742 if (!result)
2743 {
2744 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `achievement_reward_locale` is empty.");
2745 return;
2746 }
2747
2748 do
2749 {
2750 Field* fields = result->Fetch();
2751
2752 uint32 id = fields[0].GetUInt32();
2753 std::string localeName = fields[1].GetString();
2754
2755 LocaleConstant locale = GetLocaleByName(localeName);
2756 if (locale == LOCALE_enUS)
2757 continue;
2758
2759 if (_achievementRewards.find(id) == _achievementRewards.end())
2760 {
2761 TC_LOG_ERROR("sql.sql", "Table `achievement_reward_locale` (ID: {}) contains locale strings for a non-existing achievement reward.", id);
2762 continue;
2763 }
2764
2766 ObjectMgr::AddLocaleString(fields[2].GetString(), locale, data.Subject);
2767 ObjectMgr::AddLocaleString(fields[3].GetString(), locale, data.Text);
2768 } while (result->NextRow());
2769
2770 TC_LOG_INFO("server.loading", ">> Loaded {} achievement reward locale strings in {} ms.", uint32(_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
2771}
bool IsAchievementCriteriaTypeStoredByMiscValue(AchievementCriteriaTypes type)
static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT]
ProgressType
@ PROGRESS_SET
@ PROGRESS_ACCUMULATE
@ PROGRESS_HIGHEST
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_NTH_BIRTHDAY
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_KNOWN_TITLE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_GAME_EVENT
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPPED_ITEM
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_PLAYER_CLASS_RACE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD
@ MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE
@ ACHIEVEMENT_CRITERIA_DATA_TYPE_S_ITEM_QUALITY
std::vector< AchievementCriteriaEntry const * > AchievementCriteriaEntryList
#define sAchievementMgr
std::vector< AchievementEntry const * > AchievementEntryList
#define sArenaTeamMgr
#define MAX_ARENA_SLOT
Definition ArenaTeam.h:114
@ CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS_BY_CRITERIA
@ CHAR_INS_CHAR_ACHIEVEMENT_PROGRESS
@ CHAR_INS_CHAR_ACHIEVEMENT
@ CHAR_DEL_CHAR_ACHIEVEMENT_BY_ACHIEVEMENT
@ CHAR_DEL_INVALID_ACHIEVMENT
@ CHAR_DEL_CHAR_ACHIEVEMENT_PROGRESS
@ CHAR_DEL_INVALID_ACHIEV_PROGRESS_CRITERIA
@ CHAR_DEL_CHAR_ACHIEVEMENT
LocaleConstant GetLocaleByName(const std::string &name)
Definition Common.cpp:33
LocaleConstant
Definition Common.h:48
@ LOCALE_enUS
Definition Common.h:49
@ IN_MILLISECONDS
Definition Common.h:35
@ DAY
Definition Common.h:31
@ ACHIEVEMENT_FACTION_HORDE
Definition DBCEnums.h:75
@ ACHIEVEMENT_FACTION_ALLIANCE
Definition DBCEnums.h:76
@ ACHIEVEMENT_FACTION_ANY
Definition DBCEnums.h:77
@ RAID_DIFFICULTY_25MAN_HEROIC
Definition DBCEnums.h:289
@ RAID_DIFFICULTY_25MAN_NORMAL
Definition DBCEnums.h:287
AchievementCriteriaTimedTypes
Definition DBCEnums.h:121
@ ACHIEVEMENT_TIMED_TYPE_MAX
Definition DBCEnums.h:129
AchievementCriteriaCondition
Definition DBCEnums.h:97
@ ACHIEVEMENT_CRITERIA_CONDITION_NONE
Definition DBCEnums.h:98
@ ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP
Definition DBCEnums.h:104
@ ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE
Definition DBCEnums.h:102
@ ACHIEVEMENT_CRITERIA_CONDITION_MAX
Definition DBCEnums.h:107
@ ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP
Definition DBCEnums.h:101
#define MAX_DIFFICULTY
Definition DBCEnums.h:294
@ ACHIEVEMENT_FLAG_COUNTER
Definition DBCEnums.h:82
@ ACHIEVEMENT_FLAG_HIDDEN
Definition DBCEnums.h:83
@ ACHIEVEMENT_FLAG_REALM_FIRST_REACH
Definition DBCEnums.h:90
@ ACHIEVEMENT_FLAG_REALM_FIRST_KILL
Definition DBCEnums.h:91
@ ACHIEVEMENT_FLAG_SUMM
Definition DBCEnums.h:85
AchievementCriteriaTypes
Definition DBCEnums.h:133
@ ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION
Definition DBCEnums.h:203
@ ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE
Definition DBCEnums.h:229
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER
Definition DBCEnums.h:216
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE
Definition DBCEnums.h:141
@ ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM
Definition DBCEnums.h:167
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY
Definition DBCEnums.h:140
@ ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN
Definition DBCEnums.h:228
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED
Definition DBCEnums.h:207
@ ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL
Definition DBCEnums.h:137
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL
Definition DBCEnums.h:190
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT
Definition DBCEnums.h:139
@ ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET
Definition DBCEnums.h:154
@ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM
Definition DBCEnums.h:183
@ ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA
Definition DBCEnums.h:159
@ ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT
Definition DBCEnums.h:195
@ ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING
Definition DBCEnums.h:151
@ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL
Definition DBCEnums.h:155
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED
Definition DBCEnums.h:222
@ ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM
Definition DBCEnums.h:168
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR
Definition DBCEnums.h:219
@ ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP
Definition DBCEnums.h:174
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST
Definition DBCEnums.h:143
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS
Definition DBCEnums.h:202
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND
Definition DBCEnums.h:144
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH
Definition DBCEnums.h:215
@ ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK
Definition DBCEnums.h:170
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID
Definition DBCEnums.h:148
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT
Definition DBCEnums.h:177
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER
Definition DBCEnums.h:189
@ ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT
Definition DBCEnums.h:192
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CAST
Definition DBCEnums.h:224
@ ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE
Definition DBCEnums.h:180
@ ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS
Definition DBCEnums.h:205
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED
Definition DBCEnums.h:226
@ ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM
Definition DBCEnums.h:162
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION
Definition DBCEnums.h:173
@ ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS
Definition DBCEnums.h:235
@ ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED
Definition DBCEnums.h:227
@ ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP
Definition DBCEnums.h:145
@ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL
Definition DBCEnums.h:160
@ ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT
Definition DBCEnums.h:171
@ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS
Definition DBCEnums.h:198
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED
Definition DBCEnums.h:214
@ ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL
Definition DBCEnums.h:136
@ ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL
Definition DBCEnums.h:232
@ ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE
Definition DBCEnums.h:181
@ ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE
Definition DBCEnums.h:201
@ ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM
Definition DBCEnums.h:152
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION
Definition DBCEnums.h:208
@ ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD
Definition DBCEnums.h:187
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED
Definition DBCEnums.h:225
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER
Definition DBCEnums.h:150
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING
Definition DBCEnums.h:188
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_AURA
Definition DBCEnums.h:193
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER
Definition DBCEnums.h:218
@ ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM
Definition DBCEnums.h:211
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING
Definition DBCEnums.h:220
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT
Definition DBCEnums.h:138
@ ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL
Definition DBCEnums.h:161
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION
Definition DBCEnums.h:172
@ ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2
Definition DBCEnums.h:230
@ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE
Definition DBCEnums.h:231
@ ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS
Definition DBCEnums.h:185
@ ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE
Definition DBCEnums.h:142
@ ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED
Definition DBCEnums.h:223
@ ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST
Definition DBCEnums.h:153
@ ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
Definition DBCEnums.h:163
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT
Definition DBCEnums.h:217
@ ACHIEVEMENT_CRITERIA_TYPE_HK_RACE
Definition DBCEnums.h:179
@ ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS
Definition DBCEnums.h:210
@ ACHIEVEMENT_CRITERIA_TYPE_DEATH
Definition DBCEnums.h:146
@ ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA
Definition DBCEnums.h:169
@ ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS
Definition DBCEnums.h:184
@ ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS
Definition DBCEnums.h:234
@ ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL
Definition DBCEnums.h:166
@ ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE
Definition DBCEnums.h:149
@ ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM
Definition DBCEnums.h:175
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID
Definition DBCEnums.h:204
@ ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE
Definition DBCEnums.h:134
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD
Definition DBCEnums.h:206
@ ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON
Definition DBCEnums.h:147
@ ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL
Definition DBCEnums.h:199
@ ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS
Definition DBCEnums.h:233
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT
Definition DBCEnums.h:221
@ ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA
Definition DBCEnums.h:157
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING
Definition DBCEnums.h:164
@ ACHIEVEMENT_CRITERIA_TYPE_WIN_BG
Definition DBCEnums.h:135
@ ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION
Definition DBCEnums.h:209
@ ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL
Definition DBCEnums.h:194
@ ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE
Definition DBCEnums.h:156
@ ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS
Definition DBCEnums.h:182
@ ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY
Definition DBCEnums.h:191
@ ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA
Definition DBCEnums.h:158
@ ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS
Definition DBCEnums.h:186
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT
Definition DBCEnums.h:176
@ ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM
Definition DBCEnums.h:212
@ ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING
Definition DBCEnums.h:165
@ ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS
Definition DBCEnums.h:178
@ ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED
Definition DBCEnums.h:213
@ ACHIEVEMENT_CRITERIA_TYPE_ON_LOGIN
Definition DBCEnums.h:197
@ ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL
Definition DBCEnums.h:200
#define MAX_CRITERIA_REQUIREMENTS
Definition DBCEnums.h:94
@ CATEGORY_CHILDRENS_WEEK
Definition DBCEnums.h:242
@ STRONG_MAX_LEVEL
Definition DBCEnums.h:53
#define ACHIEVEMENT_CRITERIA_TYPE_TOTAL
Definition DBCEnums.h:238
DBCStorage< AchievementCriteriaEntry > sAchievementCriteriaStore(AchievementCriteriafmt)
DBCStorage< CharTitlesEntry > sCharTitlesStore(CharTitlesEntryfmt)
DBCStorage< MailTemplateEntry > sMailTemplateStore(MailTemplateEntryfmt)
DBCStorage< HolidaysEntry > sHolidaysStore(Holidaysfmt)
DBCStorage< AchievementEntry > sAchievementStore(Achievementfmt)
DBCStorage< WorldMapOverlayEntry > sWorldMapOverlayStore(WorldMapOverlayEntryfmt)
DBCStorage< MapEntry > sMapStore(MapEntryfmt)
DBCStorage< AreaTableEntry > sAreaTableStore(AreaTableEntryfmt)
#define MAX_WORLD_MAP_OVERLAY_AREA_IDX
SQLTransaction< CharacterDatabaseConnection > CharacterDatabaseTransaction
std::shared_ptr< ResultSet > QueryResult
std::shared_ptr< PreparedResultSet > PreparedQueryResult
DatabaseWorkerPool< CharacterDatabaseConnection > CharacterDatabase
Accessor to the character database.
DatabaseWorkerPool< WorldDatabaseConnection > WorldDatabase
Accessor to the world database.
uint8_t uint8
Definition Define.h:135
int32_t int32
Definition Define.h:129
uint16_t uint16
Definition Define.h:134
uint32_t uint32
Definition Define.h:133
@ DISABLE_TYPE_ACHIEVEMENT_CRITERIA
Definition DisableMgr.h:31
std::chrono::minutes Minutes
Minutes shorthand typedef.
Definition Duration.h:30
#define ASSERT
Definition Errors.h:68
bool IsHolidayActive(HolidayIds id)
bool IsEventActive(uint16 eventId)
#define sGameEventMgr
#define sGuildMgr
Definition GuildMgr.h:59
@ BROADCAST_TEXT_ACHIEVEMENT_EARNED
Definition Language.h:23
#define TC_LOG_DEBUG(filterType__,...)
Definition Log.h:156
#define TC_LOG_TRACE(filterType__,...)
Definition Log.h:153
#define TC_LOG_ERROR(filterType__,...)
Definition Log.h:165
#define TC_LOG_INFO(filterType__,...)
Definition Log.h:159
@ MAIL_CREATURE
Definition Mail.h:40
#define sMapMgr
Definition MapManager.h:211
@ TYPEID_UNIT
Definition ObjectGuid.h:38
@ TYPEID_PLAYER
Definition ObjectGuid.h:39
#define sObjectMgr
Definition ObjectMgr.h:1721
#define MAX_DRUNKEN
Definition Player.h:342
@ AT_LOGIN_FIRST
Definition Player.h:486
#define PLAYER_EXPLORED_ZONES_SIZE
Definition Player.h:119
DrunkenState
Definition Player.h:335
std::set< uint32 > RewardedQuestSet
Definition Player.h:493
Role Based Access Control related classes definition.
#define sScriptMgr
Definition ScriptMgr.h:1168
SpellEffIndex
Gender
@ GENDER_NONE
@ MAX_ITEM_QUALITY
@ ITEM_QUALITY_EPIC
@ TEAM_ALLIANCE
@ TEAM_HORDE
@ ALLIANCE
@ HORDE
@ CHAT_MSG_GUILD_ACHIEVEMENT
@ CHAT_MSG_ACHIEVEMENT
#define CLASSMASK_ALL_PLAYABLE
HolidayIds
#define RACEMASK_ALL_PLAYABLE
#define sSpellMgr
Definition SpellMgr.h:738
std::pair< SkillLineAbilityMap::const_iterator, SkillLineAbilityMap::const_iterator > SkillLineAbilityMapBounds
Definition SpellMgr.h:537
uint32 GetMSTimeDiffToNow(uint32 oldMSTime)
Definition Timer.h:57
uint32 getMSTime()
Definition Timer.h:33
@ PLAYER_EXPLORED_ZONES_1
@ PLAYER_FIELD_LIFETIME_HONORABLE_KILLS
bool CompareValues(ComparisionType type, T val1, T val2)
Definition Util.h:532
ComparisionType
Definition Util.h:522
@ COMP_TYPE_MAX
Definition Util.h:528
AchievementCriteriaDataSet const * GetCriteriaDataSet(AchievementCriteriaEntry const *achievementCriteria) const
AchievementCriteriaEntryList const & GetAchievementCriteriaByType(AchievementCriteriaTypes type, uint32 miscValue) const
static AchievementGlobalMgr * instance()
AchievementRewards _achievementRewards
AchievementRewardLocales _achievementRewardLocales
AchievementCriteriaDataMap _criteriaDataMap
bool IsRealmCompleted(AchievementEntry const *achievement) const
AchievementCriteriaEntryList _achievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]
AchievementCriteriaListByCondition _achievementCriteriasByCondition[ACHIEVEMENT_CRITERIA_CONDITION_MAX]
AchievementCriteriaEntryList _achievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]
void SetRealmCompleted(AchievementEntry const *achievement)
static char const * GetCriteriaTypeString(AchievementCriteriaTypes type)
static AchievementCriteriaEntryList const EmptyCriteriaList
AchievementCriteriaListByMiscValue _achievementCriteriasByMiscalue[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]
std::unordered_map< uint32, SystemTimePoint > _allCompletedAchievements
AchievementListByReferencedId _achievementListByReferencedId
AchievementCriteriaListByAchievement _achievementCriteriaListByAchievement
void SaveToDB(CharacterDatabaseTransaction trans)
Player * GetPlayer() const
CriteriaProgress * GetCriteriaProgress(AchievementCriteriaEntry const *entry)
void UpdateTimedAchievements(uint32 timeDiff)
void CompletedCriteriaFor(AchievementEntry const *achievement)
bool RequirementsSatisfied(AchievementCriteriaEntry const *criteria, AchievementEntry const *achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const *ref) const
void StartTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry, uint32 timeLost=0)
bool HasAchieved(uint32 achievementId) const
CriteriaProgressMap m_criteriaProgress
void ResetAchievementCriteria(AchievementCriteriaCondition condition, uint32 value, bool evenIfCriteriaComplete)
bool ConditionsSatisfied(AchievementCriteriaEntry const *criteria) const
void CompletedAchievement(AchievementEntry const *entry)
uint32 m_achievementPoints
bool CanUpdateCriteria(AchievementCriteriaEntry const *criteria, AchievementEntry const *achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const *ref)
void SetCriteriaProgress(AchievementCriteriaEntry const *entry, uint32 changeValue, ProgressType ptype=PROGRESS_SET)
CompletedAchievementMap m_completedAchievements
void SendCriteriaUpdate(AchievementCriteriaEntry const *entry, CriteriaProgress const *progress, uint32 timeElapsed, bool timedCompleted) const
bool IsCompletedCriteria(AchievementCriteriaEntry const *achievementCriteria, AchievementEntry const *achievement)
void SendAllAchievementData() const
static void DeleteFromDB(ObjectGuid lowguid)
bool IsCompletedAchievement(AchievementEntry const *entry)
void BuildAllDataPacket(Player const *receiver, WorldPackets::Achievement::AllAchievements *data) const
void CheckAllAchievementCriteria()
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult)
void SendRespondInspectAchievements(Player *player) const
void SendCriteriaProgressRemoved(uint32 criteriaId) const
AchievementMgr(Player *player)
void SendAchievementEarned(AchievementEntry const *achievement) const
void RemoveCriteriaProgress(AchievementCriteriaEntry const *criteria)
void RemoveTimedAchievement(AchievementCriteriaTimedTypes type, uint32 entry)
TimedAchievementMap m_timedAchievements
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1=0, uint32 miscValue2=0, WorldObject *ref=nullptr)
ArenaTeamStats const & GetStats() const
Definition ArenaTeam.h:135
ArenaTeamMember * GetMember(ObjectGuid guid)
uint32 GetType() const
Definition ArenaTeam.h:129
static uint8 GetSlotByType(uint32 type)
uint8 GetArenaType() const
bool isArena() const
uint32 GetTeamScore(uint32 TeamID) const
Class used to access individual fields of database query result.
Definition Field.h:92
uint8 GetUInt8() const
Definition Field.cpp:29
std::string GetString() const
Definition Field.cpp:125
uint16 GetUInt16() const
Definition Field.cpp:45
uint32 GetUInt32() const
Definition Field.cpp:61
std::vector< GameEventData > GameEventDataMap
Definition Guild.h:284
uint32 GetMaxPlayers() const
Definition Map.cpp:4291
InstanceScript * GetInstanceScript()
Definition Map.h:907
virtual bool CheckAchievementCriteriaMeet(uint32, Player const *, Unit const *=nullptr, uint32=0)
Definition Item.h:62
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:329
static Item * CreateItem(uint32 itemEntry, uint32 count, Player const *player=nullptr)
Definition Item.cpp:1050
void SendMailTo(CharacterDatabaseTransaction trans, MailReceiver const &receiver, MailSender const &sender, MailCheckMask checked=MAIL_CHECK_MASK_NONE, uint32 deliver_delay=0)
Definition Mail.cpp:188
MailDraft & AddItem(Item *item)
Definition Mail.cpp:90
Definition Map.h:302
bool IsDungeon() const
Definition Map.cpp:4231
uint8 GetSpawnMode() const
Definition Map.h:409
bool IsRaid() const
Definition Map.cpp:4241
bool Is25ManRaid() const
Definition Map.cpp:4256
uint32 GetPlayersCountExceptGMs() const
Definition Map.cpp:3659
uint32 GetId() const
Definition Map.cpp:4216
InstanceMap * ToInstanceMap()
Definition Map.h:540
LowType GetCounter() const
Definition ObjectGuid.h:156
std::string ToString() const
static std::string_view GetLocaleString(std::vector< std::string > const &data, LocaleConstant locale)
Definition ObjectMgr.h:1519
static void AddLocaleString(std::string &&value, LocaleConstant localeConstant, std::vector< std::string > &data)
static Unit * ToUnit(Object *o)
Definition Object.h:195
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:241
bool IsInWorld() const
Definition Object.h:73
TypeID GetTypeId() const
Definition Object.h:93
uint32 GetEntry() const
Definition Object.h:81
static ObjectGuid GetGUID(Object const *o)
Definition Object.h:78
static Player * ToPlayer(Object *o)
Definition Object.h:183
uint32 GetTeam() const
Definition Player.h:1818
RewardedQuestSet const & getRewardedQuests() const
Definition Player.h:1398
uint8 GetDrunkValue() const
Definition Player.h:1869
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6163
bool HasTitle(uint32 bitIndex) const
Definition Player.cpp:24276
WorldSession * GetSession() const
Definition Player.h:1705
static uint32 TeamForRace(uint8 race)
Definition Player.cpp:6271
TeamId GetTeamId() const
Definition Player.h:1819
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:1518
uint32 GetArenaTeamId(uint8 slot) const
Definition Player.h:1615
Battleground * GetBattleground() const
Definition Player.cpp:23024
Group * GetGroup()
Definition Player.h:2159
bool IsGameMaster() const
Definition Player.h:976
void SetTitle(CharTitlesEntry const *title, bool lost=false)
Definition Player.cpp:24291
ReputationMgr & GetReputationMgr()
Definition Player.h:1834
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition Player.cpp:865
void setUInt16(uint8 index, uint16 value)
void setUInt32(uint8 index, uint32 value)
int32 GetZoneOrSort() const
Definition QuestDef.h:230
int32 GetReputation(uint32 faction_id) const
AuraType ApplyAuraName
Definition SpellInfo.h:211
SpellEffectInfo const & GetEffect(SpellEffIndex index) const
Definition SpellInfo.h:483
Definition Unit.h:783
bool HealthAbovePct(int32 pct) const
Definition Unit.h:933
uint8 GetClass() const
Definition Unit.h:909
Gender GetGender() const
Definition Unit.h:912
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4528
uint8 GetLevel() const
Definition Unit.h:903
uint8 GetRace() const
Definition Unit.h:906
uint32 GetMapId() const
Definition Position.h:193
Map * GetMap() const
Definition Object.h:451
std::string const & GetName() const
Definition Object.h:384
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition Object.h:377
LocaleConstant GetSessionDbLocaleIndex() const
Minutes GetTimezoneOffset() const
bool HasPermission(uint32 permissionId)
void SetUtcTimeFromUnixTime(std::time_t unixTime)
Definition WowTime.cpp:86
#define sWorld
Definition World.h:901
@ CONFIG_BIRTHDAY_TIME
Definition World.h:382
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:190
bool IsDisabledFor(DisableType type, uint32 entry, WorldObject const *ref, uint8 flags)
WowTime const * GetUtcWowTime()
Definition GameTime.cpp:67
SystemTimePoint GetSystemTime()
Current chrono system_clock time point.
Definition GameTime.cpp:52
time_t GetGameTime()
Definition GameTime.cpp:42
@ RBAC_PERM_CANNOT_EARN_REALM_FIRST_ACHIEVEMENTS
Definition RBAC.h:62
@ RBAC_PERM_CANNOT_EARN_ACHIEVEMENTS
Definition RBAC.h:61
void Add(AchievementCriteriaData const &data)
bool Meets(Player const *source, WorldObject const *target, uint32 miscValue1=0, uint32 miscValue2=0) const
struct AchievementCriteriaData::@5::@24 birthday_login
struct AchievementCriteriaData::@5::@26 game_event
bool IsValid(AchievementCriteriaEntry const *criteria)
bool Meets(uint32 criteria_id, Player const *source, WorldObject const *target, uint32 miscValue1=0, uint32 miscValue2=0) const
struct AchievementCriteriaData::@5::@10 player_dead
struct AchievementCriteriaData::@5::@21 bg_loss_team_score
struct AchievementCriteriaData::@5::@9 health
struct AchievementCriteriaData::@5::@14 level
AchievementCriteriaDataType dataType
struct AchievementCriteriaData::@5::@7 creature
struct AchievementCriteriaData::@5::@27 item
struct AchievementCriteriaData::@5::@22 equipped_item
struct AchievementCriteriaData::@5::@19 drunk
struct AchievementCriteriaData::@5::@8 classRace
struct AchievementCriteriaData::@5::@12 area
struct AchievementCriteriaData::@5::@25 known_title
struct AchievementCriteriaData::@5::@17 map_players
struct AchievementCriteriaData::@5::@20 holiday
struct AchievementCriteriaData::@5::@11 aura
union AchievementCriteriaEntry::@279 Asset
struct AchievementCriteriaEntry::@280 AdditionalRequirements[MAX_CRITERIA_REQUIREMENTS]
std::vector< std::string > Text
std::vector< std::string > Subject
static void VisitWorldObjects(WorldObject const *obj, T &visitor, float radius, bool dont_load=true)
Definition CellImpl.h:180
uint32 GetBaseItemLevel() const
uint32 GetQuality() const
uint32 AreaID[MAX_WORLD_MAP_OVERLAY_AREA_IDX]
std::vector< CriteriaProgress > Progress
std::vector< EarnedAchievement > Earned