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 "ArenaTeamMgr.h"
20#include "Battleground.h"
21#include "CellImpl.h"
22#include "ChatTextBuilder.h"
23#include "DatabaseEnv.h"
24#include "DBCEnums.h"
25#include "DisableMgr.h"
26#include "GameEventMgr.h"
27#include "GameTime.h"
28#include "GridNotifiersImpl.h"
29#include "Guild.h"
30#include "GuildMgr.h"
31#include "InstanceScript.h"
32#include "Item.h"
33#include "Language.h"
34#include "Log.h"
35#include "Mail.h"
36#include "Map.h"
37#include "MapManager.h"
38#include "ObjectMgr.h"
39#include "Player.h"
40#include "RBAC.h"
41#include "ReputationMgr.h"
42#include "ScriptMgr.h"
43#include "SpellInfo.h"
44#include "SpellMgr.h"
45#include "World.h"
46#include "WorldSession.h"
47#include "WowTime.h"
48
50{
52 {
53 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` for criteria (Entry: {}) contains a wrong data type ({}), ignored.", criteria->ID, dataType);
54 return false;
55 }
56
57 switch (criteria->Type)
58 {
64 case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST: // only hardcoded list
79 case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST: // only Children's Week achievements
80 case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements
86 break;
87 default:
89 {
90 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for a non-supported criteria type (Entry: {} Type: {}), ignored.", criteria->ID, criteria->Type);
91 return false;
92 }
93 break;
94 }
95
96 switch (dataType)
97 {
101 return true;
103 if (!creature.id || !sObjectMgr->GetCreatureTemplate(creature.id))
104 {
105 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.",
106 criteria->ID, criteria->Type, dataType, creature.id);
107 return false;
108 }
109 return true;
111 if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
112 {
113 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.",
114 criteria->ID, criteria->Type, dataType, classRace.class_id);
115 return false;
116 }
117 if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
118 {
119 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.",
120 criteria->ID, criteria->Type, dataType, classRace.race_id);
121 return false;
122 }
123 return true;
125 if (health.percent < 1 || health.percent > 100)
126 {
127 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.",
128 criteria->ID, criteria->Type, dataType, health.percent);
129 return false;
130 }
131 return true;
133 if (player_dead.own_team_flag > 1)
134 {
135 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 ({}).",
136 criteria->ID, criteria->Type, dataType, player_dead.own_team_flag);
137 return false;
138 }
139 return true;
142 {
143 SpellInfo const* spellEntry = sSpellMgr->GetSpellInfo(aura.spell_id);
144 if (!spellEntry)
145 {
146 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a wrong spell id in value1 ({}), ignored.",
147 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);
148 return false;
149 }
150 if (aura.effect_idx >= 3)
151 {
152 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a wrong spell effect index in value2 ({}), ignored.",
153 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);
154 return false;
155 }
156 if (!spellEntry->GetEffect(SpellEffIndex(aura.effect_idx)).ApplyAuraName)
157 {
158 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains a non-aura spell effect (ID: {} Effect: {}), ignored.",
159 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);
160 return false;
161 }
162 return true;
163 }
165 if (!sAreaTableStore.LookupEntry(area.id))
166 {
167 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.",
168 criteria->ID, criteria->Type, dataType, area.id);
169 return false;
170 }
171 return true;
173 if (value.compType >= COMP_TYPE_MAX)
174 {
175 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.",
176 criteria->ID, criteria->Type, dataType, value.compType);
177 return false;
178 }
179 return true;
181 if (level.minlevel > STRONG_MAX_LEVEL)
182 {
183 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.",
184 criteria->ID, criteria->Type, dataType, level.minlevel);
185 return false;
186 }
187 return true;
189 if (gender.gender > GENDER_NONE)
190 {
191 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.",
192 criteria->ID, criteria->Type, dataType, gender.gender);
193 return false;
194 }
195 return true;
197 if (!ScriptId)
198 {
199 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.",
200 criteria->ID, criteria->Type, dataType);
201 return false;
202 }
203 return true;
205 if (difficulty.difficulty >= MAX_DIFFICULTY)
206 {
207 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.",
208 criteria->ID, criteria->Type, dataType, difficulty.difficulty);
209 return false;
210 }
211 return true;
213 if (map_players.maxcount <= 0)
214 {
215 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.",
216 criteria->ID, criteria->Type, dataType, map_players.maxcount);
217 return false;
218 }
219 return true;
221 if (team.team != ALLIANCE && team.team != HORDE)
222 {
223 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.",
224 criteria->ID, criteria->Type, dataType, team.team);
225 return false;
226 }
227 return true;
229 if (drunk.state >= MAX_DRUNKEN)
230 {
231 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.",
232 criteria->ID, criteria->Type, dataType, drunk.state);
233 return false;
234 }
235 return true;
237 if (!sHolidaysStore.LookupEntry(holiday.id))
238 {
239 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.",
240 criteria->ID, criteria->Type, dataType, holiday.id);
241 return false;
242 }
243 return true;
245 {
246 GameEventMgr::GameEventDataMap const& events = sGameEventMgr->GetEventMap();
247 if (game_event.id < 1 || game_event.id >= events.size())
248 {
249 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.",
250 criteria->ID, criteria->Type, dataType, game_event.id);
251 return false;
252 }
253 return true;
254 }
256 return true; // not check correctness node indexes
259 if (equipped_item.item_quality >= MAX_ITEM_QUALITY)
260 {
261 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` (Entry: {} Type: {}) for data type {} ({}) contains an unknown quality state value in value1 ({}), ignored.",
262 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);
263 return false;
264 }
265 return true;
267 if (!sMapStore.LookupEntry(map_id.mapId))
268 {
269 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.",
270 criteria->ID, criteria->Type, dataType, map_id.mapId);
271 return false;
272 }
273 return true;
275 if (!classRace.class_id && !classRace.race_id)
276 {
277 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.",
278 criteria->ID, criteria->Type, dataType);
279 return false;
280 }
281 if (classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE) == 0)
282 {
283 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.",
284 criteria->ID, criteria->Type, dataType, classRace.class_id);
285 return false;
286 }
287 if (classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE) == 0)
288 {
289 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.",
290 criteria->ID, criteria->Type, dataType, classRace.race_id);
291 return false;
292 }
293 return true;
295 if (!sCharTitlesStore.LookupEntry(known_title.title_id))
296 {
297 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.",
298 criteria->ID, criteria->Type, dataType, known_title.title_id);
299 return false;
300 }
301 return true;
302 default:
303 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);
304 return false;
305 }
306}
307
308bool AchievementCriteriaData::Meets(uint32 criteria_id, Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
309{
310 switch (dataType)
311 {
313 return true;
315 if (!target || target->GetTypeId() != TYPEID_UNIT)
316 return false;
317 return target->GetEntry() == creature.id;
319 if (!target || target->GetTypeId() != TYPEID_PLAYER)
320 return false;
321 if (classRace.class_id && classRace.class_id != target->ToPlayer()->GetClass())
322 return false;
323 if (classRace.race_id && classRace.race_id != target->ToPlayer()->GetRace())
324 return false;
325 return true;
327 if (source->GetTypeId() != TYPEID_PLAYER)
328 return false;
329 if (classRace.class_id && classRace.class_id != source->ToPlayer()->GetClass())
330 return false;
331 if (classRace.race_id && classRace.race_id != source->ToPlayer()->GetRace())
332 return false;
333 return true;
335 if (!target || target->GetTypeId() != TYPEID_PLAYER)
336 return false;
337 return !target->ToPlayer()->HealthAbovePct(health.percent);
339 if (!target || target->GetTypeId() != TYPEID_PLAYER)
340 return false;
341 if (Player const* player = target->ToPlayer())
342 if (!player->IsAlive() && player->GetDeathTimer() != 0)
343 // flag set == must be same team, not set == different team
344 return (player->GetTeam() == source->GetTeam()) == (player_dead.own_team_flag != 0);
345 return false;
347 return source->HasAuraEffect(aura.spell_id, aura.effect_idx);
349 {
350 uint32 zone_id, area_id;
351 source->GetZoneAndAreaId(zone_id, area_id);
352 return area.id == zone_id || area.id == area_id;
353 }
355 {
356 if (!target)
357 return false;
358 Unit const* unitTarget = target->ToUnit();
359 if (!unitTarget)
360 return false;
361 return unitTarget->HasAuraEffect(aura.spell_id, aura.effect_idx);
362 }
364 return CompareValues(ComparisionType(value.compType), miscValue1, value.value);
366 {
367 if (!target)
368 return false;
369 Unit const* unitTarget = target->ToUnit();
370 if (!unitTarget)
371 return false;
372 return unitTarget->GetLevel() >= level.minlevel;
373 }
375 {
376 if (!target)
377 return false;
378 Unit const* unitTarget = target->ToUnit();
379 if (!unitTarget)
380 return false;
381 return unitTarget->GetGender() == Gender(gender.gender);
382 }
384 {
385 Unit const* unitTarget = nullptr;
386 if (target)
387 unitTarget = target->ToUnit();
388 return sScriptMgr->OnCriteriaCheck(ScriptId, const_cast<Player*>(source), const_cast<Unit*>(unitTarget));
389 }
391 if (source->GetMap()->IsRaid())
392 if (source->GetMap()->Is25ManRaid() != ((difficulty.difficulty & RAID_DIFFICULTY_MASK_25MAN) != 0))
393 return false;
394 return source->GetMap()->GetSpawnMode() >= difficulty.difficulty;
396 return source->GetMap()->GetPlayersCountExceptGMs() <= map_players.maxcount;
398 if (!target || target->GetTypeId() != TYPEID_PLAYER)
399 return false;
400 return target->ToPlayer()->GetTeam() == team.team;
406 return IsEventActive(game_event.id);
408 {
409 Battleground* bg = source->GetBattleground();
410 if (!bg)
411 return false;
412
414 return score >= bg_loss_team_score.min_score && score <= bg_loss_team_score.max_score;
415 }
417 {
418 if (!source->IsInWorld())
419 return false;
420 Map* map = source->GetMap();
421 if (!map->IsDungeon())
422 {
423 TC_LOG_ERROR("achievement", "Achievement system call ACHIEVEMENT_CRITERIA_DATA_TYPE_INSTANCE_SCRIPT ({}) for achievement criteria {} in a non-dungeon/non-raid map {}",
424 dataType, criteria_id, map->GetId());
425 return false;
426 }
427 InstanceScript* instance = map->ToInstanceMap()->GetInstanceScript();
428 if (!instance)
429 {
430 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.",
431 dataType, criteria_id, map->GetId());
432 return false;
433 }
434
435 Unit const* unitTarget = nullptr;
436 if (target)
437 unitTarget = target->ToUnit();
438 return instance->CheckAchievementCriteriaMeet(criteria_id, source, unitTarget, miscValue1);
439 }
441 {
442 AchievementCriteriaEntry const* entry = sAchievementCriteriaStore.AssertEntry(criteria_id);
443
444 uint32 itemId = (entry->Type == ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM ? miscValue2 : miscValue1);
445 ItemTemplate const* itemTemplate = sObjectMgr->GetItemTemplate(itemId);
446 if (!itemTemplate)
447 return false;
448 return itemTemplate->ItemLevel >= equipped_item.item_level && itemTemplate->Quality >= equipped_item.item_quality;
449 }
451 return source->GetMapId() == map_id.mapId;
453 {
454 time_t birthday_start = time_t(sWorld->getIntConfig(CONFIG_BIRTHDAY_TIME));
455 tm birthday_tm;
456 localtime_r(&birthday_start, &birthday_tm);
457
458 // exactly N birthday
459 birthday_tm.tm_year += birthday_login.nth_birthday;
460
461 time_t birthday = mktime(&birthday_tm);
462 time_t now = GameTime::GetGameTime();
463 return now <= birthday + DAY && now >= birthday;
464 }
466 {
467 if (CharTitlesEntry const* titleInfo = sCharTitlesStore.LookupEntry(known_title.title_id))
468 return source->HasTitle(titleInfo->MaskID);
469 return false;
470 }
472 {
473 ItemTemplate const* pProto = sObjectMgr->GetItemTemplate(miscValue1);
474 if (!pProto)
475 return false;
476 return pProto->Quality == item.item_quality;
477 }
478 default:
479 break;
480 }
481 return false;
482}
483
484bool AchievementCriteriaDataSet::Meets(Player const* source, WorldObject const* target, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /* = 0*/) const
485{
486 for (AchievementCriteriaData const& criteriadata : storage)
487 if (!criteriadata.Meets(criteria_id, source, target, miscValue1, miscValue2))
488 return false;
489
490 return true;
491}
492
493AchievementMgr::AchievementMgr(Player* player) : m_player(player), m_achievementPoints(0)
494{
495}
496
498
500{
501 for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : m_completedAchievements)
502 {
504 data << uint32(completedAchievement.first);
506 }
507
508 for (std::pair<uint32 const, CriteriaProgress> const& criteriaprogress : m_criteriaProgress)
509 {
511 data << uint32(criteriaprogress.first);
513 }
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
703 WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, GetPlayer()->GetName().size() + 1 + 8 + 4 + 4);
704 data << GetPlayer()->GetName();
705 data << GetPlayer()->GetGUID();
706 data << uint32(achievement->ID);
707
708 std::size_t linkTypePos = data.wpos();
709 data << uint32(1); // display name as clickable link in chat
710 sWorld->SendGlobalMessage(&data, nullptr, team);
711
712 data.put<uint32>(linkTypePos, 0); // display name as plain string in chat
713 sWorld->SendGlobalMessage(&data, nullptr, team == ALLIANCE ? HORDE : ALLIANCE);
714 }
715 // if player is in world he can tell his friends about new achievement
716 else if (GetPlayer()->IsInWorld())
717 {
722 }
723
724 auto achievementEarnedBuilder = [&](Player const* receiver)
725 {
727 now += receiver->GetSession()->GetTimezoneOffset();
728
729 WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8 + 4 + 8);
730 data << GetPlayer()->GetPackGUID();
731 data << uint32(achievement->ID);
732 data << now;
733 data << uint32(0);
734 receiver->SendDirectMessage(&data);
735 };
736
737 float dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY);
738 Trinity::PlayerDistWorker notifier(GetPlayer(), dist, achievementEarnedBuilder);
739 Cell::VisitWorldObjects(GetPlayer(), notifier, dist);
740}
741
742void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const
743{
744 WowTime date;
745 date.SetUtcTimeFromUnixTime(progress->date);
746 date += GetPlayer()->GetSession()->GetTimezoneOffset();
747
748 WorldPacket data(SMSG_CRITERIA_UPDATE, 8 + 4 + 8);
749 data << uint32(entry->ID);
750
751 // the counter is packed like a packed Guid
752 data.appendPackGUID(progress->counter);
753
754 data << GetPlayer()->GetPackGUID();
755 if (!entry->StartTimer)
756 data << uint32(0);
757 else
758 data << uint32(timedCompleted ? 1 : 0); // this are some flags, 1 is for keeping the counter at 0 in client
759 data << date;
760 data << uint32(timeElapsed); // time elapsed in seconds
761 data << uint32(0); // unk
763}
764
769{
770 // suppress sending packets
771 for (uint32 i = 0; i < ACHIEVEMENT_CRITERIA_TYPE_TOTAL; ++i)
773}
774
775static const uint32 achievIdByArenaSlot[MAX_ARENA_SLOT] = { 1057, 1107, 1108 };
776
780void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscValue1 /*= 0*/, uint32 miscValue2 /*= 0*/, WorldObject* ref /*= nullptr*/)
781{
783 {
784 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: Wrong criteria type {}", type);
785 return;
786 }
787
788 // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission
790 {
791 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: [Player {} {}] {}, {} ({}), {}, {}"
792 , m_player->GetName(), m_player->IsGameMaster() ? "GM mode on" : "disallowed by RBAC", m_player->GetGUID().ToString(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
793 return;
794 }
795
796 TC_LOG_DEBUG("achievement", "UpdateAchievementCriteria: {}, {} ({}), {}, {}"
797 , m_player->GetGUID().ToString(), AchievementGlobalMgr::GetCriteriaTypeString(type), type, miscValue1, miscValue2);
798
799 AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr->GetAchievementCriteriaByType(type, miscValue1);
800 for (AchievementCriteriaEntry const* achievementCriteria : achievementCriteriaList)
801 {
802 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementCriteria->AchievementID);
803 if (!CanUpdateCriteria(achievementCriteria, achievement, miscValue1, miscValue2, ref))
804 continue;
805
806 switch (type)
807 {
808 // special cases, db data is checked later
812 break;
813 default:
814 if (AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria))
815 if (!data->Meets(GetPlayer(), ref, miscValue1, miscValue2))
816 continue;
817 break;
818 }
819
820 switch (type)
821 {
822 // std. case: increment at 1
836 case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA: // This also behaves like ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA
852 case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS: /* FIXME: for online player only currently */
861 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
862 break;
863 // std case: increment at miscValue1
873 case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS: /* FIXME: for online player only currently */
877 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
878 break;
879 // std case: increment at miscValue2
885 SetCriteriaProgress(achievementCriteria, miscValue2, PROGRESS_ACCUMULATE);
886 break;
887 // std case: high value at miscValue1
889 case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD: /* FIXME: for online player only currently */
894 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
895 break;
896 // std. case: set at 1
904 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_SET);
905 break;
906
907 // specialized cases
909 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetLevel());
910 break;
912 if (uint32 skillvalue = GetPlayer()->GetBaseSkillValue(achievementCriteria->Asset.SkillID))
913 SetCriteriaProgress(achievementCriteria, skillvalue);
914 break;
916 if (uint32 maxSkillvalue = GetPlayer()->GetPureMaxSkillValue(achievementCriteria->Asset.SkillID))
917 SetCriteriaProgress(achievementCriteria, maxSkillvalue);
918 break;
920 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetRewardedQuestCount());
921 break;
923 {
924 time_t nextDailyResetTime = sWorld->GetNextDailyQuestsResetTime();
925 CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
926
927 if (!miscValue1) // Login case.
928 {
929 // reset if player missed one day.
930 if (progress && progress->date < (nextDailyResetTime - 2 * DAY))
931 SetCriteriaProgress(achievementCriteria, 0, PROGRESS_SET);
932 continue;
933 }
934
935 ProgressType progressType;
936 if (!progress)
937 // 1st time. Start count.
938 progressType = PROGRESS_SET;
939 else if (progress->date < (nextDailyResetTime - 2 * DAY))
940 // last progress is older than 2 days. Player missed 1 day => Restart count.
941 progressType = PROGRESS_SET;
942 else if (progress->date < (nextDailyResetTime - DAY))
943 // last progress is between 1 and 2 days. => 1st time of the day.
944 progressType = PROGRESS_ACCUMULATE;
945 else
946 // last progress is within the day before the reset => Already counted today.
947 continue;
948
949 SetCriteriaProgress(achievementCriteria, 1, progressType);
950 break;
951 }
953 {
954 uint32 counter = 0;
955
956 RewardedQuestSet const& rewQuests = GetPlayer()->getRewardedQuests();
957 for (uint32 rewQuest : rewQuests)
958 {
959 Quest const* quest = sObjectMgr->GetQuestTemplate(rewQuest);
960 if (quest && quest->GetZoneOrSort() >= 0 && uint32(quest->GetZoneOrSort()) == achievementCriteria->Asset.ZoneID)
961 ++counter;
962 }
963 SetCriteriaProgress(achievementCriteria, counter);
964 break;
965 }
967 // miscValue1 is the ingame fallheight*100 as stored in dbc
968 SetCriteriaProgress(achievementCriteria, miscValue1);
969 break;
971 // additional requirements
972 if (achievementCriteria->AdditionalRequirements[0].Type == ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE)
973 {
974 // those requirements couldn't be found in the dbc
975 AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
976 if (!data || !data->Meets(GetPlayer(), ref, miscValue1))
977 {
978 // reset the progress as we have a win without the requirement.
979 SetCriteriaProgress(achievementCriteria, 0);
980 continue;
981 }
982 }
983
984 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
985 break;
987 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetBankBagSlotCount());
988 break;
990 {
991 int32 reputation = GetPlayer()->GetReputationMgr().GetReputation(achievementCriteria->Asset.FactionID);
992 if (reputation > 0)
993 SetCriteriaProgress(achievementCriteria, reputation);
994 break;
995 }
997 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetExaltedFactionCount());
998 break;
1001 {
1002 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
1003 if (!proto)
1004 continue;
1005
1006 // check item level via achievement_criteria_data
1007 AchievementCriteriaDataSet const* data = sAchievementMgr->GetCriteriaDataSet(achievementCriteria);
1008 if (!data || !data->Meets(GetPlayer(), nullptr, proto->ItemLevel))
1009 continue;
1010
1011 SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
1012 break;
1013 }
1015 {
1016 uint32 spellCount = 0;
1017 for (std::pair<uint32 const, PlayerSpell> const& spellIter : GetPlayer()->GetSpellMap())
1018 {
1019 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter.first);
1020 for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
1021 {
1022 if (skillIter->second->SkillLine == achievementCriteria->Asset.SkillID)
1023 {
1024 // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
1025 ++spellCount;
1026 break;
1027 }
1028 }
1029 }
1030 SetCriteriaProgress(achievementCriteria, spellCount);
1031 break;
1032 }
1034 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetReveredFactionCount());
1035 break;
1037 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetHonoredFactionCount());
1038 break;
1040 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetReputationMgr().GetVisibleFactionCount());
1041 break;
1043 {
1044 uint32 spellCount = 0;
1045 for (std::pair<uint32 const, PlayerSpell> const& spellIter : GetPlayer()->GetSpellMap())
1046 {
1047 SkillLineAbilityMapBounds bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellIter.first);
1048 for (SkillLineAbilityMap::const_iterator skillIter = bounds.first; skillIter != bounds.second; ++skillIter)
1049 {
1050 if (skillIter->second->SkillLine == achievementCriteria->Asset.SkillID)
1051 {
1052 // do not add couter twice if by any chance skill is listed twice in dbc (eg. skill 777 and spell 22717)
1053 ++spellCount;
1054 break;
1055 }
1056 }
1057 }
1058 SetCriteriaProgress(achievementCriteria, spellCount);
1059 break;
1060 }
1062 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetUInt32Value(PLAYER_FIELD_LIFETIME_HONORABLE_KILLS));
1063 break;
1065 SetCriteriaProgress(achievementCriteria, GetPlayer()->GetMoney(), PROGRESS_HIGHEST);
1066 break;
1068 if (!miscValue1)
1070 else
1071 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_ACCUMULATE);
1072 break;
1074 {
1075 uint32 reqTeamType = achievementCriteria->Asset.TeamType;
1076
1077 if (miscValue1)
1078 {
1079 if (miscValue2 != reqTeamType)
1080 continue;
1081
1082 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
1083 }
1084 else // login case
1085 {
1086 for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
1087 {
1088 uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot);
1089 if (!teamId)
1090 continue;
1091
1092 ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
1093 if (!team || team->GetType() != reqTeamType)
1094 continue;
1095
1096 SetCriteriaProgress(achievementCriteria, team->GetStats().Rating, PROGRESS_HIGHEST);
1097 break;
1098 }
1099 }
1100 break;
1101 }
1103 {
1104 uint32 reqTeamType = achievementCriteria->Asset.TeamType;
1105
1106 if (miscValue1)
1107 {
1108 if (miscValue2 != reqTeamType)
1109 continue;
1110
1111 SetCriteriaProgress(achievementCriteria, miscValue1, PROGRESS_HIGHEST);
1112 }
1113 else // login case
1114 {
1115 for (uint32 arena_slot = 0; arena_slot < MAX_ARENA_SLOT; ++arena_slot)
1116 {
1117 uint32 teamId = GetPlayer()->GetArenaTeamId(arena_slot);
1118 if (!teamId)
1119 continue;
1120
1121 ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(teamId);
1122 if (!team || team->GetType() != reqTeamType)
1123 continue;
1124
1125 if (ArenaTeamMember const* member = team->GetMember(GetPlayer()->GetGUID()))
1126 {
1127 SetCriteriaProgress(achievementCriteria, member->PersonalRating, PROGRESS_HIGHEST);
1128 break;
1129 }
1130 }
1131 }
1132
1133 break;
1134 }
1135 // std case: does not exist in DBC, not triggered in code as result
1142 break;
1143 // FIXME: not triggered in code as result, need to implement
1147 break; // Not implemented yet :(
1148 }
1149
1150 if (IsCompletedCriteria(achievementCriteria, achievement))
1151 CompletedCriteriaFor(achievement);
1152
1153 // check again the completeness for SUMM and REQ COUNT achievements,
1154 // as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
1155 if (achievement->Flags & ACHIEVEMENT_FLAG_SUMM)
1156 if (IsCompletedAchievement(achievement))
1157 CompletedAchievement(achievement);
1158
1159 if (AchievementEntryList const* achRefList = sAchievementMgr->GetAchievementByReferencedId(achievement->ID))
1160 for (AchievementEntry const* achievement : *achRefList)
1161 if (IsCompletedAchievement(achievement))
1162 CompletedAchievement(achievement);
1163 }
1164}
1165
1166bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement)
1167{
1168 if (!achievement)
1169 return false;
1170
1171 // counter can never complete
1172 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER)
1173 return false;
1174
1176 {
1177 // someone on this realm has already completed that achievement
1178 if (sAchievementMgr->IsRealmCompleted(achievement))
1179 return false;
1180 }
1181
1182 CriteriaProgress const* progress = GetCriteriaProgress(achievementCriteria);
1183 if (!progress)
1184 return false;
1185
1186 switch (AchievementCriteriaTypes(achievementCriteria->Type))
1187 {
1234 return progress->counter >= achievementCriteria->Quantity;
1239 return progress->counter >= 1;
1241 return progress->counter >= (achievementCriteria->Quantity * 75);
1243 return progress->counter >= 9000;
1245 return achievementCriteria->Quantity && progress->counter >= achievementCriteria->Quantity;
1247 return true;
1248 // handle all statistic-only criteria here
1283 default:
1284 break;
1285 }
1286
1287 return false;
1288}
1289
1291{
1292 // counter can never complete
1293 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER)
1294 return;
1295
1296 // already completed and stored
1297 if (HasAchieved(achievement->ID))
1298 return;
1299
1300 if (IsCompletedAchievement(achievement))
1301 CompletedAchievement(achievement);
1302}
1303
1305{
1306 // counter can never complete
1307 if (entry->Flags & ACHIEVEMENT_FLAG_COUNTER)
1308 return false;
1309
1310 // for achievement with referenced achievement criterias get from referenced and counter from self
1311 uint32 achievementForTestId = entry->SharesCriteria ? entry->SharesCriteria : entry->ID;
1312 uint32 achievementForTestCount = entry->MinimumCriteria;
1313
1314 AchievementCriteriaEntryList const* cList = sAchievementMgr->GetAchievementCriteriaByAchievement(achievementForTestId);
1315 if (!cList)
1316 return false;
1317 uint32 count = 0;
1318
1319 // For SUMM achievements, we have to count the progress of each criteria of the achievement.
1320 // Oddly, the target count is NOT contained in the achievement, but in each individual criteria
1321 if (entry->Flags & ACHIEVEMENT_FLAG_SUMM)
1322 {
1323 for (AchievementCriteriaEntry const* criteria : *cList)
1324 {
1325 CriteriaProgress const* progress = GetCriteriaProgress(criteria);
1326 if (!progress)
1327 continue;
1328
1329 count += progress->counter;
1330
1331 // for counters, field4 contains the main count requirement
1332 if (count >= criteria->Quantity)
1333 return true;
1334 }
1335 return false;
1336 }
1337
1338 // Default case - need complete all or
1339 bool completed_all = true;
1340 for (AchievementCriteriaEntry const* criteria : *cList)
1341 {
1342 bool completed = IsCompletedCriteria(criteria, entry);
1343
1344 // found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL
1345 if (completed)
1346 ++count;
1347 else
1348 completed_all = false;
1349
1350 // completed as have req. count of completed criterias
1351 if (achievementForTestCount > 0 && achievementForTestCount <= count)
1352 return true;
1353 }
1354
1355 // all criterias completed requirement
1356 if (completed_all && achievementForTestCount == 0)
1357 return true;
1358
1359 return false;
1360}
1361
1363{
1364 CriteriaProgressMap::iterator iter = m_criteriaProgress.find(entry->ID);
1365
1366 if (iter == m_criteriaProgress.end())
1367 return nullptr;
1368
1369 return &(iter->second);
1370}
1371
1373{
1374 // Don't allow to cheat - doing timed achievements without timer active
1375 TimedAchievementMap::iterator timedIter = m_timedAchievements.find(entry->ID);
1376 if (entry->StartTimer && timedIter == m_timedAchievements.end())
1377 return;
1378
1379 TC_LOG_DEBUG("achievement", "AchievementMgr::SetCriteriaProgress({}, {}) for {}", entry->ID, changeValue, m_player->GetGUID().ToString());
1380
1381 CriteriaProgress* progress = GetCriteriaProgress(entry);
1382 if (!progress)
1383 {
1384 // not create record for 0 counter but allow it for timed achievements
1385 // we will need to send 0 progress to client to start the timer
1386 if (changeValue == 0 && !entry->StartTimer)
1387 return;
1388
1389 progress = &m_criteriaProgress[entry->ID];
1390 progress->counter = changeValue;
1391 }
1392 else
1393 {
1394 uint32 newValue = 0;
1395 switch (ptype)
1396 {
1397 case PROGRESS_SET:
1398 newValue = changeValue;
1399 break;
1401 {
1402 // avoid overflow
1403 uint32 max_value = std::numeric_limits<uint32>::max();
1404 newValue = max_value - progress->counter > changeValue ? progress->counter + changeValue : max_value;
1405 break;
1406 }
1407 case PROGRESS_HIGHEST:
1408 newValue = progress->counter < changeValue ? changeValue : progress->counter;
1409 break;
1410 }
1411
1412 // not update (not mark as changed) if counter will have same value
1413 if (progress->counter == newValue && !entry->StartTimer)
1414 return;
1415
1416 progress->counter = newValue;
1417 }
1418
1419 progress->changed = true;
1420 progress->date = GameTime::GetGameTime(); // set the date to the latest update.
1421
1422 uint32 timeElapsed = 0;
1423 bool timedCompleted = false;
1424
1425 if (entry->StartTimer)
1426 {
1427 // has to exist, otherwise we wouldn't be here
1428 timedCompleted = IsCompletedCriteria(entry, sAchievementStore.LookupEntry(entry->AchievementID));
1429 // Client expects this in packet
1430 timeElapsed = entry->StartTimer - (timedIter->second/IN_MILLISECONDS);
1431
1432 // Remove the timer, we wont need it anymore
1433 if (timedCompleted)
1434 m_timedAchievements.erase(timedIter);
1435 }
1436
1437 SendCriteriaUpdate(entry, progress, timeElapsed, timedCompleted);
1438}
1439
1441{
1442 if (!entry)
1443 return;
1444
1445 CriteriaProgressMap::iterator criteriaProgress = m_criteriaProgress.find(entry->ID);
1446 if (criteriaProgress == m_criteriaProgress.end())
1447 return;
1448
1450 data << uint32(entry->ID);
1452
1453 m_criteriaProgress.erase(criteriaProgress);
1454}
1455
1457{
1458 if (!m_timedAchievements.empty())
1459 {
1460 for (TimedAchievementMap::iterator itr = m_timedAchievements.begin(); itr != m_timedAchievements.end();)
1461 {
1462 // Time is up, remove timer and reset progress
1463 if (itr->second <= timeDiff)
1464 {
1465 AchievementCriteriaEntry const* entry = sAchievementCriteriaStore.LookupEntry(itr->first);
1467 m_timedAchievements.erase(itr++);
1468 }
1469 else
1470 {
1471 itr->second -= timeDiff;
1472 ++itr;
1473 }
1474 }
1475 }
1476}
1477
1479{
1480 for (AchievementCriteriaEntry const* criteria : sAchievementMgr->GetTimedAchievementCriteriaByType(type))
1481 {
1482 if (criteria->StartAsset != entry)
1483 continue;
1484
1485 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
1486 if (m_timedAchievements.find(criteria->ID) == m_timedAchievements.end() && !IsCompletedCriteria(criteria, achievement))
1487 {
1488 // Start the timer
1489 if (criteria->StartTimer * IN_MILLISECONDS > timeLost)
1490 {
1491 m_timedAchievements[criteria->ID] = criteria->StartTimer * IN_MILLISECONDS - timeLost;
1492
1493 // and at client too
1494 SetCriteriaProgress(criteria, 0, PROGRESS_SET);
1495 }
1496 }
1497 }
1498}
1499
1501{
1502 for (AchievementCriteriaEntry const* criteria : sAchievementMgr->GetTimedAchievementCriteriaByType(type))
1503 {
1504 if (criteria->StartAsset != entry)
1505 continue;
1506
1507 TimedAchievementMap::iterator timedIter = m_timedAchievements.find(criteria->ID);
1508 // We don't have timer for this achievement
1509 if (timedIter == m_timedAchievements.end())
1510 continue;
1511
1512 // remove progress
1513 RemoveCriteriaProgress(criteria);
1514
1515 // Remove the timer
1516 m_timedAchievements.erase(timedIter);
1517 }
1518}
1519
1521{
1522 // Disable for GameMasters with GM-mode enabled or for players that don't have the related RBAC permission
1524 return;
1525
1526 if (achievement->Flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved(achievement->ID))
1527 return;
1528
1529 TC_LOG_INFO("achievement", "AchievementMgr::CompletedAchievement({}). Player: {} {}",
1530 achievement->ID, m_player->GetGUID().ToString(), m_player->GetName());
1531
1532 SendAchievementEarned(achievement);
1535 ca.changed = true;
1536
1538 sAchievementMgr->SetRealmCompleted(achievement);
1539
1540 m_achievementPoints += achievement->Points;
1541
1544
1545 // reward items and titles if any
1546 AchievementReward const* reward = sAchievementMgr->GetAchievementReward(achievement);
1547
1548 // no rewards
1549 if (!reward)
1550 return;
1551
1552 // titles
1557 if (uint32 titleId = reward->TitleId[achievement->ID == 1793 ? GetPlayer()->GetNativeGender() : (GetPlayer()->GetTeam() == ALLIANCE ? 0 : 1)])
1558 if (CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(titleId))
1559 GetPlayer()->SetTitle(titleEntry);
1560
1561 // mail
1562 if (reward->SenderCreatureId)
1563 {
1564 MailDraft draft(reward->MailTemplateId);
1565
1566 if (!reward->MailTemplateId)
1567 {
1568 // subject and text
1569 std::string subject = reward->Subject;
1570 std::string text = reward->Body;
1571
1573 if (localeConstant != LOCALE_enUS)
1574 {
1575 if (AchievementRewardLocale const* loc = sAchievementMgr->GetAchievementRewardLocale(achievement))
1576 {
1577 ObjectMgr::GetLocaleString(loc->Subject, localeConstant, subject);
1578 ObjectMgr::GetLocaleString(loc->Text, localeConstant, text);
1579 }
1580 }
1581
1582 draft = MailDraft(subject, text);
1583 }
1584
1585 CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction();
1586
1587 Item* item = reward->ItemId ? Item::CreateItem(reward->ItemId, 1, GetPlayer()) : nullptr;
1588 if (item)
1589 {
1590 // save new item before send
1591 item->SaveToDB(trans); // save for prevent lost at next mail load, if send fail then item will deleted
1592
1593 // item
1594 draft.AddItem(item);
1595 }
1596
1598 CharacterDatabase.CommitTransaction(trans);
1599 }
1600}
1601
1608
1610{
1612 data << GetPlayer()->GetPackGUID();
1613 BuildAllDataPacket(player, &data);
1614 player->SendDirectMessage(&data);
1615}
1616
1621{
1622 for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : m_completedAchievements)
1623 {
1624 // Skip hidden achievements
1625 AchievementEntry const* achievement = sAchievementStore.LookupEntry(completedAchievement.first);
1626 if (!achievement || achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN)
1627 continue;
1628
1629 WowTime date;
1630 date.SetUtcTimeFromUnixTime(completedAchievement.second.date);
1631 date += receiver->GetSession()->GetTimezoneOffset();
1632
1633 *data << uint32(completedAchievement.first);
1634 *data << date;
1635 }
1636 *data << int32(-1);
1637
1638 for (std::pair<uint32 const, CriteriaProgress> const& criteriaProgress : m_criteriaProgress)
1639 {
1640 WowTime date;
1641 date.SetUtcTimeFromUnixTime(criteriaProgress.second.date);
1642 date += receiver->GetSession()->GetTimezoneOffset();
1643
1644 *data << uint32(criteriaProgress.first);
1645 data->appendPackGUID(criteriaProgress.second.counter);
1646 *data << GetPlayer()->GetPackGUID();
1647 *data << uint32(0);
1648 *data << date;
1649 *data << uint32(0);
1650 *data << uint32(0);
1651 }
1652
1653 *data << int32(-1);
1654}
1655
1656bool AchievementMgr::HasAchieved(uint32 achievementId) const
1657{
1658 return m_completedAchievements.find(achievementId) != m_completedAchievements.end();
1659}
1660
1661bool AchievementMgr::CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref)
1662{
1664 {
1665 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Disabled",
1667 return false;
1668 }
1669
1670 if (achievement->InstanceID != -1 && GetPlayer()->GetMapId() != uint32(achievement->InstanceID))
1671 {
1672 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {} Achievement {}) Wrong map",
1673 criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type), achievement->ID);
1674 return false;
1675 }
1676
1677 if ((achievement->Faction == ACHIEVEMENT_FACTION_HORDE && GetPlayer()->GetTeam() != HORDE) ||
1678 (achievement->Faction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
1679 {
1680 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {} Achievement {}) Wrong faction",
1681 criteria->ID, AchievementGlobalMgr::GetCriteriaTypeString(criteria->Type), achievement->ID);
1682 return false;
1683 }
1684
1685 if (!RequirementsSatisfied(criteria, achievement, miscValue1, miscValue2, ref))
1686 {
1687 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Requirements have not been satisfied",
1689 return false;
1690 }
1691
1692 if (!ConditionsSatisfied(criteria))
1693 {
1694 TC_LOG_TRACE("achievement", "CanUpdateCriteria: (Id: {} Type {}) Conditions have not been satisfied",
1696 return false;
1697 }
1698
1699 // Don't update realm first achievements if the player's account isn't allowed to do so
1701 if (GetPlayer()->GetSession()->HasPermission(rbac::RBAC_PERM_CANNOT_EARN_REALM_FIRST_ACHIEVEMENTS))
1702 return false;
1703
1704 // don't update already completed criteria
1705 if (IsCompletedCriteria(criteria, achievement))
1706 return false;
1707
1708 return true;
1709}
1710
1712{
1713 for (auto AdditionalRequirement : criteria->AdditionalRequirements)
1714 {
1715 if (!AdditionalRequirement.Type)
1716 continue;
1717
1718 switch (AdditionalRequirement.Type)
1719 {
1721 if (GetPlayer()->GetMapId() != AdditionalRequirement.Asset)
1722 return false;
1723 break;
1725 if (GetPlayer()->GetGroup())
1726 return false;
1727 break;
1728 default:
1729 break;
1730 }
1731 }
1732
1733 return true;
1734}
1735
1736bool AchievementMgr::RequirementsSatisfied(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref) const
1737{
1738 switch (AchievementCriteriaTypes(achievementCriteria->Type))
1739 {
1776 if (!miscValue1)
1777 return false;
1778 break;
1792 break;
1793
1794 // specialized cases
1796 if ((miscValue1 && achievementCriteria->Asset.AchievementID != miscValue1) || (!miscValue1 && m_completedAchievements.find(achievementCriteria->Asset.AchievementID) == m_completedAchievements.end()))
1797 return false;
1798 break;
1802 if (!miscValue1 || achievementCriteria->Asset.MapID != GetPlayer()->GetMapId())
1803 return false;
1804 break;
1807 if (!miscValue1 || achievementCriteria->Asset.CreatureID != miscValue1)
1808 return false;
1809 break;
1812 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SkillID)
1813 return false;
1814 break;
1816 if (miscValue1 && miscValue1 != achievementCriteria->Asset.ZoneID)
1817 return false;
1818 break;
1820 if (!miscValue1)
1821 return false;
1822 for (uint8 j = 0; j < MAX_ARENA_SLOT; ++j)
1823 {
1824 if (achievIdByArenaSlot[j] == achievement->ID)
1825 {
1827 if (!bg || !bg->isArena() || ArenaTeam::GetSlotByType(bg->GetArenaType()) != j)
1828 return false;
1829 break;
1830 }
1831 }
1832 break;
1834 {
1835 if (!miscValue1)
1836 return false;
1837
1838 Map const* map = GetPlayer()->IsInWorld() ? GetPlayer()->GetMap() : sMapMgr->FindMap(GetPlayer()->GetMapId(), GetPlayer()->GetInstanceId());
1839 if (!map || !map->IsDungeon())
1840 return false;
1841
1842 //FIXME: work only for instances where max == min for players
1843 if (map->ToInstanceMap()->GetMaxPlayers() != achievementCriteria->Asset.GroupSize)
1844 return false;
1845 break;
1846 }
1848 if (!miscValue1)
1849 return false;
1850 // if team check required: must kill by opposition faction
1851 if (achievement->ID == 318 && miscValue2 == GetPlayer()->GetTeam())
1852 return false;
1853 break;
1855 if (!miscValue1 || miscValue2 != achievementCriteria->Asset.DamageType)
1856 return false;
1857 break;
1859 // if miscvalues != 0, it contains the questID.
1860 if (miscValue1)
1861 {
1862 if (miscValue1 != achievementCriteria->Asset.QuestID)
1863 return false;
1864 }
1865 else
1866 {
1867 // login case.
1868 if (!GetPlayer()->GetQuestRewardStatus(achievementCriteria->Asset.QuestID))
1869 return false;
1870 }
1871 break;
1876 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.SpellID)
1877 return false;
1878 break;
1880 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SpellID)
1881 return false;
1882 if (!GetPlayer()->HasSpell(achievementCriteria->Asset.SpellID))
1883 return false;
1884 break;
1886 // miscValue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored)
1887 // miscValue2=count of item loot
1888 if (!miscValue1 || !miscValue2)
1889 return false;
1890 if (miscValue1 != achievementCriteria->Asset.LootType)
1891 return false;
1892 break;
1894 if (miscValue1 && achievementCriteria->Asset.ItemID != miscValue1)
1895 return false;
1896 break;
1900 if (!miscValue1)
1901 return false;
1902 if (miscValue1 != achievementCriteria->Asset.ItemID)
1903 return false;
1904 break;
1906 {
1907 WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(achievementCriteria->Asset.WorldMapOverlayID);
1908 if (!worldOverlayEntry)
1909 return false;
1910
1911 bool matchFound = false;
1912 for (uint32 j : worldOverlayEntry->AreaID)
1913 {
1914 AreaTableEntry const* area = sAreaTableStore.LookupEntry(j);
1915 if (!area)
1916 break;
1917
1918 uint32 playerIndexOffset = uint32(area->AreaBit) / 32;
1919 if (playerIndexOffset >= PLAYER_EXPLORED_ZONES_SIZE)
1920 continue;
1921
1922 uint32 mask = 1 << (uint32(area->AreaBit) % 32);
1923 if (GetPlayer()->GetUInt32Value(PLAYER_EXPLORED_ZONES_1 + playerIndexOffset) & mask)
1924 {
1925 matchFound = true;
1926 break;
1927 }
1928 }
1929
1930 if (!matchFound)
1931 return false;
1932 break;
1933 }
1935 if (miscValue1 && miscValue1 != achievementCriteria->Asset.FactionID)
1936 return false;
1937 break;
1939 // miscValue1 = itemSlot
1940 // miscValue2 = itemid
1941 if (!miscValue2)
1942 return false;
1943 if (miscValue1 != achievementCriteria->Asset.ItemSlot)
1944 return false;
1945 break;
1948 // miscValue1 = itemid
1949 // miscValue2 = diced value
1950 if (!miscValue1)
1951 return false;
1952 if (miscValue2 != achievementCriteria->Asset.RollValue)
1953 return false;
1954 break;
1956 // miscValue1 = emote
1957 if (!miscValue1)
1958 return false;
1959 if (miscValue1 != achievementCriteria->Asset.EmoteID)
1960 return false;
1961 break;
1964 if (!miscValue1)
1965 return false;
1966
1968 {
1969 if (GetPlayer()->GetMapId() != achievementCriteria->AdditionalRequirements[0].Asset)
1970 return false;
1971
1972 // map specific case (BG in fact) expected player targeted damage/heal
1973 if (!ref || ref->GetTypeId() != TYPEID_PLAYER)
1974 return false;
1975 }
1976 break;
1979 if (!miscValue1)
1980 return false;
1981 if (miscValue1 != achievementCriteria->Asset.GameObjectID)
1982 return false;
1983 break;
1986 if (miscValue1 && miscValue1 != achievementCriteria->Asset.SkillID)
1987 return false;
1988 break;
1991 {
1992 if (!miscValue1)
1993 return false;
1994 ItemTemplate const* proto = sObjectMgr->GetItemTemplate(miscValue1);
1995 if (!proto || proto->Quality < ITEM_QUALITY_EPIC)
1996 return false;
1997 break;
1998 }
2000 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.ClassID)
2001 return false;
2002 break;
2004 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.RaceID)
2005 return false;
2006 break;
2008 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.ObjectiveId)
2009 return false;
2010 break;
2012 if (!miscValue1 || miscValue1 != achievementCriteria->Asset.AreaID)
2013 return false;
2014 break;
2016 if (miscValue1 != achievementCriteria->Asset.MapID)
2017 return false;
2018 break;
2019 default:
2020 break;
2021 }
2022
2023 return true;
2024}
2025
2030
2032{
2033 switch (type)
2034 {
2036 return "KILL_CREATURE";
2038 return "TYPE_WIN_BG";
2040 return "REACH_LEVEL";
2042 return "REACH_SKILL_LEVEL";
2044 return "COMPLETE_ACHIEVEMENT";
2046 return "COMPLETE_QUEST_COUNT";
2048 return "COMPLETE_DAILY_QUEST_DAILY";
2050 return "COMPLETE_QUESTS_IN_ZONE";
2052 return "DAMAGE_DONE";
2054 return "COMPLETE_DAILY_QUEST";
2056 return "COMPLETE_BATTLEGROUND";
2058 return "DEATH_AT_MAP";
2060 return "DEATH";
2062 return "DEATH_IN_DUNGEON";
2064 return "COMPLETE_RAID";
2066 return "KILLED_BY_CREATURE";
2068 return "KILLED_BY_PLAYER";
2070 return "FALL_WITHOUT_DYING";
2072 return "DEATHS_FROM";
2074 return "COMPLETE_QUEST";
2076 return "BE_SPELL_TARGET";
2078 return "CAST_SPELL";
2080 return "BG_OBJECTIVE_CAPTURE";
2082 return "HONORABLE_KILL_AT_AREA";
2084 return "WIN_ARENA";
2086 return "PLAY_ARENA";
2088 return "LEARN_SPELL";
2090 return "HONORABLE_KILL";
2092 return "OWN_ITEM";
2094 return "WIN_RATED_ARENA";
2096 return "HIGHEST_TEAM_RATING";
2098 return "HIGHEST_PERSONAL_RATING";
2100 return "LEARN_SKILL_LEVEL";
2102 return "USE_ITEM";
2104 return "LOOT_ITEM";
2106 return "EXPLORE_AREA";
2108 return "OWN_RANK";
2110 return "BUY_BANK_SLOT";
2112 return "GAIN_REPUTATION";
2114 return "GAIN_EXALTED_REPUTATION";
2116 return "VISIT_BARBER_SHOP";
2118 return "EQUIP_EPIC_ITEM";
2120 return "ROLL_NEED_ON_LOOT";
2122 return "GREED_ON_LOOT";
2124 return "HK_CLASS";
2126 return "HK_RACE";
2128 return "DO_EMOTE";
2130 return "HEALING_DONE";
2132 return "GET_KILLING_BLOWS";
2134 return "EQUIP_ITEM";
2136 return "MONEY_FROM_VENDORS";
2138 return "GOLD_SPENT_FOR_TALENTS";
2140 return "NUMBER_OF_TALENT_RESETS";
2142 return "MONEY_FROM_QUEST_REWARD";
2144 return "GOLD_SPENT_FOR_TRAVELLING";
2146 return "GOLD_SPENT_AT_BARBER";
2148 return "GOLD_SPENT_FOR_MAIL";
2150 return "LOOT_MONEY";
2152 return "USE_GAMEOBJECT";
2154 return "GAIN_AURA";
2156 return "SPECIAL_PVP_KILL";
2158 return "FISH_IN_GAMEOBJECT";
2160 return "ON_LOGIN";
2162 return "LEARN_SKILLLINE_SPELLS";
2164 return "WIN_DUEL";
2166 return "LOSE_DUEL";
2168 return "KILL_CREATURE_TYPE";
2170 return "GOLD_EARNED_BY_AUCTIONS";
2172 return "CREATE_AUCTION";
2174 return "HIGHEST_AUCTION_BID";
2176 return "WON_AUCTIONS";
2178 return "HIGHEST_AUCTION_SOLD";
2180 return "HIGHEST_GOLD_VALUE_OWNED";
2182 return "GAIN_REVERED_REPUTATION";
2184 return "GAIN_HONORED_REPUTATION";
2186 return "KNOWN_FACTIONS";
2188 return "LOOT_EPIC_ITEM";
2190 return "RECEIVE_EPIC_ITEM";
2192 return "ROLL_NEED";
2194 return "ROLL_GREED";
2196 return "HIGHEST_HEALTH";
2198 return "HIGHEST_POWER";
2200 return "HIGHEST_STAT";
2202 return "HIGHEST_SPELLPOWER";
2204 return "HIGHEST_ARMOR";
2206 return "HIGHEST_RATING";
2208 return "HIT_DEALT";
2210 return "HIT_RECEIVED";
2212 return "TOTAL_DAMAGE_RECEIVED";
2214 return "HIGHEST_HEAL_CAST";
2216 return "TOTAL_HEALING_RECEIVED";
2218 return "HIGHEST_HEALING_RECEIVED";
2220 return "QUEST_ABANDONED";
2222 return "FLIGHT_PATHS_TAKEN";
2224 return "LOOT_TYPE";
2226 return "CAST_SPELL2";
2228 return "LEARN_SKILL_LINE";
2230 return "EARN_HONORABLE_KILL";
2232 return "ACCEPTED_SUMMONINGS";
2234 return "EARN_ACHIEVEMENT_POINTS";
2236 return "USE_LFD_TO_GROUP_WITH_PLAYERS";
2237 }
2238 return "MISSING_TYPE";
2239}
2240
2242
2248
2250{
2251 switch (type)
2252 {
2284 return true;
2285 default:
2286 break;
2287 }
2288 return false;
2289}
2290
2292{
2293 if (miscValue && IsAchievementCriteriaTypeStoredByMiscValue(type))
2294 {
2295 auto itr = m_AchievementCriteriasByMiscValue[type].find(miscValue);
2296 if (itr != m_AchievementCriteriasByMiscValue[type].end())
2297 return itr->second;
2298
2299 return EmptyCriteriaList;
2300 }
2301
2302 return m_AchievementCriteriasByType[type];
2303}
2304
2306{
2307 auto itr = _allCompletedAchievements.find(achievement->ID);
2308 if (itr == _allCompletedAchievements.end())
2309 return false;
2310
2311 if (itr->second == SystemTimePoint ::min())
2312 return false;
2313
2314 if (itr->second == SystemTimePoint::max())
2315 return true;
2316
2317 // Allow completing the realm first kill for entire minute after first person did it
2318 // it may allow more than one group to achieve it (highly unlikely)
2319 // but apparently this is how blizz handles it as well
2320 if (achievement->Flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL)
2321 return (GameTime::GetSystemTime() - itr->second) > Minutes(1);
2322
2323 return true;
2324}
2325
2327{
2328 if (IsRealmCompleted(achievement))
2329 return;
2330
2332}
2333
2334//==========================================================
2336{
2337 uint32 oldMSTime = getMSTime();
2338
2339 if (sAchievementCriteriaStore.GetNumRows() == 0)
2340 {
2341 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement criteria.");
2342 return;
2343 }
2344
2345 uint32 loaded = 0;
2346 for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
2347 {
2348 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
2349 if (!criteria)
2350 continue;
2351
2352 if (!sAchievementStore.LookupEntry(criteria->AchievementID))
2353 {
2354 TC_LOG_DEBUG("server.loading", "Achievement {} referenced by criteria {} doesn't exist, criteria not loaded.", criteria->AchievementID, criteria->ID);
2355 continue;
2356 }
2357
2358 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",
2359 criteria->Type + 1, ACHIEVEMENT_CRITERIA_TYPE_TOTAL);
2360
2361 m_AchievementCriteriasByType[criteria->Type].push_back(criteria);
2362 m_AchievementCriteriaListByAchievement[criteria->AchievementID].push_back(criteria);
2364 {
2366 m_AchievementCriteriasByMiscValue[criteria->Type][criteria->Asset.ID].push_back(criteria);
2367 else
2368 {
2369 WorldMapOverlayEntry const* worldOverlayEntry = sWorldMapOverlayStore.LookupEntry(criteria->Asset.WorldMapOverlayID);
2370 if (!worldOverlayEntry)
2371 break;
2372
2373 for (uint8 j = 0; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX; ++j)
2374 {
2375 if (worldOverlayEntry->AreaID[j])
2376 {
2377 bool valid = true;
2378 for (uint8 i = 0; i < j; ++i)
2379 if (worldOverlayEntry->AreaID[j] == worldOverlayEntry->AreaID[i])
2380 valid = false;
2381 if (valid)
2382 m_AchievementCriteriasByMiscValue[criteria->Type][worldOverlayEntry->AreaID[j]].push_back(criteria);
2383 }
2384 }
2385 }
2386 }
2387
2388 for (uint32 i = 0; i < MAX_CRITERIA_REQUIREMENTS; ++i)
2389 {
2391 {
2393 "ACHIEVEMENT_CRITERIA_CONDITION_MAX must be greater than or equal to %u but is currently equal to %u",
2395
2396 if (i == 0
2397 || criteria->AdditionalRequirements[i].Type != criteria->AdditionalRequirements[i - 1].Type
2398 || criteria->AdditionalRequirements[i].Asset != criteria->AdditionalRequirements[i - 1].Asset)
2399 m_AchievementCriteriasByCondition[criteria->AdditionalRequirements[i].Type][criteria->AdditionalRequirements[i].Asset].push_back(criteria);
2400 }
2401 }
2402
2403 if (criteria->StartTimer)
2404 {
2405 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",
2406 criteria->StartEvent + 1, ACHIEVEMENT_TIMED_TYPE_MAX);
2407 m_AchievementCriteriasByTimedType[criteria->StartEvent].push_back(criteria);
2408 }
2409
2410 ++loaded;
2411 }
2412
2413 TC_LOG_INFO("server.loading", ">> Loaded {} achievement criteria in {} ms.", loaded, GetMSTimeDiffToNow(oldMSTime));
2414}
2415
2417{
2418 uint32 oldMSTime = getMSTime();
2419
2420 if (sAchievementStore.GetNumRows() == 0)
2421 {
2422 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement references.");
2423 return;
2424 }
2425
2426 uint32 count = 0;
2427
2428 for (uint32 entryId = 0; entryId < sAchievementStore.GetNumRows(); ++entryId)
2429 {
2430 AchievementEntry const* achievement = sAchievementStore.LookupEntry(entryId);
2431 if (!achievement || !achievement->SharesCriteria)
2432 continue;
2433
2434 m_AchievementListByReferencedId[achievement->SharesCriteria].push_back(achievement);
2435 ++count;
2436 }
2437
2438 // Once Bitten, Twice Shy (10 player) - Icecrown Citadel
2439 if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(4539))
2440 const_cast<AchievementEntry*>(achievement)->InstanceID = 631; // Correct map requirement (currently has Ulduar)
2441
2442 TC_LOG_INFO("server.loading", ">> Loaded {} achievement references in {} ms.", count, GetMSTimeDiffToNow(oldMSTime));
2443}
2444
2446{
2447 uint32 oldMSTime = getMSTime();
2448
2449 m_criteriaDataMap.clear(); // need for reload case
2450
2451 QueryResult result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data");
2452
2453 if (!result)
2454 {
2455 TC_LOG_INFO("server.loading", ">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty.");
2456 return;
2457 }
2458
2459 uint32 count = 0;
2460
2461 do
2462 {
2463 Field* fields = result->Fetch();
2464 uint32 criteria_id = fields[0].GetUInt32();
2465
2466 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id);
2467
2468 if (!criteria)
2469 {
2470 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains data for non-existing criteria (Entry: {}). Ignored.", criteria_id);
2471 continue;
2472 }
2473
2474 uint32 dataType = fields[1].GetUInt8();
2475 std::string scriptName = fields[4].GetString();
2476 uint32 scriptId = 0;
2477 if (scriptName.length()) // not empty
2478 {
2480 TC_LOG_ERROR("sql.sql", "Table `achievement_criteria_data` contains a ScriptName for non-scripted data type (Entry: {}, type {}), useless data.", criteria_id, dataType);
2481 else
2482 scriptId = sObjectMgr->GetScriptId(scriptName);
2483 }
2484
2485 AchievementCriteriaData data(dataType, fields[2].GetUInt32(), fields[3].GetUInt32(), scriptId);
2486
2487 if (!data.IsValid(criteria))
2488 continue;
2489
2490 // this will allocate empty data set storage
2491 AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id];
2492 dataSet.SetCriteriaId(criteria_id);
2493
2494 // add real data only for not NONE data types
2496 dataSet.Add(data);
2497
2498 // counting data by and data types
2499 ++count;
2500 }
2501 while (result->NextRow());
2502
2503 // post loading checks
2504 for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId)
2505 {
2506 AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId);
2507 if (!criteria)
2508 continue;
2509
2510 switch (criteria->Type)
2511 {
2528 // achievement requires db data
2529 break;
2531 {
2532 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
2533 if (!achievement)
2534 continue;
2535
2536 // There are many achievements with these criteria, use hardcoded check at this moment to pick a simple case
2537 if (achievement->ID == 1282)
2538 break;
2539
2540 continue;
2541 }
2542 case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA: // need skip generic cases
2544 continue;
2545 break;
2546 case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases
2547 if (criteria->Quantity == 0)
2548 continue;
2549 break;
2550 case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL: // skip statistics
2551 if (criteria->Quantity == 0)
2552 continue;
2553 break;
2554 case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE: // need skip generic cases
2555 if (criteria->Quantity != 1)
2556 continue;
2557 break;
2559 case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // only Children's Week achievements
2560 {
2561 AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->AchievementID);
2562 if (!achievement)
2563 continue;
2564 if (achievement->Category != CATEGORY_CHILDRENS_WEEK && achievement->ID != 1785)
2565 continue;
2566 break;
2567 }
2568 default: // type not use DB data, ignore
2569 continue;
2570 }
2571
2573 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);
2574 }
2575
2576 TC_LOG_INFO("server.loading", ">> Loaded {} additional achievement criteria data in {} ms", count, GetMSTimeDiffToNow(oldMSTime));
2577}
2578
2580{
2581 uint32 oldMSTime = getMSTime();
2582
2583 // Populate _allCompletedAchievements with all realm first achievement ids to make multithreaded access safer
2584 // while it will not prevent races, it will prevent crashes that happen because std::unordered_map key was added
2585 // instead the only potential race will happen on value associated with the key
2586 for (uint32 i = 0; i < sAchievementStore.GetNumRows(); ++i)
2587 if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(i))
2589 _allCompletedAchievements[achievement->ID] = SystemTimePoint::min();
2590
2591 QueryResult result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement");
2592
2593 if (!result)
2594 {
2595 TC_LOG_INFO("server.loading", ">> Loaded 0 realm first completed achievements. DB table `character_achievement` is empty.");
2596 return;
2597 }
2598
2599 do
2600 {
2601 Field* fields = result->Fetch();
2602
2603 uint16 achievementId = fields[0].GetUInt16();
2604 AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId);
2605 if (!achievement)
2606 {
2607 // Remove non-existing achievements from all characters
2608 TC_LOG_ERROR("achievement", "Non-existing achievement {} data has been removed from the table `character_achievement`.", achievementId);
2609
2611 stmt->setUInt16(0, uint16(achievementId));
2612 CharacterDatabase.Execute(stmt);
2613
2614 continue;
2615 }
2617 _allCompletedAchievements[achievementId] = SystemTimePoint::max();
2618 }
2619 while (result->NextRow());
2620
2621 TC_LOG_INFO("server.loading", ">> Loaded {} realm first completed achievements in {} ms.", (unsigned long)_allCompletedAchievements.size(), GetMSTimeDiffToNow(oldMSTime));
2622}
2623
2625{
2626 uint32 oldMSTime = getMSTime();
2627
2628 m_achievementRewards.clear(); // need for reload case
2629
2630 // 0 1 2 3 4 5 6 7
2631 QueryResult result = WorldDatabase.Query("SELECT ID, TitleA, TitleH, ItemID, Sender, Subject, Body, MailTemplateID FROM achievement_reward");
2632
2633 if (!result)
2634 {
2635 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement rewards. DB table `achievement_reward` is empty.");
2636 return;
2637 }
2638
2639 do
2640 {
2641 Field* fields = result->Fetch();
2642 uint32 id = fields[0].GetUInt32();
2643 AchievementEntry const* achievement = sAchievementStore.LookupEntry(id);
2644 if (!achievement)
2645 {
2646 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` contains a wrong achievement ID ({}), ignored.", id);
2647 continue;
2648 }
2649
2650 AchievementReward reward;
2651 reward.TitleId[0] = fields[1].GetUInt32();
2652 reward.TitleId[1] = fields[2].GetUInt32();
2653 reward.ItemId = fields[3].GetUInt32();
2654 reward.SenderCreatureId = fields[4].GetUInt32();
2655 reward.Subject = fields[5].GetString();
2656 reward.Body = fields[6].GetString();
2657 reward.MailTemplateId = fields[7].GetUInt32();
2658
2659 // must be title or mail at least
2660 if (!reward.TitleId[0] && !reward.TitleId[1] && !reward.SenderCreatureId)
2661 {
2662 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not contain title or item reward data. Ignored.", id);
2663 continue;
2664 }
2665
2666 if (achievement->Faction == ACHIEVEMENT_FACTION_ANY && (!reward.TitleId[0] ^ !reward.TitleId[1]))
2667 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]);
2668
2669 if (reward.TitleId[0])
2670 {
2671 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[0]);
2672 if (!titleEntry)
2673 {
2674 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: {}) contains an invalid title id ({}) in `title_A`, set to 0", id, reward.TitleId[0]);
2675 reward.TitleId[0] = 0;
2676 }
2677 }
2678
2679 if (reward.TitleId[1])
2680 {
2681 CharTitlesEntry const* titleEntry = sCharTitlesStore.LookupEntry(reward.TitleId[1]);
2682 if (!titleEntry)
2683 {
2684 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (Entry: {}) contains an invalid title id ({}) in `title_H`, set to 0", id, reward.TitleId[1]);
2685 reward.TitleId[1] = 0;
2686 }
2687 }
2688
2689 //check mail data before item for report including wrong item case
2690 if (reward.SenderCreatureId)
2691 {
2692 if (!sObjectMgr->GetCreatureTemplate(reward.SenderCreatureId))
2693 {
2694 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) contains an invalid creature ID {} as sender, mail reward skipped.", id, reward.SenderCreatureId);
2695 reward.SenderCreatureId = 0;
2696 }
2697 }
2698 else
2699 {
2700 if (reward.ItemId)
2701 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);
2702
2703 if (!reward.Subject.empty())
2704 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but contains a mail subject.", id);
2705
2706 if (!reward.Body.empty())
2707 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but contains mail text.", id);
2708
2709 if (reward.MailTemplateId)
2710 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) does not have sender data, but has a MailTemplate.", id);
2711 }
2712
2713 if (reward.MailTemplateId)
2714 {
2715 if (!sMailTemplateStore.LookupEntry(reward.MailTemplateId))
2716 {
2717 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) is using an invalid MailTemplate ({}).", id, reward.MailTemplateId);
2718 reward.MailTemplateId = 0;
2719 }
2720 else if (!reward.Subject.empty() || !reward.Body.empty())
2721 TC_LOG_ERROR("sql.sql", "Table `achievement_reward` (ID: {}) is using MailTemplate ({}) and mail subject/text.", id, reward.MailTemplateId);
2722 }
2723
2724 if (reward.ItemId)
2725 {
2726 if (!sObjectMgr->GetItemTemplate(reward.ItemId))
2727 {
2728 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);
2729 reward.ItemId = 0;
2730 }
2731 }
2732
2733 m_achievementRewards[id] = reward;
2734 } while (result->NextRow());
2735
2736 TC_LOG_INFO("server.loading", ">> Loaded {} achievement rewards in {} ms.", uint32(m_achievementRewards.size()), GetMSTimeDiffToNow(oldMSTime));
2737}
2738
2740{
2741 uint32 oldMSTime = getMSTime();
2742
2743 m_achievementRewardLocales.clear(); // need for reload case
2744
2745 // 0 1 2 3
2746 QueryResult result = WorldDatabase.Query("SELECT ID, Locale, Subject, Body FROM achievement_reward_locale");
2747
2748 if (!result)
2749 {
2750 TC_LOG_INFO("server.loading", ">> Loaded 0 achievement reward locale strings. DB table `achievement_reward_locale` is empty.");
2751 return;
2752 }
2753
2754 do
2755 {
2756 Field* fields = result->Fetch();
2757
2758 uint32 id = fields[0].GetUInt32();
2759 std::string localeName = fields[1].GetString();
2760
2761 LocaleConstant locale = GetLocaleByName(localeName);
2762 if (locale == LOCALE_enUS)
2763 continue;
2764
2765 if (m_achievementRewards.find(id) == m_achievementRewards.end())
2766 {
2767 TC_LOG_ERROR("sql.sql", "Table `achievement_reward_locale` (ID: {}) contains locale strings for a non-existing achievement reward.", id);
2768 continue;
2769 }
2770
2772 ObjectMgr::AddLocaleString(fields[2].GetString(), locale, data.Subject);
2773 ObjectMgr::AddLocaleString(fields[3].GetString(), locale, data.Text);
2774 } while (result->NextRow());
2775
2776 TC_LOG_INFO("server.loading", ">> Loaded {} achievement reward locale strings in {} ms.", uint32(m_achievementRewardLocales.size()), GetMSTimeDiffToNow(oldMSTime));
2777}
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
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:296
@ 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 RAID_DIFFICULTY_MASK_25MAN
Definition DBCEnums.h:292
#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:39
#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:340
#define PLAYER_EXPLORED_ZONES_SIZE
Definition Player.h:117
DrunkenState
Definition Player.h:333
std::set< uint32 > RewardedQuestSet
Definition Player.h:485
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
AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]
static AchievementGlobalMgr * instance()
bool IsRealmCompleted(AchievementEntry const *achievement) const
AchievementCriteriaListByAchievement m_AchievementCriteriaListByAchievement
AchievementRewards m_achievementRewards
void SetRealmCompleted(AchievementEntry const *achievement)
AchievementListByReferencedId m_AchievementListByReferencedId
static char const * GetCriteriaTypeString(AchievementCriteriaTypes type)
AchievementRewardLocales m_achievementRewardLocales
static AchievementCriteriaEntryList const EmptyCriteriaList
AchievementCriteriaListByMiscValue m_AchievementCriteriasByMiscValue[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]
AchievementCriteriaDataMap m_criteriaDataMap
AchievementCriteriaListByCondition m_AchievementCriteriasByCondition[ACHIEVEMENT_CRITERIA_CONDITION_MAX]
std::unordered_map< uint32, SystemTimePoint > _allCompletedAchievements
AchievementCriteriaEntryList m_AchievementCriteriasByTimedType[ACHIEVEMENT_TIMED_TYPE_MAX]
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
void RemoveCriteriaProgress(AchievementCriteriaEntry const *entry)
static void DeleteFromDB(ObjectGuid lowguid)
bool IsCompletedAchievement(AchievementEntry const *entry)
void CheckAllAchievementCriteria()
void LoadFromDB(PreparedQueryResult achievementResult, PreparedQueryResult criteriaResult)
void BuildAllDataPacket(Player const *receiver, WorldPacket *data) const
void SendRespondInspectAchievements(Player *player) const
AchievementMgr(Player *player)
void SendAchievementEarned(AchievementEntry const *achievement) const
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
void appendPackGUID(uint64 guid)
Definition ByteBuffer.h:464
size_t wpos() const
Definition ByteBuffer.h:321
void put(std::size_t pos, T value)
Definition ByteBuffer.h:137
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:4296
InstanceScript * GetInstanceScript()
Definition Map.h:887
virtual bool CheckAchievementCriteriaMeet(uint32, Player const *, Unit const *=nullptr, uint32=0)
Definition Item.h:62
virtual void SaveToDB(CharacterDatabaseTransaction trans)
Definition Item.cpp:323
static Item * CreateItem(uint32 itemEntry, uint32 count, Player const *player=nullptr)
Definition Item.cpp:1044
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:281
bool IsDungeon() const
Definition Map.cpp:4236
uint8 GetSpawnMode() const
Definition Map.h:388
bool IsRaid() const
Definition Map.cpp:4246
bool Is25ManRaid() const
Definition Map.cpp:4261
uint32 GetPlayersCountExceptGMs() const
Definition Map.cpp:3659
uint32 GetId() const
Definition Map.cpp:4216
InstanceMap * ToInstanceMap()
Definition Map.h:520
LowType GetCounter() const
Definition ObjectGuid.h:156
std::string ToString() const
static std::string_view GetLocaleString(std::vector< std::string > const &data, size_t locale)
Definition ObjectMgr.h:1525
static void AddLocaleString(std::string &&value, LocaleConstant localeConstant, std::vector< std::string > &data)
PackedGuid const & GetPackGUID() const
Definition Object.h:80
static Unit * ToUnit(Object *o)
Definition Object.h:192
uint32 GetUInt32Value(uint16 index) const
Definition Object.cpp:249
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:180
uint32 GetTeam() const
Definition Player.h:1832
RewardedQuestSet const & getRewardedQuests() const
Definition Player.h:1414
uint8 GetDrunkValue() const
Definition Player.h:1883
void SendDirectMessage(WorldPacket const *data) const
Definition Player.cpp:6161
bool HasTitle(uint32 bitIndex) const
Definition Player.cpp:24301
WorldSession * GetSession() const
Definition Player.h:1719
static uint32 TeamForRace(uint8 race)
Definition Player.cpp:6269
TeamId GetTeamId() const
Definition Player.h:1833
PlayerSpellMap const & GetSpellMap() const
Definition Player.h:1534
uint32 GetArenaTeamId(uint8 slot) const
Definition Player.h:1629
Battleground * GetBattleground() const
Definition Player.cpp:23049
Group * GetGroup()
Definition Player.h:2171
bool IsGameMaster() const
Definition Player.h:998
void SetTitle(CharTitlesEntry const *title, bool lost=false)
Definition Player.cpp:24316
ReputationMgr & GetReputationMgr()
Definition Player.h:1848
static DrunkenState GetDrunkenstateByValue(uint8 value)
Definition Player.cpp:861
void setUInt16(uint8 index, uint16 value)
void setUInt32(uint8 index, uint32 value)
int32 GetZoneOrSort() const
Definition QuestDef.h:231
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:769
bool HealthAbovePct(int32 pct) const
Definition Unit.h:919
uint8 GetClass() const
Definition Unit.h:895
Gender GetGender() const
Definition Unit.h:898
bool HasAuraEffect(uint32 spellId, uint8 effIndex, ObjectGuid caster=ObjectGuid::Empty) const
Definition Unit.cpp:4505
uint8 GetLevel() const
Definition Unit.h:889
uint8 GetRace() const
Definition Unit.h:892
uint32 GetMapId() const
Definition Position.h:193
Map * GetMap() const
Definition Object.h:449
std::string const & GetName() const
Definition Object.h:382
void GetZoneAndAreaId(uint32 &zoneid, uint32 &areaid) const
Definition Object.h:375
LocaleConstant GetSessionDbLocaleIndex() const
Minutes GetTimezoneOffset() const
bool HasPermission(uint32 permissionId)
void SetUtcTimeFromUnixTime(std::time_t unixTime)
Definition WowTime.cpp:86
@ SMSG_ACHIEVEMENT_EARNED
Definition Opcodes.h:1157
@ SMSG_SERVER_FIRST_ACHIEVEMENT
Definition Opcodes.h:1205
@ SMSG_RESPOND_INSPECT_ACHIEVEMENTS
Definition Opcodes.h:1161
@ SMSG_CRITERIA_DELETED
Definition Opcodes.h:1211
@ SMSG_ALL_ACHIEVEMENT_DATA
Definition Opcodes.h:1178
@ SMSG_CRITERIA_UPDATE
Definition Opcodes.h:1159
@ SMSG_ACHIEVEMENT_DELETED
Definition Opcodes.h:1212
#define sWorld
Definition World.h:900
@ CONFIG_BIRTHDAY_TIME
Definition World.h:381
@ CONFIG_LISTEN_RANGE_SAY
Definition World.h:189
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 AreaID[MAX_WORLD_MAP_OVERLAY_AREA_IDX]