root/trunk/src/arcemu-world/AchievementMgr.cpp @ 2950

Revision 2950, 83.9 kB (checked in by Dfighter, 11 months ago)

Merging the Untested branch back to Trunk.
Trunk is now 3.2.2 compatible.

  • Property svn:eol-style set to native
  • Property ff set to
    *.cpp = svn:eol-style=native
    Makefile = svn:eol-style=native
    README = svn:eol-style=native
    CHANGELOG = svn:eol-style=native
    LICENSE = svn:eol-style=native
  • Property svn:keywords set to Date Author Rev
Line 
1/*
2 * ArcEmu MMORPG Server
3 * Copyright (C) 2005-2007 Ascent Team <http://www.ascentemu.com/>
4 * Copyright (C) 2008-2009 <http://www.ArcEmu.org/>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21
22#include "StdAfx.h"
23#ifdef ENABLE_ACHIEVEMENTS
24/**
25        Takes achievementlink c-string and returns the ID value from it.
26*/
27uint32 GetAchievementIDFromLink(const char* achievementlink)
28{
29        if( achievementlink == NULL )
30                return 0;
31
32        const char* ptr = strstr(achievementlink, "|Hachievement:");
33        if( ptr == NULL )
34                return 0;
35
36        // achievement id is just past "|Hachievement:" (14 bytes)
37        return atol(ptr + 14);
38}
39
40/**
41        True if CriteriaProgress should be sent to Player; False if CriteriaProgress should not be sent.
42        If the CriteriaProgress specified should not be sent to the Player, it returns false, otherwise it returns true.
43        Examples of CriteriaProgress that should not be sent to the Player are:
44                1. When counter is zero or negative, which would indicate the achievement hasn't been started yet.
45                2. Reputation type achievements, where the progress is not shown in the client.
46                3. Reach-Level type achievements, where the progress is not shown in the client.
47*/
48bool SendAchievementProgress(const CriteriaProgress* c)
49{
50        if( c == NULL || c->counter <= 0 )
51                // achievement not started yet, don't send progress
52                return false;
53
54        AchievementCriteriaEntry const* acEntry = dbcAchievementCriteriaStore.LookupEntry(c->id);
55        if( !acEntry )
56                return false;
57
58        if( acEntry->requiredType == ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION )
59                // Exalted with X faction (don't send 12323/42000 progress, it's not shown anyway)
60                return false;
61
62        if( acEntry->requiredType == ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL )
63                // Reach level (don't send 7/80 progress, it's not shown anyway)
64                return false;
65
66        return true;
67}
68
69/**
70        True if CriteriaProgress should be saved to database.  False if CriteriaProgress should not be saved to database.
71        Not all achievement progresses get saved to progress database, since some are saved in the character database,
72                or are easily computable when the player logs in.
73*/
74bool SaveAchievementProgressToDB(const CriteriaProgress* c)
75{
76        if( c->counter <= 0 )
77        {
78                // don't save it if it's not started yet
79                return false;
80        }
81        AchievementCriteriaEntry const* acEntry = dbcAchievementCriteriaStore.LookupEntry(c->id);
82        switch(acEntry->requiredType)
83        {
84                // these get updated when character logs on, don't save to character progress db
85                case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
86                case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
87                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
88                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
89                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
90                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
91                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
92                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
93                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
94                case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS:
95                case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
96                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
97                case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
98                        return false;
99                default:
100                        break;
101        }
102        return true;
103}
104
105/**
106        true if the achievement should be shown; false otherwise
107*/
108bool ShowCompletedAchievement(uint32 achievementID, const Player* plr)
109{
110        switch(achievementID)
111        {
112                case  457: // Realm First! Level 80
113                case  467: // Realm First! Level 80 Shaman
114                case  466: // Realm First! Level 80 Druid
115                case  465: // Realm First! Level 80 Paladin
116                case  464: // Realm First! Level 80 Priest
117                case  463: // Realm First! Level 80 Warlock
118                case  462: // Realm First! Level 80 Hunter
119                case  461: // Realm First! Level 80 Death Knight
120                case  460: // Realm First! Level 80 Mage
121                case  459: // Realm First! Level 80 Warrior
122                case  458: // Realm First! Level 80 Rogue
123                case 1404: // Realm First! Level 80 Gnome
124                case 1405: // Realm First! Level 80 Blood Elf
125                case 1406: // Realm First! Level 80 Draenei
126                case 1407: // Realm First! Level 80 Dwarf
127                case 1408: // Realm First! Level 80 Human
128                case 1409: // Realm First! Level 80 Night Elf
129                case 1410: // Realm First! Level 80 Orc
130                case 1411: // Realm First! Level 80 Tauren
131                case 1412: // Realm First! Level 80 Troll
132                case 1413: // Realm First! Level 80 Forsaken
133                case 1415: // Realm First! Grand Master Alchemist
134                case 1414: // Realm First! Grand Master Blacksmith
135                case 1416: // Realm First! Cooking Grand Master
136                case 1417: // Realm First! Grand Master Enchanter
137                case 1418: // Realm First! Grand Master Engineer
138                case 1419: // Realm First! First Aid Grand Master
139                case 1420: // Realm First! Grand Master Angler
140                case 1421: // Realm First! Grand Master Herbalist
141                case 1422: // Realm First! Grand Master Scribe
142                case 1423: // Realm First! Grand Master Jewelcrafter
143                case 1424: // Realm First! Grand Master Leatherworker
144                case 1425: // Realm First! Grand Master Miner
145                case 1426: // Realm First! Grand Master Skinner
146                case 1427: // Realm First! Grand Master Tailor
147                case 1463: // Realm First! Northrend Vanguard: First player on the realm to gain exalted reputation with the Argent Crusade, Wyrmrest Accord, Kirin Tor and Knights of the Ebon Blade.
148                        {
149                                QueryResult* achievementResult = CharacterDatabase.Query("SELECT guid FROM character_achievement WHERE achievement=%u ORDER BY date LIMIT 1", achievementID);
150                                if( achievementResult != NULL )
151                                {
152                                        Field* field = achievementResult->Fetch();
153                                        if( field != NULL )
154                                        {
155                                                // somebody has this Realm First achievement... is it this player?
156                                                uint64 firstguid = field->GetUInt32();
157                                                if( firstguid != (uint32)plr->GetGUID() )
158                                                {
159                                                        // nope, somebody else was first.
160                                                        delete achievementResult;
161                                                        return false;
162                                                }
163                                        }
164                                        delete achievementResult;
165                                }
166                        }
167                        break;
168// All raid members should receive these last 3 Realm First achievements when they first occur.
169// (not implemented yet)
170//              case 1400: // Realm First! Magic Seeker: Participated in the realm first defeat of Malygos on Heroic Difficulty.
171//              case  456: // Realm First! Obsidian Slayer: Participated in the realm first defeat of Sartharion the Onyx Guardian on Heroic Difficulty.
172//              case 1402: // Realm First! Conqueror of Naxxramas: Participated in the realm first defeat of Kel'Thuzad on Heroic Difficulty in Naxxramas.
173                default:
174                        break;
175        }
176        return true;
177}
178
179/**
180        AchievementMgr constructor
181*/
182AchievementMgr::AchievementMgr(Player *player)
183:
184m_player(player),
185isCharacterLoading(true)
186{
187
188}
189
190/**
191        AchievementMgr destructor
192*/
193AchievementMgr::~AchievementMgr()
194{
195        for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
196                delete iter->second;
197        m_criteriaProgress.clear();
198        m_completedAchievements.clear();
199}
200
201/**
202        Save Achievement data to database
203        Saves all completed achievements to database.  Saves all achievement progresses that have been started, and that aren't calculated on login, to database.
204*/
205void AchievementMgr::SaveToDB()
206{
207        if( !m_completedAchievements.empty() )
208        {
209                std::ostringstream ss;
210                ss << "REPLACE INTO character_achievement (guid, achievement, date) VALUES ";
211                bool first = true;
212                for(CompletedAchievementMap::iterator iter = m_completedAchievements.begin(); iter!=m_completedAchievements.end(); iter++)
213                {
214                        if( ss.str().length() >= 16000 )
215                        {
216                                // SQL query length is limited to 16384 characters
217                                CharacterDatabase.Execute( ss.str().c_str() );
218                                ss.str("");
219                                ss << "REPLACE INTO character_achievement (guid, achievement, date) VALUES ";
220                                first = true;
221                        }
222                        if( !first )
223                        {
224                                ss << ", ";
225                        }
226                        else
227                        {
228                                first = false;
229                        }
230                        ss << "("<<GetPlayer()->GetUInt32Value(OBJECT_FIELD_GUID) << ", " << iter->first << ", " << iter->second << ")";
231                }
232                CharacterDatabase.Execute( ss.str().c_str() );
233        }
234
235        if( !m_criteriaProgress.empty() )
236        {
237                std::ostringstream ss;
238                ss << "REPLACE INTO character_achievement_progress (guid, criteria, counter, date) VALUES ";
239                bool first = true;
240                for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
241                {
242                        if( SaveAchievementProgressToDB(iter->second) )
243                        {
244                                // only save some progresses, others will be updated when character logs in
245                                if( ss.str().length() >= 16000 )
246                                {
247                                        // SQL query length is limited to 16384 characters
248                                        CharacterDatabase.Execute( ss.str().c_str() );
249                                        ss.str("");
250                                        ss << "REPLACE INTO character_achievement_progress (guid, criteria, counter, date) VALUES ";
251                                        first = true;
252                                }
253                                if( !first )
254                                {
255                                        ss << ", ";
256                                }
257                                else
258                                {
259                                        first = false;
260                                }
261                                ss << "(" << GetPlayer()->GetUInt32Value(OBJECT_FIELD_GUID) << ", " << iter->first << ", " << iter->second->counter << ", " << iter->second->date << ")";
262                        }
263                }
264                if( !first )
265                {
266                        // don't execute query if there's no entries to save
267                        CharacterDatabase.Execute( ss.str().c_str() );
268                }
269        }
270}
271
272/**
273        Load achievements from database.
274        Loads completed achievements and achievement progresses from the database.
275*/
276void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult)
277{
278        if( achievementResult )
279        {
280                do
281                {
282                        Field *fields = achievementResult->Fetch();
283                        uint32 id = fields[0].GetUInt32();
284                        if( m_completedAchievements[id] == NULL )
285                                m_completedAchievements[id] = fields[1].GetUInt32();
286                        else 
287                                sLog.outError("Duplicate completed achievement %u for player %u, skipping", id, (uint32)m_player->GetGUID() );
288                } while(achievementResult->NextRow());
289                delete achievementResult;
290        }
291
292        if( criteriaResult )
293        {
294                do
295                {
296                        Field *fields = criteriaResult->Fetch();
297                        uint32 progress_id = fields[0].GetUInt32();
298                        if( m_criteriaProgress[ progress_id ] == NULL )
299                        {
300                                CriteriaProgress *progress = new CriteriaProgress( progress_id, fields[1].GetUInt32(), fields[2].GetUInt64() );
301                                m_criteriaProgress[ progress_id ] = progress;
302                        }
303                        else
304                                sLog.outError( "Duplicate criteria progress %u for player %u, skipping", progress_id, (uint32) m_player->GetGUID() );
305
306                }while( criteriaResult->NextRow() );
307                delete criteriaResult;
308        }
309}
310
311/**
312        Sends message to player(s) that the achievement has been completed.
313        Realm first! achievements get sent to all players currently online.
314        All other achievements get sent to all of the achieving player's guild members, group members, and other in-range players.
315*/
316void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement)
317{
318        if( achievement == NULL || isCharacterLoading )
319        {
320                return;
321        }
322
323        const char *msg = "|Hplayer:$N|h[$N]|h has earned the achievement $a!";
324        uint32* guidList = NULL;
325        uint32 guidCount = 0;
326        uint32 guidIndex = 0;
327
328        // Send Achievement message to everyone currently on the server
329        if( achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH) )
330        {
331                WorldPacket data(SMSG_SERVER_FIRST_ACHIEVEMENT, 200);
332                data << GetPlayer()->GetName();
333                data << uint64(GetPlayer()->GetGUID());
334                data << uint32(achievement->ID);
335                data << uint32(0);
336                sWorld.SendGlobalMessage(&data);
337        }
338        else
339        {
340                // allocate enough space
341                guidList = new uint32[sWorld.GetSessionCount() + 256];
342                // Send Achievement message to every guild member currently on the server
343                if( GetPlayer()->IsInGuild() )
344                {
345                        Guild* guild = GetPlayer()->getPlayerInfo()->guild;
346                        WorldPacket data(SMSG_MESSAGECHAT, 200);
347                        data << uint8(CHAT_MSG_GUILD_ACHIEVEMENT);
348                        data << uint32(LANG_UNIVERSAL);
349                        data << uint64(GetPlayer()->GetGUID());
350                        data << uint32(5);
351                        data << uint64(GetPlayer()->GetGUID());
352                        data << uint32(strlen(msg)+1);
353                        data << msg;
354                        data << uint8(0);
355                        data << uint32(achievement->ID);
356//                      guild->SendPacket(&data);
357                        GuildMemberMap::iterator guildItr = guild->GetGuildMembersBegin();
358                        GuildMemberMap::iterator guildItrLast = guild->GetGuildMembersEnd();
359                        while(guildItr != guildItrLast)
360                        {
361                                if( guildItr->first->m_loggedInPlayer && guildItr->first->m_loggedInPlayer->GetSession() )
362                                {
363                                        guildItr->first->m_loggedInPlayer->GetSession()->SendPacket(&data);
364                                        // store GUID, so we don't send message to the same player again (anti-spam)
365                                        guidList[guidCount++] = guildItr->first->guid;
366                                }
367                                ++guildItr;
368                        }
369                }
370                // Build generic packet for group members and nearby players
371                WorldPacket cdata(SMSG_MESSAGECHAT, 200);
372                cdata << uint8(CHAT_MSG_ACHIEVEMENT);
373                cdata << uint32(LANG_UNIVERSAL);
374                cdata << uint64(GetPlayer()->GetGUID());
375                cdata << uint32(5);
376                cdata << uint64(GetPlayer()->GetGUID());
377                cdata << uint32(strlen(msg)+1);
378                cdata << msg;
379                cdata << uint8(0);
380                cdata << uint32(achievement->ID);
381                bool alreadySent;
382                // Send Achievement message to group members
383                Group* grp = GetPlayer()->GetGroup();
384               
385                if( grp )
386                {
387//                      grp->SendPacketToAll(&cdata);
388                        uint8 i = 0;
389                        GroupMembersSet::iterator groupItr;
390                        GroupMembersSet::iterator groupItrLast;
391                        grp->Lock();
392                        for(; i < grp->GetSubGroupCount(); ++i)
393                        {
394                                SubGroup* sg = grp->GetSubGroup(i);
395                                if( sg == NULL )
396                                {
397                                        continue;
398                                }
399
400                                groupItr = sg->GetGroupMembersBegin();
401                                groupItrLast = sg->GetGroupMembersEnd();
402                                for(; groupItr != groupItrLast; ++groupItr)
403                                {
404                                        if( (*groupItr)->m_loggedInPlayer != NULL && (*groupItr)->m_loggedInPlayer->GetSession() )
405                                        {
406                                                // check if achievement message has already been sent to this player (if they received a guild achievement message already)
407                                                alreadySent = false;
408                                                for(guidIndex = 0; guidIndex < guidCount; ++guidIndex)
409                                                {
410                                                        if( guidList[guidIndex] == (*groupItr)->guid )
411                                                        {
412                                                                alreadySent = true;
413                                                                guidIndex = guidCount;
414                                                        }
415                                                }
416                                                if( !alreadySent )
417                                                {
418                                                        (*groupItr)->m_loggedInPlayer->GetSession()->SendPacket(&cdata);
419                                                        guidList[guidCount++] = (*groupItr)->guid;
420                                                }
421                                        }
422                                }
423                        }
424                        grp->Unlock();
425                }
426                // Send Achievement message to nearby players
427                std::set<Player*>::iterator inRangeItr = GetPlayer()->GetInRangePlayerSetBegin();
428                std::set<Player*>::iterator inRangeItrLast = GetPlayer()->GetInRangePlayerSetEnd();
429                for(; inRangeItr != inRangeItrLast; ++inRangeItr)
430                {
431                        if( (*inRangeItr) && (*inRangeItr)->GetSession() &&  !(*inRangeItr)->Social_IsIgnoring( GetPlayer()->GetLowGUID() ) )
432                        {
433                                // check if achievement message has already been sent to this player (in guild or group)
434                                alreadySent = false;
435                                for(guidIndex = 0; guidIndex < guidCount; ++guidIndex)
436                                {
437                                        if( guidList[guidIndex] == (*inRangeItr)->GetLowGUID() )
438                                        {
439                                                alreadySent = true;
440                                                guidIndex = guidCount;
441                                        }
442                                }
443                                if( !alreadySent )
444                                {
445                                        (*inRangeItr)->GetSession()->SendPacket(&cdata);
446                                        guidList[guidCount++] = (*inRangeItr)->GetLowGUID();
447                                }
448                        }
449                }
450                // Have we sent the message to the achieving player yet?
451                alreadySent = false;
452                for(guidIndex = 0; guidIndex < guidCount; ++guidIndex)
453                {
454                        if( guidList[guidIndex] == GetPlayer()->GetLowGUID() )
455                        {
456                                alreadySent = true;
457                                guidIndex = guidCount;
458                        }
459                        if( !alreadySent )
460                        {
461                                GetPlayer()->GetSession()->SendPacket(&cdata);
462                        }
463                }
464        }
465//      GetPlayer()->SendMessageToSet(&cdata, true);
466
467        WorldPacket data( SMSG_ACHIEVEMENT_EARNED, 30);
468        data << GetPlayer()->GetNewGUID();
469        data << uint32( achievement->ID );
470        data << uint32( secsToTimeBitFields(UNIXTIME) );
471        data << uint32(0);
472        GetPlayer()->GetSession()->SendPacket(&data);
473        if( guidList )
474        {
475                delete [] guidList;
476        }
477}
478
479/**
480        Sends update to achievement criteria to the player.
481*/
482void AchievementMgr::SendCriteriaUpdate(CriteriaProgress* progress)
483{
484        if( progress == NULL || isCharacterLoading )
485        {
486                return;
487        }
488
489        WorldPacket data(SMSG_CRITERIA_UPDATE, 32);
490        data << uint32(progress->id);
491
492        data.appendPackGUID(progress->counter);
493
494        data << GetPlayer()->GetNewGUID();
495        data << uint32(0);
496        data << uint32(secsToTimeBitFields(progress->date));
497        data << uint32(0);  // timer 1
498        data << uint32(0);  // timer 2
499        if( !GetPlayer()->IsInWorld() ) //VLack: maybe we should NOT send these delayed, for 3.1.1, but seems logical
500                GetPlayer()->CopyAndSendDelayedPacket(&data);
501        else
502                GetPlayer()->GetSession()->SendPacket(&data);
503}
504
505/**
506        Updates ALL achievement criteria
507        This is called during player login to update some criteria which aren't saved in achievement progress DB,
508                since they are saved in the character DB or can easily be computed.
509*/
510void AchievementMgr::CheckAllAchievementCriteria()
511{
512        for(uint32 i=0; i<ACHIEVEMENT_CRITERIA_TYPE_TOTAL; i++)
513                UpdateAchievementCriteria(AchievementCriteriaTypes(i));
514}
515
516/**
517        Updates achievement criteria of the specified type
518        This is what should be called from other places in the code (upon killing a monster, or looting an object, or completing a quest, etc.).
519        miscvalue1, miscvalue2 depend on the achievement type.
520        Generally, miscvalue1 is an ID of some type (quest ID, item ID, faction ID, etc.), and miscvalue2 is the amount to increase the progress.
521*/
522void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, int32 miscvalue1, int32 miscvalue2, uint32 time)
523{
524        uint64 selectedGUID;
525        if( type == ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE )
526        {
527                selectedGUID = GetPlayer()->GetSelection();
528        }
529        AchievementCriteriaEntryList const& achievementCriteriaList = objmgr.GetAchievementCriteriaByType(type);
530        for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
531        {
532                AchievementCriteriaEntry const *achievementCriteria = (*i);
533
534                if( IsCompletedCriteria(achievementCriteria) )
535                {
536                        // don't bother updating it, if it has already been completed
537                        continue;
538                }
539
540                if( (achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP) && GetPlayer()->GetGroup() )
541                {
542                        // criteria requires that the player not be in a group, but they are in a group, so don't update it
543                        continue;
544                }
545
546                AchievementEntry const *achievement = dbcAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
547                if( !achievement )
548                {
549                        // referred achievement not found (shouldn't normally happen)
550                        continue;
551                }
552
553                if( (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) ||
554                        (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE) )
555                {
556                        // achievement requires a faction of which the player is not a member
557                        continue;
558                }
559
560                switch (type)
561                {
562                        //Start of Achievement List
563                        case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
564                                SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
565                                break;
566                        case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
567                        case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
568                                if( achievementCriteria->loot_item.itemID == static_cast<uint32>( miscvalue1 ))
569                                {
570                                        UpdateCriteriaProgress(achievementCriteria, miscvalue2);
571                                }
572                                break;
573                        case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
574                                if( GetPlayer()->HasOverlayUncovered(achievementCriteria->explore_area.areaReference) )
575                                {
576                                        SetCriteriaProgress(achievementCriteria, 1);
577                                }
578                                break;
579                        case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
580                                if( achievementCriteria->complete_quests_in_zone.zoneID == static_cast<uint32>( miscvalue1 ))
581                                {
582                                        UpdateCriteriaProgress(achievementCriteria, 1);
583                                }
584                                break;
585                        case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
586                                if( achievementCriteria->complete_quest.questID == static_cast<uint32>( miscvalue1 ))
587                                {
588                                        UpdateCriteriaProgress(achievementCriteria, 1);
589                                }
590                                break;
591                        case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
592                                if( achievementCriteria->gain_reputation.factionID == static_cast<uint32>( miscvalue1 ))
593                                {
594                                        SetCriteriaProgress(achievementCriteria, miscvalue2);
595                                }
596                                break;
597                        case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
598                                if( achievementCriteria->learn_spell.spellID == static_cast<uint32>( miscvalue1 ))
599                                {
600                                        SetCriteriaProgress(achievementCriteria, miscvalue2);
601                                }
602                                break;
603                        case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS:
604                                // Vanity pets owned - miscvalue1==778
605                                // Number of mounts  - miscvalue1==777
606                                if( achievementCriteria->number_of_mounts.unknown == static_cast<uint32>( miscvalue1 ))
607                                {
608                                        UpdateCriteriaProgress(achievementCriteria, 1);
609                                }
610                                break;
611                        case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
612                                if( achievementCriteria->kill_creature.creatureID == static_cast<uint32>( miscvalue1 ))
613                                {
614                                        switch(achievement->ID)
615                                        {
616                                                case 2556: // Pest Control
617                                                        if(   (miscvalue1== 3300 && achievementCriteria->index== 1)   // Adder
618                                                                || (miscvalue1==32261 && achievementCriteria->index== 2)   // Crystal Spider
619                                                                || (miscvalue1==24270 && achievementCriteria->index== 3)   // Devouring Maggot
620                                                                || (miscvalue1== 9699 && achievementCriteria->index== 4)   // Fire Beetle
621                                                                || (miscvalue1==24174 && achievementCriteria->index== 5)   // Fjord Rat
622                                                                || (miscvalue1==32258 && achievementCriteria->index== 6)   // Gold Beetle
623                                                                || (miscvalue1==16068 && achievementCriteria->index== 7)   // Larva
624                                                                || (miscvalue1==16030 && achievementCriteria->index== 8)   // Maggot
625                                                                || (miscvalue1== 4953 && achievementCriteria->index== 9)   // Moccasin
626                                                                || (miscvalue1== 6271 && achievementCriteria->index==10)   // Mouse
627                                                                || (miscvalue1== 4075 && achievementCriteria->index==11)   // Rat
628                                                                || (miscvalue1== 4076 && achievementCriteria->index==12)   // Roach
629                                                                || (miscvalue1==15476 && achievementCriteria->index==13)   // Scorpion
630                                                                || (miscvalue1== 2914 && achievementCriteria->index==14)   // Snake
631                                                                || (miscvalue1==14881 && achievementCriteria->index==15)   // Spider
632                                                                || (miscvalue1==32428 && achievementCriteria->index==16)   // Underbelly Rat
633                                                                || (miscvalue1==28202 && achievementCriteria->index==17) ) // Zul'Drak Rat
634                                                        {
635                                                                SetCriteriaProgress(achievementCriteria, 1);
636                                                        }
637                                                        break;
638// Kill creature X in Heroic dungeon
639                                                case 489: // Heroic: Utgarde Keep
640                                                case 490: // Heroic: The Nexus
641                                                case 491: // Heroic: Azjol-Nerub
642                                                case 492: // Heroic: Ahn'kahet: The Old Kingdom
643                                                case 493: // Heroic: Drak'Tharon Keep
644                                                case 494: // Heroic: The Violet Hold
645                                                case 495: // Heroic: Gundrak
646                                                case 496: // Heroic: Halls of Stone
647                                                case 497: // Heroic: Halls of Lightning
648                                                case 498: // Heroic: The Oculus
649                                                case 499: // Heroic: Utgarde Pinnacle
650                                                case 500: // Heroic: The Culling of Stratholme
651                                                case 563: // Heroic: The Arachnid Quarter
652                                                case 565: // Heroic: The Construct Quarter
653                                                case 567: // Heroic: The Plague Quarter
654                                                case 569: // Heroic: The Military Quarter
655                                                case 573: // Heroic: Sapphiron's Demise
656                                                case 575: // Heroic: Kel'Thuzad's Defeat
657                                                case 577: // Heroic: The Fall of Naxxramas
658                                                case 623: // Heroic: The Spellweaver's Downfall
659                                                case 625: // Heroic: Besting the Black Dragonflight
660                                                case 667: // Heroic: Hellfire Ramparts
661                                                case 668: // Heroic: The Blood Furnace
662                                                case 669: // Heroic: The Slave Pens
663                                                case 670: // Heroic: Underbog
664                                                case 671: // Heroic: Mana-Tombs
665                                                case 672: // Heroic: Auchenai Crypts
666                                                case 673: // Heroic: The Escape From Durnholde
667                                                case 674: // Heroic: Sethekk Halls
668                                                case 675: // Heroic: Shadow Labyrinth
669                                                case 676: // Heroic: Opening of the Dark Portal
670                                                case 677: // Heroic: The Steamvault
671                                                case 678: // Heroic: The Shattered Halls
672                                                case 679: // Heroic: The Mechanar
673                                                case 680: // Heroic: The Botanica
674                                                case 681: // Heroic: The Arcatraz
675                                                case 682: // Heroic: Magister's Terrace
676                                                case 1312: // Utgarde Keep bosses on Heroic Difficulty.
677                                                case 1504: // Ingvar the Plunderer kills (Heroic Utgarde Keep)
678                                                case 1505: // Keristrasza kills (Heroic Nexus)
679                                                case 1506: // Anub'arak kills (Heroic Azjol-Nerub)
680                                                case 1507: // Herald Volazj kills (Heroic Ahn'kahet)
681                                                case 1508: // The Prophet Tharon'ja kills (Heroic Drak'Tharon Keep)
682                                                case 1509: // Cyanigosa kills (Heroic Violet Hold)
683                                                case 1510: // Gal'darah kills (Heroic Gundrak)
684                                                case 1511: // Sjonnir the Ironshaper kills (Heroic Halls of Stone)
685                                                case 1512: // Loken kills (Heroic Halls of Lightning)
686                                                case 1513: // Ley-Guardian Eregos kills (Heroic Oculus)
687                                                case 1514: // King Ymiron kills (Heroic Utgarde Pinnacle)
688                                                case 1515: // Mal'Ganis defeated (Heroic CoT: Stratholme)
689                                                case 1721: // Heroic: Archavon the Stone Watcher
690                                                case 1817: // The Culling of Time
691                                                case 1865: // Lockdown!
692                                                        if( GetPlayer()->iInstanceType >= MODE_HEROIC )
693                                                        {
694                                                                UpdateCriteriaProgress(achievementCriteria, 1);
695                                                        }
696                                                        break;
697// TODO: More complicated achievements: time limits, group size limits, other criteria...
698                                                case 1870: // Heroic: A Poke In The Eye
699                                                        // Defeat Malygos on Heroic Difficulty with fewer than 21.
700                                                case 2056: // Volunteer Work
701                                                        // Defeat Jedoga Shadowseeker in Ahn'kahet on Heroic Difficulty without killing any Twilight Volunteers.
702                                                case 1875: // Heroic: You Don't Have An Eternity
703                                                        // Defeat Malygos in 6 minutes or less on Heroic Difficulty.
704                                                case 2185: // Heroic: Just Can't Get Enough
705                                                        // Defeat Kel'Thuzad on Heroic Difficulty in Naxxramas while killing at least 18 abominations in his chamber.
706                                                case 1862: // Volazj's Quick Demise
707                                                        // Defeat Herald Volazj in Ahn'kahet on Heroic Difficulty in 2 minutes or less.
708                                                case 2186: // The Immortal
709                                                        // Within one raid lockout period, defeat every boss in Naxxramas on Heroic Difficulty without allowing any raid member to die during any of the boss encounters.
710                                                case 2038: // Respect Your Elders
711                                                        // Defeat Elder Nadox in Ahn'kahet on Heroic Difficulty without killing any Ahn'kahar Guardians.
712                                                case 2183: // Heroic: Spore Loser
713                                                        // Defeat Loatheb in Naxxramas on Heroic Difficulty without killing any spores.
714                                                case 1297: // Hadronox Denied
715                                                        // Defeat Hadronox in Azjol-Nerub on Heroic Difficulty before he webs the top doors and prevents more creatures from spawning.
716                                                case 2177: // Heroic: And They Would All Go Down Together
717                                                        // Defeat the 4 Horsemen in Naxxramas on Heroic Difficulty, ensuring that they all die within 15 seconds of each other.
718                                                case 1860: // Gotta Go!
719                                                        // Defeat Anub'arak in Azjol-Nerub on Heroic Difficulty in 2 minutes or less.
720                                                case 2147: // Heroic: The Hundred Club
721                                                        // Defeat Sapphiron on Heroic Difficulty in Naxxramas without any member of the raid having a frost resist value over 100.
722                                                case 1861: // The Party's Over
723                                                        // Defeat Prince Taldaram in Ahn'kahet on Heroic Difficulty with less than 5 people.
724                                                case 2181: // Heroic: Subtraction
725                                                        // Defeat Thaddius in Naxxramas on Heroic Difficulty with less than 21 people.
726                                                case 579: // Heroic: The Dedicated Few
727                                                        // Defeat the bosses of Naxxramas with less than 21 people in the zone on Heroic Difficulty.
728                                                case 1296: // Watch Him Die
729                                                        // Defeat Krik'thir the Gatewatcher in Azjol-Nerub on Heroic Difficulty while Watcher Gashra, Watcher Narjil and Watcher Silthik are still alive.
730                                                case 1589: // Heroic: Arachnophobia
731                                                        // Kill Maexxna in Naxxramas within 20 minutes of Anub'Rekhan's death on Heroic Difficulty.
732                                                case 1857: // Heroic: Make Quick Werk Of Him
733                                                        // Kill Patchwerk in Naxxramas in 3 minutes or less on Heroic Difficulty.
734                                                case 1877: // Heroic: Less Is More
735                                                        // Defeat Sartharion the Onyx Guardian and the Twilight Drakes on Heroic Difficulty with fewer than 21.
736                                                case 1919: // On The Rocks
737                                                        // Defeat Prince Keleseth in Utgarde Keep on Heroic Difficulty without shattering any Frost Tombs.
738                                                case 2036: // Intense Cold
739                                                        // Defeat Keristrasza in The Nexus on Heroic Difficulty without allowing Intense Cold to reach more than two stacks.
740                                                case 2139: // Heroic: The Safety Dance
741                                                        // Defeat Heigan the Unclean in Naxxramas on Heroic Difficulty without anyone in the raid dying.
742                                                case 2140: // Heroic: Momma Said Knock You Out
743                                                        // Defeat Grand Widow Faerlina in Naxxramas on Heroic Difficulty without dispelling frenzy.
744                                                case 2150: // Split Personality
745                                                        // Defeat Grand Magus Telestra in The Nexus on Heroic Difficulty after having killed her images within 5 seconds of each other during both splits.
746                                                case 2151: // Consumption Junction
747                                                        // Defeat Trollgore in Drak'Tharon Keep on Heroic Difficulty before Consume reaches ten stacks.
748                                                case 2179: // Heroic: Shocking!
749                                                        // Defeat Thaddius in Naxxramas on Heroic Difficulty without anyone in the raid crossing the negative and positive charges.
750                                                case 2037: // Chaos Theory
751                                                        // Defeat Anomalus in The Nexus on Heroic Difficulty without destroying any Chaotic Rifts.
752                                                case 2039: // Better Off Dred
753                                                        // Engage King Dred in Drak'Tharon Keep on Heroic Difficulty and slay 6 Drakkari Gutrippers or Drakkari Scytheclaw during his defeat.
754                                                case 2048: // Heroic: Gonna Go When the Volcano Blows
755                                                        // Defeat Sartharion the Onyx Guardian on Heroic Difficulty without getting hit by Lava Strike.
756                                                case 2057: // Oh Novos!
757                                                        // Defeat Novos the Summoner in Drak'Tharon Keep on Heroic Difficulty without allowing any undead minions to reach the floor.
758                                                case 1816: // Defenseless
759                                                        // Defeat Cyanigosa in The Violet Hold without using Defense Control Crystals and with Prison Seal Integrity at 100% while in Heroic Difficulty.
760                                                case 2052: // Heroic: Twilight Assist
761                                                        // With at least one Twilight Drake still alive, engage and defeat Sartharion the Onyx Guardian on Heroic Difficulty.
762                                                case 2053: // Heroic: Twilight Duo
763                                                        // With at least two Twilight Drakes still alive, engage and defeat Sartharion the Onyx Guardian on Heroic Difficulty.
764                                                case 2041: // Dehydration
765                                                        // Defeat Ichoron in the Violet Hold on Heroic Difficulty without allowing any Ichor Globules to merge.
766                                                case 2054: // Heroic: The Twilight Zone
767                                                        // With all three Twilight Drakes still alive, engage and defeat Sartharion the Onyx Guardian on Heroic Difficulty.
768                                                case 1864: // What the Eck?
769                                                        // Defeat Gal'darah in Gundrak on Heroic Difficulty while under the effects of Eck Residue.
770                                                case 2152: // Share The Love
771                                                        // Defeat Gal'darah in Gundrak on Heroic Difficulty and have 5 unique party members get impaled throughout the fight.
772                                                case 2040: // Less-rabi
773                                                        // Defeat Moorabi in Gundrak on Heroic Difficulty while preventing him from transforming into a mammoth at any point during the encounter.
774                                                case 2058: // Snakes. Why'd It Have To Be Snakes?
775                                                        // Defeat Slad'ran in Gundrak on Heroic Difficulty without getting snake wrapped.
776                                                case 1866: // Good Grief
777                                                        // Defeat the Maiden of Grief in the Halls of Stone on Heroic Difficulty in 1 minute or less.
778                                                case 2155: // Abuse the Ooze
779                                                        // Defeat Sjonnir the Ironshaper in the Halls of Stone on Heroic Difficulty and kill 5 Iron Sludges during the encounter.
780                                                case 2154: // Brann Spankin' New
781                                                        // Defeat the Tribunal of Ages encounter in the Halls of Stone on Heroic Difficulty without allowing Brann Bronzebeard to take any damage.
782                                                case 1867: // Timely Death
783                                                        // Defeat Loken in the Halls of Lightning on Heroic Difficulty in 2 minutes or less.
784                                                case 1834: //Lightning Struck
785                                                        // Defeat General Bjarngrim in the Halls of Lightning on Heroic Difficulty while he has a Temporary Electrical Charge.
786                                                case 2042: // Shatter Resistant
787                                                        // Defeat Volkhan in the Halls of Lightning on Heroic Difficulty without allowing him to shatter more than 4 Brittle Golems.
788                                                case 1872: // Zombiefest!
789                                                        // Kill 100 Risen Zombies in 1 minute in The Culling of Stratholme on Heroic Difficulty.
790                                                case 2043: // The Incredible Hulk
791                                                        // Force Svala Sorrowgrave to kill a Scourge Hulk on Heroic Difficulty in Utgarde Pinnacle.
792                                                case 1873: // Lodi Dodi We Loves the Skadi
793                                                        // Defeat Skadi the Ruthless in Utgarde Pinnacle on Heroic Difficulty within 3 minutes of starting the gauntlet event.
794                                                case 2156: // My Girl Loves to Skadi All the Time
795                                                        // Defeat Skadi the Ruthless in Utgarde Pinnacle on Heroic Difficulty after having killed Grauf from 100% to dead in a single pass.
796                                                case 2157: // King's Bane
797                                                        // Defeat King Ymiron in Utgarde Pinnacle on Heroic Difficulty without anyone in the party triggering Bane.
798                                                case 1871: // Experienced Drake Rider
799                                                        // On three different visits to The Oculus, get credit for defeating Ley-Guardian Eregos while riding an Amber, Emerald, and Ruby drake on Heroic Difficulty.
800                                                case 1868: // Make It Count
801                                                        // Defeat Ley-Guardian Eregos in The Oculus on Heroic Difficulty within 20 minutes of Drakos the Interrogator's death.
802                                                case 2044: // Ruby Void
803                                                        // Defeat Ley-Guardian Eregos in The Oculus on Heroic Difficulty without anyone in your party using a Ruby Drake.
804                                                case 2045: // Emerald Void
805                                                        // Defeat Ley-Guardian Eregos in The Oculus on Heroic Difficulty without anyone in your party using an Emerald Drake.
806                                                case 2046: // Amber Void
807                                                        // Defeat Ley-Guardian Eregos in The Oculus on Heroic Difficulty without anyone in your party using an Amber Drake.
808                                                        break;
809                                                default:
810                                                        if( !IS_INSTANCE(GetPlayer()->GetMapId()) || (GetPlayer()->iInstanceType == MODE_NORMAL) )
811                                                        {
812                                                                // already tested heroic achievements above, the rest should be normal or non-dungeon
813                                                                UpdateCriteriaProgress(achievementCriteria, 1);
814                                                        }
815                                                        break;
816                                        }
817                                }
818                                break;
819                        case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
820                                if( achievementCriteria->reach_skill_level.skillID == static_cast<uint32>( miscvalue1 ))
821                                {
822                                        SetCriteriaProgress(achievementCriteria, miscvalue2);
823                                }
824                                break;
825                        case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
826                                if( achievementCriteria->learn_skill_level.skillID == static_cast<uint32>( miscvalue1 ))
827                                {
828                                        SetCriteriaProgress(achievementCriteria, miscvalue2);
829                                }
830                                break;
831                        case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
832                                if( achievementCriteria->equip_item.itemID == static_cast<uint32>( miscvalue1 ))
833                                {
834                                        SetCriteriaProgress(achievementCriteria, 1);
835                                }
836                                break;
837                        case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
838                                // Achievement ID:556 description Equip an epic item in every slot with a minimum item level of 213.
839                                // "213" value not found in achievement or criteria entries (dbc), have to hard-code it here? :(
840                                // Achievement ID:557 description Equip a superior item in every slot with a minimum item level of 187.
841                                // "187" value not found in achievement or criteria entries (dbc), have to hard-code it here? :(
842                                // AchievementType for both Achievement ID:556 (Equip epic items) and ID:557 (Equip superior items)
843                                //    is the same (47) ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM
844                                // Going to send item slot in miscvalue1 and item quality in miscvalue2 when calling UpdateAchievementCriteria.
845                                if( achievementCriteria->equip_epic_item.itemSlot == static_cast<uint32>( miscvalue1 ))
846                                {
847                                        if( (achievementCriteria->referredAchievement == 556) && (miscvalue2 == ITEM_QUALITY_EPIC_PURPLE) )
848                                        {
849                                                SetCriteriaProgress(achievementCriteria, 1);
850                                        }
851                                        else if( (achievementCriteria->referredAchievement == 557) && (miscvalue2 == ITEM_QUALITY_RARE_BLUE) )
852                                        {
853                                                SetCriteriaProgress(achievementCriteria, 1);
854                                        }
855                                }
856                                break;
857                        case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
858                                if( achievementCriteria->do_emote.emoteID == static_cast<uint32>( miscvalue1 ))
859                                {
860                                        // emote matches, check the achievement target ... (if required)
861                                        Unit* pUnit = GetPlayer()->GetMapMgr()->GetUnit(selectedGUID);
862                                        switch(achievement->ID)
863                                        {
864                                                case 1206: // To All The Squirrels I've Loved Before
865                                                        // requires a target
866                                                        if( pUnit )
867                                                        {
868                                                                uint32 ent = pUnit->GetEntry();
869                                                                if(   (ent== 1412 && achievementCriteria->index== 1)   // Squirrel
870                                                                        || (ent==25679 && achievementCriteria->index== 2)   // Steam Frog
871                                                                        || (ent==25677 && achievementCriteria->index== 3)   // Borean Frog
872                                                                        || (ent== 6368 && achievementCriteria->index== 4)   // Cat
873                                                                        || (ent==  620 && achievementCriteria->index== 5)   // Chicken
874                                                                        || (ent== 2442 && achievementCriteria->index== 6)   // Cow
875                                                                        || (ent== 6827 && achievementCriteria->index== 7)   // Crab
876                                                                        || (ent==  883 && achievementCriteria->index== 8)   // Deer
877                                                                        || (ent==19665 && achievementCriteria->index== 9)   // Ewe
878                                                                        || (ent==  890 && achievementCriteria->index==10)   // Fawn
879                                                                        || (ent==13321 && achievementCriteria->index==11)   // Frog
880                                                                        || (ent== 4166 && achievementCriteria->index==12)   // Gazelle
881                                                                        || (ent== 5951 && achievementCriteria->index==13)   // Hare
882                                                                        || (ent== 9600 && achievementCriteria->index==14)   // Parrot
883                                                                        || (ent==  721 && achievementCriteria->index==15)   // Rabbit
884                                                                        || (ent== 2098 && achievementCriteria->index==16)   // Ram
885                                                                        || (ent== 1933 && achievementCriteria->index==17)   // Sheep
886                                                                        || (ent==17467 && achievementCriteria->index==18)   // Skunk
887                                                                        || (ent==10685 && achievementCriteria->index==19)   // Swine
888                                                                        || (ent== 1420 && achievementCriteria->index==20)   // Toad
889                                                                        || (ent== 2620 && achievementCriteria->index==21) ) // Prairie Dog
890                                                                {
891                                                                        SetCriteriaProgress(achievementCriteria, 1);
892                                                                }
893                                                        }
894                                                        break;
895                                                case 2557: // To All The Squirrels Who Shared My Life
896                                                        // requires a target
897                                                        if( pUnit )
898                                                        {
899                                                                uint32 ent = pUnit->GetEntry();
900                                                                if(   (ent==29328 && achievementCriteria->index== 1)   // Arctic Hare
901                                                                        || (ent==31685 && achievementCriteria->index== 2)   // Borean Marmot
902                                                                        || (ent==28407 && achievementCriteria->index== 3)   // Fjord Penguin
903                                                                        || (ent==24746 && achievementCriteria->index== 4)   // Fjord Turkey
904                                                                        || (ent==32498 && achievementCriteria->index== 5)   // Glacier Penguin (not in db?)
905                                                                        || (ent==31889 && achievementCriteria->index== 6)   // Grizzly Squirrel
906                                                                        || (ent== 6653 && achievementCriteria->index== 7)   // Huge Toad
907                                                                        || (ent== 9700 && achievementCriteria->index== 8)   // Lava Crab
908                                                                        || (ent==31890 && achievementCriteria->index== 9)   // Mountain Skunk
909                                                                        || (ent==26503 && achievementCriteria->index==10)   // Scalawag Frog
910                                                                        || (ent==28093 && achievementCriteria->index==11)   // Sholazar Tickbird
911                                                                        || (ent==28440 && achievementCriteria->index==12) ) // Tundra Penguin
912                                                                {
913                                                                        SetCriteriaProgress(achievementCriteria, 1);
914                                                                }
915                                                        }
916                                                        break;
917                                                case 247: // Make Love, Not Warcraft
918                                                        {
919                                                                Player* pTarget = objmgr.GetPlayer((uint32)selectedGUID);
920                                                                if( pTarget && pTarget->IsPlayer() && pTarget->IsDead() && isHostile(pTarget, GetPlayer()) )
921                                                                {
922                                                                        UpdateCriteriaProgress(achievementCriteria, 1);
923                                                                }
924                                                        }
925                                                        break;
926                                                case 293: // TODO:  Disturbing the Peace
927                                                        // While wearing 3 pieces of Brewfest clothing, get completely smashed and dance in Dalaran.
928                                                        break;
929                                                case 1280: // TODO: Flirt With Disaster
930                                                        // Get completely smashed, put on your best perfume, throw a handful of rose petals on Jeremiah Payson and then kiss him. You'll regret it in the morning.
931                                                        break;
932                                                case 1279: // TODO: Flirt With Disaster
933                                                        // Get completely smashed, put on your best perfume, throw a handful of rose petals on Sraaz and then kiss him. You'll regret it in the morning.
934                                                        break;
935                                                case 1690: // TODO: A Frosty Shake
936                                                        // During the Feast of Winter Veil, use your Winter Veil Disguise kit to become a snowman and then dance with another snowman in Dalaran.
937                                                        break;
938                                                case 1704: // TODO: I Pitied The Fool
939                                                        // Pity the Love Fool in the locations specified below.
940                                                        // Wintergrasp (achievementCriteria->index==1)
941                                                        // Battle Ring of Gurubashi Arena (achievementCriteria->index==2)
942                                                        // Arathi Basin Blacksmith (achievementCriteria->index==3)
943                                                        // The Culling of Stratholme (achievementCriteria->index==4)
944                                                        // Naxxramas (achievementCriteria->index==5)
945                                                        break;
946
947                                                // Statistics for emotes
948                                                case 1042: // Number of Hugs
949                                                case 1045: // Total cheers
950                                                case 1047: // Total facepalms
951                                                case 1065: // Total waves
952                                                case 1066: // Total times LOL'd (laugh, guffaw, rofl, giggle, chuckle)
953                                                case 1067: // Total times playing world's smallest violin
954                                                        UpdateCriteriaProgress(achievementCriteria, 1);
955                                                        break;
956                                                default:
957                                                        break;
958                                        }
959                                }
960                                break;
961                        case ACHIEVEMENT_CRITERIA_TYPE_KILLING_BLOW:
962                                // miscvalue1 contain Map ID
963                                switch(achievementCriteria->referredAchievement)
964                                {
965                                        case 231:
966                                                if(   ( (miscvalue1 ==  30) && (achievementCriteria->index==1) )   // Alterac Valley
967                                                        || ( (miscvalue1 == 529) && (achievementCriteria->index==2) )   // Arathi Basin
968                                                        || ( (miscvalue1 == 566) && (achievementCriteria->index==3) )   // Eye of the Storm
969                                                        || ( (miscvalue1 == 489) && (achievementCriteria->index==4) )   // Warsong Gulch
970                                                        || ( (miscvalue1 == 607) && (achievementCriteria->index==5) ) ) // Strand of the Ancients
971                                                {
972                                                        UpdateCriteriaProgress(achievementCriteria, 1);
973                                                }
974                                                break;
975                                        case 233: // TODO: Berserking killing blow
976                                                break;
977                                        case 1487: // Total Killing Blows
978                                                UpdateCriteriaProgress(achievementCriteria, 1);
979                                                break;
980                                        case 1488:
981                                                if(   ( (miscvalue1 ==   0) && (achievementCriteria->index==1) )   // Eastern Kingdoms
982                                                        || ( (miscvalue1 ==   1) && (achievementCriteria->index==2) )   // Kalimdor
983                                                        || ( (miscvalue1 == 530) && (achievementCriteria->index==3) )   // Burning Crusade Areas
984                                                        || ( (miscvalue1 == 571) && (achievementCriteria->index==4) ) ) // Northrend
985                                                {
986                                                        UpdateCriteriaProgress(achievementCriteria, 1);
987                                                }
988                                                break;
989                                        case 1490:
990                                                if(   ( (miscvalue1 == 559) && (achievementCriteria->index==1) )   // Nagrand Arena
991                                                        || ( (miscvalue1 == 562) && (achievementCriteria->index==2) )   // Blade's Edge Arena
992                                                        || ( (miscvalue1 == 572) && (achievementCriteria->index==3) )   // Ruins of Lordaeron
993                                                        || ( (miscvalue1 == 617) && (achievementCriteria->index==4) )   // Dalaran Sewers
994                                                        || ( (miscvalue1 == 618) && (achievementCriteria->index==5) ) ) // Ring of Valor
995                                                {
996                                                        UpdateCriteriaProgress(achievementCriteria, 1);
997                                                }
998                                                break;
999                                        case 1491:
1000                                                if(   ( (miscvalue1 ==  30) && (achievementCriteria->index==1) )   // Alterac Valley
1001                                                        || ( (miscvalue1 == 529) && (achievementCriteria->index==2) )   // Arathi Basin
1002                                                        || ( (miscvalue1 == 489) && (achievementCriteria->index==3) )   // Warsong Gulch
1003                                                        || ( (miscvalue1 == 566) && (achievementCriteria->index==4) )   // Eye of the Storm
1004                                                        || ( (miscvalue1 == 607) && (achievementCriteria->index==5) ) ) // Strand of the Ancients
1005                                                {
1006                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1007                                                }
1008                                                break;
1009                                        case 1492: // TODO: 2v2 Arena Killing Blows
1010                                                break;
1011                                        case 1493: // TODO: 3v3 Arena Killing Blows
1012                                                break;
1013                                        case 1494: // TODO: 5v5 Arena Killing Blows
1014                                                break;
1015                                        case 1495: // Alterac Valley Killing Blows
1016                                                if( miscvalue1 == 30 )
1017                                                {
1018                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1019                                                }
1020                                                break;
1021                                        case 1496: // Arathi Basin Killing Blows
1022                                                if( miscvalue1 == 529 )
1023                                                {
1024                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1025                                                }
1026                                                break;
1027                                        case 1497: // Warsong Gulch Killing Blows
1028                                                if( miscvalue1 == 489 )
1029                                                {
1030                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1031                                                }
1032                                                break;
1033                                        case 1498: // Eye of the Storm Killing Blows
1034                                                if( miscvalue1 == 566 )
1035                                                {
1036                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1037                                                }
1038                                                break;
1039                                        case 1499: // Strand of the Ancients Killing Blows
1040                                                if( miscvalue1 == 607 )
1041                                                {
1042                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1043                                                }
1044                                                break;
1045                                        case 2148: // TODO: Deliver a killing blow to a Scion of Eternity while riding on a hover disk
1046                                                break;
1047                                        case 2149: // TODO: Deliver a killing blow to a Scion of Eternity while riding on a hover disk
1048                                                break;
1049                                        default:
1050                                                break;
1051                                }
1052                                break;
1053                        case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM: // itemID in miscvalue1
1054                                if( achievementCriteria->use_item.itemID == static_cast<uint32>( miscvalue1 ))
1055                                {
1056                                        switch(achievementCriteria->referredAchievement)
1057                                        {
1058                                                case 1281: // Shoot off 10 Red Rocket Clusters in 25 seconds or less
1059                                                case 1552: // Shoot off 10 Festival Firecrackers in 30 seconds or less
1060                                                case 1696: // Shoot off 10 Love Rockets in 20 seconds or less
1061                                                case 1781: // Get 10 critters in 3 minutes
1062                                                case 1791: // Hearthstone with kid out
1063                                                        break;
1064                                                default:
1065                                                        UpdateCriteriaProgress(achievementCriteria, 1);
1066                                                        break;
1067                                        }
1068                                }
1069                                break;
1070                        case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE:
1071                                // Total NPC kills, Kill an NPC that yields XP, Beasts, Critters killed, Demons, Dragonkin ...
1072                                // miscvalue1 = killed creature high GUID
1073                                // miscvalue2 = killed creature low GUID
1074                                {
1075                                        uint64 crGUID = miscvalue1;
1076                                        crGUID <<= 32; // shift to high 32-bits
1077                                        crGUID += miscvalue2;
1078                                        Unit* pUnit = GetPlayer()->GetMapMgr()->GetUnit(crGUID);
1079                                        if( pUnit )
1080                                        {
1081                                                uint8 crTypeId = pUnit->GetTypeId();
1082                                                uint32 crType = UNIT_TYPE_NONE;
1083                                                bool crTotem = false;
1084                                                bool yieldXP = CalculateXpToGive( pUnit, GetPlayer() )  > 0;
1085                                                if( crTypeId == TYPEID_UNIT )
1086                                                {
1087                                                        crTotem = ((Creature*)pUnit)->IsTotem();
1088                                                        if( ((Creature*)pUnit)->GetCreatureInfo() )
1089                                                        {
1090                                                                crType = ((Creature*)pUnit)->GetCreatureInfo()->Type;
1091                                                        }
1092                                                        if(     (achievementCriteria->ID == 4944)                             // Total NPC kills              refAch==1197
1093                                                                || ( (achievementCriteria->ID == 4946) && (yieldXP)            )   // Kill an NPC that yields XP   refAch==1198
1094                                                                || ( (achievementCriteria->ID == 4948) && (crType==UNIT_TYPE_BEAST)      )   // Beasts                       refAch== 107
1095                                                                || ( (achievementCriteria->ID == 4958) && (crType==UNIT_TYPE_CRITTER)    )   // Critters killed              refAch== 107
1096                                                                || ( (achievementCriteria->ID == 4949) && (crType==UNIT_TYPE_DEMON)      )   // Demons                       refAch== 107
1097                                                                || ( (achievementCriteria->ID == 4950) && (crType==UNIT_TYPE_DRAGONKIN) )   // Dragonkin                    refAch== 107
1098                                                                || ( (achievementCriteria->ID == 4951) && (crType==UNIT_TYPE_ELEMENTAL)  )   // Elemental                    refAch== 107
1099                                                                || ( (achievementCriteria->ID == 4952) && (crType==UNIT_TYPE_GIANT)      )   // Giant                        refAch== 107
1100                                                                || ( (achievementCriteria->ID == 4953) && (crType==UNIT_TYPE_HUMANOID)   )   // Humanoid                     refAch== 107
1101                                                                || ( (achievementCriteria->ID == 4954) && (crType==UNIT_TYPE_MECHANICAL) )   // Mechanical                   refAch== 107
1102                                                                || ( (achievementCriteria->ID == 4955) && (crType==UNIT_TYPE_UNDEAD)     )   // Undead                       refAch== 107
1103                                                                || ( (achievementCriteria->ID == 4956) && (crType==UNIT_TYPE_NONE)               )   // Unspecified                  refAch== 107
1104                                                                || ( (achievementCriteria->ID == 4957) && (crTotem)            ) ) // Totems                       refAch== 107
1105                                                        {
1106                                                                UpdateCriteriaProgress(achievementCriteria, 1);
1107                                                        }
1108                                                }
1109                                        }
1110                                }
1111                                break;
1112                        case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
1113                                if( achievementCriteria->use_gameobject.goEntry == static_cast<uint32>( miscvalue1 ))
1114                                {
1115                                        UpdateCriteriaProgress(achievementCriteria, 1);
1116                                }
1117                                break;
1118                        case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
1119                                // fall distance (>=65) has been checked before UpdateAchievementCriteria() call, but it is sent in miscvalue1 just in case "they" add more...
1120                                if( achievement->ID == 1260 )
1121                                {
1122                                        // Fall 65 yards without dying while completely smashed during the Brewfest Holiday.
1123                                        if( miscvalue2 == DRUNKEN_SMASHED )
1124                                        {
1125                                                // drunken state, "completely smashed"
1126                                                // TODO: Check if it is during the Brewfest Holiday ...
1127                                                UpdateCriteriaProgress(achievementCriteria, 1);
1128                                        }
1129                                }
1130                                else
1131                                {
1132                                        // achievement->ID==964 // Fall 65 yards without dying.
1133                                        UpdateCriteriaProgress(achievementCriteria, 1);
1134                                }
1135                                break;
1136                        case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
1137                                if( achievementCriteria->honorable_kill_at_area.areaID == static_cast<uint32>( miscvalue1 ))
1138                                {
1139                                        UpdateCriteriaProgress(achievementCriteria, 1);
1140                                }
1141                                break;
1142                        case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
1143                                if( achievementCriteria->hk_class.classID == static_cast<uint32>( miscvalue1 ))
1144                                {
1145                                        UpdateCriteriaProgress(achievementCriteria, 1);
1146                                }
1147                                break;
1148                        case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
1149                                if( achievementCriteria->hk_race.raceID == static_cast<uint32>( miscvalue1 ))
1150                                {
1151                                        UpdateCriteriaProgress(achievementCriteria, 1);
1152                                }
1153                                break;
1154                        case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP:
1155                                if( achievementCriteria->death_at_map.mapID == static_cast<uint32>( miscvalue1 ))
1156                                {
1157                                        UpdateCriteriaProgress(achievementCriteria, 1);
1158                                }
1159                                break;
1160
1161                        // these achievement criteria types simply update the progress by the value passed in miscvalue1
1162                        case ACHIEVEMENT_CRITERIA_TYPE_QUEST_REWARD_GOLD:
1163                        case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
1164                        case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
1165                        case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
1166                        case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
1167                        case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
1168                        case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER:
1169                        case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
1170                        case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER:
1171                        case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE:
1172                        case ACHIEVEMENT_CRITERIA_TYPE_DEATH:
1173                                UpdateCriteriaProgress(achievementCriteria, miscvalue1);
1174                                break;
1175                        //End of Achievement List
1176                        default:
1177                                return;
1178                }
1179                CompletedCriteria(achievementCriteria);
1180        }
1181}
1182
1183/**
1184        Updates all achievement criteria of the specified type.
1185        This is only called from CheckAllAchievementCriteria(), during player login
1186*/
1187void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type)
1188{
1189        AchievementCriteriaEntryList const& achievementCriteriaList = objmgr.GetAchievementCriteriaByType(type);
1190        for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
1191        {
1192                AchievementCriteriaEntry const *achievementCriteria = (*i);
1193
1194                AchievementEntry const *achievement = dbcAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
1195                if( !achievement //|| IsCompletedCriteria(achievementCriteria)
1196                        || (achievement->flags & ACHIEVEMENT_FLAG_COUNTER)
1197                        || (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && m_player->GetTeam() != HORDE)
1198                        || (achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && m_player->GetTeam() != ALLIANCE) )
1199                {
1200                        continue;
1201                }
1202
1203                switch(type)
1204                {
1205                //Start of Achievement List
1206                case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
1207                        SetCriteriaProgress(achievementCriteria, GetPlayer()->getLevel());
1208                        break;
1209                case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
1210                        if( GetPlayer()->HasOverlayUncovered(achievementCriteria->explore_area.areaReference) )
1211                        {
1212                                SetCriteriaProgress(achievementCriteria, 1);
1213                        }
1214                        break;
1215                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
1216                        if( m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end() )
1217                        {
1218                                SetCriteriaProgress(achievementCriteria, 1, true);
1219                        }
1220                        break;
1221                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
1222                        SetCriteriaProgress(achievementCriteria, (int32)GetPlayer()->m_finishedQuests.size());
1223                        break;
1224                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
1225                        {
1226                                uint32 qcinzone = 0;
1227                                set<uint32>::iterator qc = GetPlayer()->m_finishedQuests.begin();
1228                                for(; qc!=GetPlayer()->m_finishedQuests.end(); ++qc)
1229                                {
1230                                        Quest* qst = QuestStorage.LookupEntry(*qc);
1231                                        if( qst && qst->zone_id == achievementCriteria->complete_quests_in_zone.zoneID )
1232                                        {
1233                                                ++qcinzone;
1234                                        }
1235                                }
1236                                SetCriteriaProgress(achievementCriteria, qcinzone);
1237                        }
1238                        break;
1239                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
1240                        {
1241                                uint32 completed = 0;
1242                                set<uint32>::iterator it = GetPlayer()->m_finishedQuests.find(achievementCriteria->complete_quest.questID);
1243                                if( it!=GetPlayer()->m_finishedQuests.end() )
1244                                {
1245                                        ++completed;
1246                                }
1247                                SetCriteriaProgress(achievementCriteria, completed);
1248                        }
1249                        break;
1250                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
1251                        {
1252                                int32 rep = GetPlayer()->GetStanding(achievementCriteria->gain_reputation.factionID);
1253                                SetCriteriaProgress(achievementCriteria, rep);
1254                        }
1255                        break;
1256                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
1257                        SetCriteriaProgress(achievementCriteria,GetPlayer()->GetExaltedCount());
1258                        break;
1259                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
1260                        if( GetPlayer()->HasSpell(achievementCriteria->learn_spell.spellID) )
1261                        {
1262                                SetCriteriaProgress(achievementCriteria, 1);
1263                        }
1264                        break;
1265                case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS:
1266                        {
1267                                // achievementCriteria field4 = 777 for mounts, 778 for companion pets
1268                                SpellSet::iterator sl = GetPlayer()->mSpells.begin();
1269                                uint32 nm = 0;
1270                                while(sl != GetPlayer()->mSpells.end())
1271                                {
1272                                        SpellEntry* sp = dbcSpell.LookupEntry(*sl);
1273                                        if( achievementCriteria->number_of_mounts.unknown == 777 && sp && sp->MechanicsType == MECHANIC_MOUNTED )
1274                                        {
1275                                                // mount spell
1276                                                ++nm;
1277                                        }
1278                                        else if( achievementCriteria->number_of_mounts.unknown == 778 && sp && (sp->Effect[0]==SPELL_EFFECT_SUMMON) )
1279                                        {
1280                                                // Companion pet?
1281                                                // make sure it's a companion pet, not some other summon-type spell
1282                                                if( strncmp(sp->Description,"Right Cl", 8) == 0 )
1283                                                {
1284                                                        // "Right Click to summon and dismiss " ...
1285                                                        ++nm;
1286                                                }
1287                                        }
1288                                        ++sl;
1289                                }
1290                                SetCriteriaProgress(achievementCriteria, nm);
1291                        }
1292                        break;
1293                case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
1294                        SetCriteriaProgress(achievementCriteria, GetPlayer()->_GetSkillLineCurrent(achievementCriteria->reach_skill_level.skillID, true));
1295                        break;
1296                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
1297                        SetCriteriaProgress(achievementCriteria, GetPlayer()->_GetSkillLineMax(achievementCriteria->learn_skill_level.skillID)/75);
1298                        break;
1299                case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
1300                        SetCriteriaProgress(achievementCriteria, (uint8)(GetPlayer()->GetUInt32Value(PLAYER_BYTES_2) >> 16));
1301                        break;
1302                //End of Achievement List
1303                default:
1304                        break;
1305                }
1306                CompletedCriteria(achievementCriteria);
1307        }
1308}
1309
1310/**
1311        True if the criteria has been completed; false if error; false if criteria has not been completed.
1312*/
1313bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria)
1314{
1315        if( !achievementCriteria )
1316        {
1317                return false;
1318        }
1319        AchievementEntry const* achievement = dbcAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
1320        if( achievement == NULL )
1321        {
1322                return false;
1323        }
1324
1325
1326        if( achievement->flags & ACHIEVEMENT_FLAG_COUNTER )
1327        {
1328                return false;
1329        }
1330
1331        if( achievement->flags & (ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL) )
1332        {
1333                if( objmgr.allCompletedAchievements.find(achievement->ID)!=objmgr.allCompletedAchievements.end() )
1334                {
1335                        return false;
1336                }
1337        }
1338
1339        CriteriaProgressMap::iterator itr = m_criteriaProgress.find(achievementCriteria->ID);
1340        if( itr == m_criteriaProgress.end() )
1341        {
1342                return false;
1343        }
1344
1345        CriteriaProgress *progress = itr->second;
1346
1347        // 0 or negative, not completed.
1348        if( progress->counter < 1 )
1349        {
1350                return false;
1351        }
1352
1353        uint32 progresscounter = (uint32)progress->counter;
1354        switch(achievementCriteria->requiredType)
1355        {
1356                case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL:
1357                        if( achievement->ID == 467 && GetPlayer()->getClass() != SHAMAN ||
1358                                achievement->ID == 466 && GetPlayer()->getClass() != DRUID ||
1359                                achievement->ID == 465 && GetPlayer()->getClass() != PALADIN ||
1360                                achievement->ID == 464 && GetPlayer()->getClass() != PRIEST ||
1361                                achievement->ID == 463 && GetPlayer()->getClass() != WARLOCK ||
1362                                achievement->ID == 462 && GetPlayer()->getClass() != HUNTER ||
1363                                achievement->ID == 461 && GetPlayer()->getClass() != DEATHKNIGHT ||
1364                                achievement->ID == 460 && GetPlayer()->getClass() != MAGE ||
1365                                achievement->ID == 459 && GetPlayer()->getClass() != WARRIOR ||
1366                                achievement->ID == 458 && GetPlayer()->getClass() != ROGUE ||
1367                                achievement->ID == 1404 && GetPlayer()->getRace() != RACE_GNOME ||
1368                                achievement->ID == 1405 && GetPlayer()->getRace() != RACE_BLOODELF ||
1369                                achievement->ID == 1406 && GetPlayer()->getRace() != RACE_DRAENEI ||
1370                                achievement->ID == 1407 && GetPlayer()->getRace() != RACE_DWARF ||
1371                                achievement->ID == 1408 && GetPlayer()->getRace() != RACE_HUMAN ||
1372                                achievement->ID == 1409 && GetPlayer()->getRace() != RACE_NIGHTELF ||
1373                                achievement->ID == 1410 && GetPlayer()->getRace() != RACE_ORC ||
1374                                achievement->ID == 1411 && GetPlayer()->getRace() != RACE_TAUREN ||
1375                                achievement->ID == 1412 && GetPlayer()->getRace() != RACE_TROLL ||
1376                                achievement->ID == 1413 && GetPlayer()->getRace() != RACE_UNDEAD )
1377                        {
1378                                return false;
1379                        }
1380                        return progresscounter >= (int32)achievementCriteria->reach_level.level;
1381                        break;
1382                case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM:
1383                case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM:
1384                        return progresscounter >= achievementCriteria->loot_item.itemCount;
1385                case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY:
1386                        return progresscounter >= achievementCriteria->loot_money.goldInCopper;
1387                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT:
1388                        return progresscounter >= achievementCriteria->complete_quest_count.totalQuestCount;
1389                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE:
1390                        return progresscounter >= achievementCriteria->complete_quests_in_zone.questCount;
1391                case ACHIEVEMENT_CRITERIA_TYPE_QUEST_REWARD_GOLD:
1392                        return progresscounter >= achievementCriteria->quest_reward_money.goldInCopper;
1393                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION:
1394                        return progresscounter >= achievementCriteria->gain_reputation.reputationAmount;
1395                case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION:
1396                        return progresscounter >= achievementCriteria->gain_exalted_reputation.numberOfExaltedFactions;
1397                case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_MOUNTS:
1398                        return progresscounter >= achievementCriteria->number_of_mounts.mountCount;
1399                case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE:
1400                        return progresscounter >= achievementCriteria->kill_creature.creatureCount;
1401                case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL:
1402                        return progresscounter >= achievementCriteria->reach_skill_level.skillLevel;
1403                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL:
1404                        return progresscounter >= achievementCriteria->learn_skill_level.skillLevel;
1405                case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM:
1406                        return progresscounter >= achievementCriteria->use_item.itemCount;
1407                case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT:
1408                        return progresscounter >= achievementCriteria->use_gameobject.useCount;
1409                case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT:
1410                        return progresscounter >= achievementCriteria->buy_bank_slot.numberOfSlots;
1411                case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL:
1412                        return progresscounter >= achievementCriteria->honorable_kill.killCount;
1413                case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA:
1414                        return progresscounter >= achievementCriteria->honorable_kill_at_area.killCount;
1415                case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS:
1416                        return progresscounter >= achievementCriteria->hk_class.count;
1417                case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE:
1418                        return progresscounter >= achievementCriteria->hk_race.count;
1419                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT:
1420                        return m_completedAchievements.find(achievementCriteria->complete_achievement.linkedAchievement) != m_completedAchievements.end();
1421
1422                // These achievements only require counter to be 1 (or higher)
1423                case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA:
1424                case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST:
1425                case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL:
1426                case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM:
1427                case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM:
1428                case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
1429                case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP:
1430                case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING:
1431                        return progresscounter >= 1;
1432
1433                // unknown or need to be finished:
1434                default:
1435                        if( achievementCriteria->raw.field4 > 0 )
1436                        {
1437                                return progresscounter >= achievementCriteria->raw.field4;
1438                        }
1439                        break;
1440        }
1441        return false;
1442}
1443
1444/**
1445        If achievement criteria has been completed, checks whether to complete the achievement too.
1446*/
1447void AchievementMgr::CompletedCriteria(AchievementCriteriaEntry const* criteria)
1448{
1449        if( !IsCompletedCriteria( criteria ) )
1450        {
1451                return;
1452        }
1453        AchievementEntry const* achievement = dbcAchievementStore.LookupEntry(criteria->referredAchievement);
1454
1455        if( criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL || GetAchievementCompletionState(achievement) == ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED )
1456        {
1457                CompletedAchievement(achievement);
1458        }
1459}
1460
1461/**
1462        Returns the completion state of the achievement.
1463        ACHIEVEMENT_COMPLETED_COMPLETED_STORED: Achievement has been completed and stored already.
1464        ACHIVEMENT_COMPLETED_COMPLETED_NOT_STORED: Achievement has been completed but not stored yet.
1465        ACHIEVEMENT_COMPLETED_NONE: Achievement has not been completed yet.
1466*/
1467AchievementCompletionState AchievementMgr::GetAchievementCompletionState(AchievementEntry const* entry)
1468{
1469        if( m_completedAchievements.find(entry->ID)!=m_completedAchievements.end() )
1470        {
1471                return ACHIEVEMENT_COMPLETED_COMPLETED_STORED;
1472        }
1473
1474        uint32 completedCount = 0;
1475        bool foundOutstanding = false;
1476        for ( uint32 rowId = 0; rowId<dbcAchievementCriteriaStore.GetNumRows(); ++rowId )
1477        {
1478                AchievementCriteriaEntry const* criteria = dbcAchievementCriteriaStore.LookupRow(rowId);
1479                if( criteria == NULL || criteria->referredAchievement!= entry->ID )
1480                {
1481                        continue;
1482                }
1483
1484                if( IsCompletedCriteria(criteria) && criteria->completionFlag & ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL )
1485                {
1486                        return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED;
1487                }
1488
1489                if( !IsCompletedCriteria(criteria) )
1490                {
1491                        foundOutstanding = true;
1492                }
1493                else
1494                {
1495                        ++completedCount;
1496                }
1497        }
1498        if( !foundOutstanding )
1499        {
1500                return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED;
1501        }
1502
1503        if( (entry->count > 1) && (completedCount >= entry->count) )
1504        {
1505                return ACHIEVEMENT_COMPLETED_COMPLETED_NOT_STORED;
1506        }
1507        return ACHIEVEMENT_COMPLETED_NONE;
1508}
1509
1510/**
1511        Sets progress of the achievement criteria.
1512        If relative argument is true, this behaves the same as UpdateCriteriaProgress.
1513*/
1514void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* entry, int32 newValue, bool relative)
1515{
1516        CriteriaProgress *progress = NULL;
1517
1518        if( m_criteriaProgress.find(entry->ID) == m_criteriaProgress.end() )
1519        {
1520                if( newValue < 1 )
1521                {
1522                        return;
1523                }
1524                progress = new CriteriaProgress(entry->ID, newValue);
1525                m_criteriaProgress[entry->ID]=progress;
1526        }
1527        else
1528        {
1529                progress = m_criteriaProgress[entry->ID];
1530                if( progress->counter == newValue )
1531                {
1532                        return;
1533                }
1534                progress->counter = newValue;
1535        }
1536        if( progress->counter > 0 )
1537        {
1538                // Send update only if criteria is started (counter > 0)
1539                SendCriteriaUpdate( progress );
1540        }
1541}
1542
1543/**
1544        Updates progress of the achievement criteria.
1545        updateByValue is added to the current progress counter.
1546*/
1547void AchievementMgr::UpdateCriteriaProgress(AchievementCriteriaEntry const* entry, int32 updateByValue)
1548{
1549        CriteriaProgress *progress = NULL;
1550
1551        if( m_criteriaProgress.find(entry->ID) == m_criteriaProgress.end() )
1552        {
1553                if( updateByValue < 1 )
1554                {
1555                        return;
1556                }
1557                progress = new CriteriaProgress(entry->ID, updateByValue);
1558                m_criteriaProgress[entry->ID]=progress;
1559        }
1560        else
1561        {
1562                progress = m_criteriaProgress[entry->ID];
1563                progress->counter += updateByValue;
1564        }
1565        if(progress->counter > 0)
1566        {
1567                SendCriteriaUpdate( progress );
1568        }
1569}
1570
1571/**
1572        Completes the achievement for the player.
1573*/
1574void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement)
1575{
1576        if( achievement->flags & ACHIEVEMENT_FLAG_COUNTER || m_completedAchievements.find(achievement->ID)!=m_completedAchievements.end() )
1577        {
1578                return;
1579        }
1580
1581        if( ShowCompletedAchievement(achievement->ID, GetPlayer()) )
1582        {
1583                SendAchievementEarned( achievement );
1584        }
1585        m_completedAchievements[achievement->ID] = time(NULL);
1586
1587        objmgr.allCompletedAchievements.insert( achievement->ID );
1588        UpdateAchievementCriteria( ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT );
1589
1590        // check for reward
1591        GiveAchievementReward(achievement);
1592}
1593
1594/**
1595        Sends all achievement data to the player. Also used for achievement inspection.
1596*/
1597void AchievementMgr::SendAllAchievementData(Player* player)
1598{
1599        // maximum size for the SMSG_ALL_ACHIEVEMENT_DATA packet without causing client problems seems to be 0x7fff
1600        uint32 packetSize = 18 + ((uint32)m_completedAchievements.size() * 8) + (GetCriteriaProgressCount() * 36);
1601        bool doneCompleted = false;
1602        bool doneProgress = false;
1603        AchievementCriteriaEntry const* acEntry;
1604        AchievementEntry const* achievement;
1605
1606        WorldPacket data;
1607        if( packetSize < 0x8000 )
1608        {
1609                data.resize( packetSize );
1610        }
1611        else
1612        {
1613                data.resize( 0x7fff );
1614        }
1615
1616        CompletedAchievementMap::iterator completeIter = m_completedAchievements.begin();
1617        CriteriaProgressMap::iterator progressIter = m_criteriaProgress.begin();
1618        bool packetFull;
1619
1620        while( !doneCompleted || !doneProgress )
1621        {
1622                data.clear();
1623                if( player == m_player )
1624                {
1625                        data.SetOpcode ( SMSG_ALL_ACHIEVEMENT_DATA );
1626                }
1627                else
1628                {
1629                        data.SetOpcode( SMSG_RESPOND_INSPECT_ACHIEVEMENTS );
1630                        FastGUIDPack(data, m_player->GetGUID());
1631                }
1632                packetFull = false;
1633
1634                // add the completed achievements
1635                if( !doneCompleted )
1636                {
1637                        for( ; completeIter != m_completedAchievements.end() && !packetFull; ++completeIter )
1638                        {
1639                                if( ShowCompletedAchievement(completeIter->first, m_player) )
1640                                {
1641                                        data << uint32(completeIter->first);
1642                                        data << uint32(secsToTimeBitFields(completeIter->second));
1643                                }
1644                                packetFull = data.size() > 0x7f00;
1645                        }
1646                        if( completeIter == m_completedAchievements.end() )
1647                        {
1648                                doneCompleted = true;
1649                        }
1650                }
1651               
1652                // 0xffffffff separates between completed achievements and ones in progress
1653                data << int32(-1);
1654                for(; progressIter != m_criteriaProgress.end() && !packetFull; ++progressIter)
1655                {
1656                        acEntry = dbcAchievementCriteriaStore.LookupEntry(progressIter->first);
1657                        if( !acEntry )
1658                        {
1659                                continue;
1660                        }
1661                        achievement = dbcAchievementStore.LookupEntry(acEntry->referredAchievement);
1662                        if( !achievement )
1663                        {
1664                                continue;
1665                        }
1666                        // achievement progress to send to self
1667                        if( player == m_player )
1668                        {
1669                                if( SendAchievementProgress(progressIter->second) )
1670                                {
1671                                        data << uint32(progressIter->first);
1672                                        data.appendPackGUID(progressIter->second->counter);
1673                                        data << GetPlayer()->GetNewGUID();
1674                                        data << uint32(0);
1675                                        data << uint32(secsToTimeBitFields(progressIter->second->date));
1676                                        data << uint32(0);
1677                                        data << uint32(0);
1678                                }
1679                        }
1680                        // achievement progress to send to other players (inspect)
1681                        else
1682                        {
1683                                // only send statistics, no other unfinished achievement progress, since client only displays them as completed or not completed
1684                                if( (progressIter->second->counter > 0) && (achievement->flags & ACHIEVEMENT_FLAG_COUNTER) )
1685                                {
1686                                        data << uint32(progressIter->first);
1687                                        data.appendPackGUID(progressIter->second->counter);
1688                                        data << GetPlayer()->GetNewGUID();
1689                                        data << uint32(0);
1690                                        data << uint32(secsToTimeBitFields(progressIter->second->date));
1691                                        data << uint32(0);
1692                                        data << uint32(0);
1693                                }
1694                        }
1695                        packetFull = data.size() > 0x7f00;
1696                }
1697                if( progressIter == m_criteriaProgress.end() )
1698                {
1699                        doneProgress = true;
1700                }
1701
1702                // another 0xffffffff denotes end of the packet
1703                data << int32(-1);
1704                player->GetSession()->SendPacket(&data);
1705        }
1706        if( isCharacterLoading && player == m_player )
1707        {
1708                // a SMSG_ALL_ACHIEVEMENT_DATA packet has been sent to the player, so the achievement manager can send SMSG_CRITERIA_UPDATE and SMSG_ACHIEVEMENT_EARNED when it gets them
1709                isCharacterLoading = false;
1710        }
1711}
1712
1713/**
1714        Returns the number of achievement progresses that get sent to the player.
1715*/
1716uint32 AchievementMgr::GetCriteriaProgressCount()
1717{
1718        uint32 criteriapc = 0;
1719        for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
1720        {
1721                //AchievementEntry const *achievement = dbcAchievementStore.LookupEntry(iter->second->id);
1722                if( SendAchievementProgress(iter->second) )
1723                {
1724                        ++criteriapc;
1725                }
1726        }
1727        return criteriapc;
1728}
1729
1730/**
1731        Gives reward to player for completing the achievement.
1732*/
1733void AchievementMgr::GiveAchievementReward(AchievementEntry const* entry)
1734{
1735        if( entry == NULL || isCharacterLoading )
1736        {
1737                return;
1738        }
1739        AchievementReward r;
1740        r.type = ACHIEVEMENT_REWARDTYPE_NONE;
1741        r.itemId = 0;
1742        r.rankId = 0;
1743        r.spellId = 0;
1744
1745        if( strlen(entry->rewardName) > 0 )
1746        {
1747                switch(entry->unknown2)
1748                {
1749                        case 0x0000000b: // Title Reward: The Flawless Victor
1750                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1751                                r.rankId = PVPTITLE_THE_FLAWLESS_VICTOR;
1752                                break;
1753                        case 0x000000b6: // Title Reward: Champion of the Frozen Wastes
1754                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1755                                r.rankId = PVPTITLE_CHAMPION_OF_THE_FROZEN_WASTES;
1756                                break;
1757                        case 0x00000229: // Title Reward: Guardian of Cenarius
1758                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1759                                r.rankId = PVPTITLE_GUARDIAN_OF_CENARIUS;
1760                                break;
1761                        case 0x00000244: // Title Reward: Salty
1762                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1763                                r.rankId = PVPTITLE_SALTY;
1764                                break;
1765                        case 0x000005f2: // Reward: Reeking Pet Carrier
1766                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1767                                r.itemId = 40653;
1768                                break;
1769                        case 0x0000066c: // Reward: Title & Loremaster's Colors
1770                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM | ACHIEVEMENT_REWARDTYPE_TITLE;
1771                                r.itemId = 43300;
1772                                r.rankId = PVPTITLE_LOREMASTER;
1773                                break;
1774                        case 0x000006a4: // Title Reward: The Magic Seeker
1775                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1776                                r.rankId = PVPTITLE_THE_MAGIC_SEEKER;
1777                                break;
1778                        case 0x000006a7: // Reward: Black War Bear [Horde]
1779                                // spellId 60018 or 60019 ?
1780                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1781                                r.itemId = 44224;
1782                                break;
1783                        case 0x000006a8: // Reward: Black War Bear [Alliance]
1784                                // spellId 60018 or 60019 ?
1785                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1786                                r.itemId = 44223;
1787                                break;
1788                        case 0x00000749: // Reward: The Schools of Arcane Magic - Mastery
1789                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1790                                r.spellId = 59983;
1791                                break;
1792                        case 0x0000076a: // Title Reward: Conqueror of Naxxramas
1793                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1794                                r.rankId = PVPTITLE_CONQUEROR_OF_NAXXRAMAS;
1795                                break;
1796                        case 0x000007fc: // Reward: Black Proto-Drake
1797                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1798                                r.spellId = 59976;
1799                                break;
1800                        case 0x00000858: // Title Reward: Elder
1801                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1802                                r.rankId = PVPTITLE_ELDER;
1803                                break;
1804                        case 0x0000085b: // Title Reward: The Argent Champion
1805                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1806                                r.rankId = PVPTITLE_THE_ARGENT_CHAMPION;
1807                                break;
1808                        case 0x0000085f: // Title Reward: The Immortal
1809                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1810                                r.rankId = PVPTITLE_THE_IMMORTAL;
1811                                break;
1812                        case 0x000008f4: // Title Reward: The Undying
1813                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1814                                r.rankId = PVPTITLE_THE_UNDYING;
1815                                break;
1816                        case 0x00000975: // Title: Bloodsail Admiral
1817                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1818                                r.rankId = PVPTITLE_BLOODSAIL_ADMIRAL;
1819                                break;
1820                        case 0x000009d3: // Title Reward: Brewmaster
1821                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1822                                r.rankId = PVPTITLE_BREWMASTER;
1823                                break;
1824                        case 0x000009db: // Title Reward: Matron/Patron
1825                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1826                                r.rankId = (GetPlayer()->getGender()==1) ? /* Matron */ PVPTITLE_MATRON : /* Patron */ PVPTITLE_PATRON;
1827                                break;
1828                        case 0x00000a03: // Title Reward: Conqueror
1829                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1830                                r.rankId = PVPTITLE_CONQUEROR;
1831                                break;
1832                        case 0x00000ab1: // Title Reward: The Diplomat
1833                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1834                                r.rankId = PVPTITLE_THE_DIPLOMAT;
1835                                break;
1836                        case 0x00000ac7: // Title Reward: The Explorer
1837                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1838                                r.rankId = PVPTITLE_THE_EXPLORER;
1839                                break;
1840                        case 0x00000b6c: // Title Reward: Justicar
1841                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1842                                r.rankId = PVPTITLE_JUSTICAR;
1843                                break;
1844                        case 0x00000b9e: // Title Reward: Flame Warden
1845                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1846                                r.rankId = PVPTITLE_FLAME_WARDEN;
1847                                break;
1848                        case 0x00000b9f: // Title Reward: Flame Keeper
1849                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1850                                r.rankId = PVPTITLE_FLAME_KEEPER;
1851                                break;
1852                        case 0x00000bb1: // Reward: Titanium Seal of Dalaran
1853                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1854                                r.spellId = 60650;
1855                                break;
1856                        case 0x00000be0: // Reward: Tabard of the Achiever
1857                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1858                                r.itemId = 40643;
1859                                break;
1860                        case 0x00000c14: // Title Reward: Merrymaker
1861                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1862                                r.rankId = PVPTITLE_MERRYMAKER;
1863                                break;
1864                        case 0x00000c78: // Title Reward: The Love Fool
1865                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1866                                r.rankId = PVPTITLE_THE_LOVE_FOOL;
1867                                break;
1868                        case 0x00000cb4: // Title Reward: Of the Nightfall [Normal] Title Reward: Twilight Vanquisher [Heroic]
1869                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1870                                r.rankId = (entry->ID == 2051) ? /* Normal */ PVPTITLE_OF_THE_NIGHTFALL : /* Heroic ID==2054 */ PVPTITLE_TWILIGHT_VANQUISHER;
1871                                break;
1872                        case 0x00000cec: // Title Reward: Obsidian Slayer
1873                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1874                                r.rankId = PVPTITLE_OBSIDIAN_SLAYER;
1875                                break;
1876                        case 0x00000d2c: // Title Reward: Battlemaster
1877                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1878                                r.rankId = PVPTITLE_BATTLEMASTER;
1879                                break;
1880                        case 0x00000d2d: // Title Reward: Battlemaster
1881                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1882                                r.rankId = PVPTITLE_BATTLEMASTER;
1883                                break;
1884                        case 0x00000d2e: // Title Reward: Ambassador
1885                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1886                                r.rankId = PVPTITLE_AMBASSADOR;
1887                                break;
1888                        case 0x00000d2f: // Title Reward: Ambassador
1889                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1890                                r.rankId = PVPTITLE_AMBASSADOR;
1891                                break;
1892                        case 0x00000d56: // Title Reward: The Seeker
1893                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1894                                r.rankId = PVPTITLE_THE_SEEKER;
1895                                break;
1896                        case 0x00000d74: // Reward: Albino Drake
1897                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1898                                r.spellId = 60025;
1899                                break;
1900                        case 0x00000d7d: // Title Reward: Of the Horde or Of the Alliance
1901                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1902                                r.rankId = (GetPlayer()->GetTeam()==HORDE) ? /* Horde */ PVPTITLE_OF_THE_HORDE : /* Alliance */ PVPTITLE_OF_THE_ALLIANCE;
1903                                break;
1904                        case 0x00000da5: // Reward: Tabard of the Explorer
1905                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1906                                r.itemId = 43348;
1907                                break;
1908                        case 0x00000da6: // Reward: Red Proto-Drake
1909                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1910                                r.spellId = 59961;
1911                                break;
1912                        case 0x00000da7: // Title: Jenkins
1913                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1914                                r.rankId = PVPTITLE_JENKINS;
1915                                break;
1916                        case 0x00000dab: // Reward: Plagued Proto-Drake
1917                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1918                                r.spellId = 60021;
1919                                break;
1920                        case 0x00000dac: // Reward: Violet Proto-Drake
1921                                r.type = ACHIEVEMENT_REWARDTYPE_SPELL;
1922                                r.spellId = 60024;
1923                                break;
1924                        case 0x00000dba: // Title Reward: The Hallowed
1925                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1926                                r.rankId = PVPTITLE_THE_HALLOWED;
1927                                break;
1928                        case 0x00000e0b: // Reward: Tabard of Brute Force
1929                                r.type = ACHIEVEMENT_REWARDTYPE_ITEM;
1930                                r.itemId = 43349;
1931                        case 0x00000e10: // Title Reward: Arena Master
1932                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1933                                r.rankId = PVPTITLE_ARENA_MASTER;
1934                                break;
1935                        case 0x00000e12: // Title Reward: The Exalted
1936                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1937                                r.rankId = PVPTITLE_THE_EXALTED;
1938                                break;
1939                        case 0x00000e5e: // Title Reward: Chef
1940                                r.type = ACHIEVEMENT_REWARDTYPE_TITLE;
1941                                r.rankId = PVPTITLE_CHEF;
1942                                break;
1943                        default:
1944                                break;
1945                }
1946                if( r.type & ACHIEVEMENT_REWARDTYPE_TITLE )
1947                {
1948                        GetPlayer()->SetKnownTitle(static_cast< RankTitles >(r.rankId), true);
1949                        GetPlayer()->SetUInt32Value( PLAYER_CHOSEN_TITLE, 0 );
1950                }
1951                if( r.type & ACHIEVEMENT_REWARDTYPE_ITEM )
1952                {
1953                        // How does this work? Add item directly to inventory, or send through mail?
1954                        ItemPrototype* it = ItemPrototypeStorage.LookupEntry(r.itemId);
1955                        if( it )
1956                        {
1957                                Item *item;
1958                                item = objmgr.CreateItem(r.itemId, GetPlayer());
1959                                if( item == NULL )
1960                                {
1961                                        // this is bad - item not found in db or unable to be created for some reason
1962                                        GetPlayer()->GetSession()->SendNotification("Unable to create item with id %lu!", r.itemId);
1963                                        return;
1964                                }
1965                                item->SetUInt32Value(ITEM_FIELD_STACK_COUNT, 1);
1966                                if( it->Bonding==ITEM_BIND_ON_PICKUP )
1967                                {
1968                                        if( it->Flags & ITEM_FLAG_ACCOUNTBOUND )
1969                                        {
1970                                                // any "accountbound" items for achievement rewards?  maybe later...
1971                                                item->AccountBind();
1972                                        }
1973                                        else
1974                                        {
1975                                                item->SoulBind();
1976                                        }
1977                                }
1978
1979                                if( !GetPlayer()->GetItemInterface()->AddItemToFreeSlot(item) )
1980                                {
1981                                        // this is bad. inventory full. maybe we should mail it instead?
1982                                        GetPlayer()->GetSession()->SendNotification("No free slots were found in your inventory!");
1983                                        item->DeleteMe();
1984                                        return;
1985                                }
1986                        }
1987                }
1988                if( r.type & ACHIEVEMENT_REWARDTYPE_SPELL )
1989                {
1990                        GetPlayer()->addSpell(r.spellId);
1991                }
1992        }
1993}
1994
1995/**
1996        Returns the number of completed achievements.
1997*/
1998uint32 AchievementMgr::GetCompletedAchievementsCount() const
1999{
2000        return (uint32)m_completedAchievements.size();
2001}
2002
2003/**
2004        GM has used a command to make the specified achievement to be completed.
2005        If achievementID is -1, all achievements available for the player's faction get marked as completed
2006        Returns true if able to complete specified achievement successfully.
2007        Returns false if there is any error (already completed, not found, ...)
2008*/
2009bool AchievementMgr::GMCompleteAchievement(WorldSession* gmSession, int32 achievementID)
2010{
2011        if( achievementID == -1 )
2012        {
2013                uint32 nr = dbcAchievementStore.GetNumRows();
2014                AchievementEntry const* ach;
2015                for(uint32 i = 0; i < nr; ++i)
2016                {
2017                        ach = dbcAchievementStore.LookupRow(i);
2018                        if( ach == NULL )
2019                        {
2020                                m_player->GetSession()->SystemMessage("Achievement %lu entry not found.", i);
2021                        }
2022                        else
2023                        {
2024                                if( !(ach->flags & ACHIEVEMENT_FLAG_COUNTER) )
2025                                {
2026                                        if( (ach->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && m_player->GetTeam() != HORDE) ||
2027                                                (ach->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && m_player->GetTeam() != ALLIANCE) )
2028                                        {
2029                                                continue;
2030                                        }
2031                                        CompletedAchievement(ach);
2032                                }
2033                        }
2034                }
2035                m_player->GetSession()->SystemMessage("All achievements completed.");
2036                return true;
2037        }
2038        if( m_completedAchievements.find(achievementID) != m_completedAchievements.end() )
2039        {
2040                gmSession->SystemMessage("Player has already completed that achievement.");
2041                return false;
2042        }
2043        AchievementEntry const* achievement = dbcAchievementStore.LookupEntry(achievementID);
2044        if( !achievement )
2045        {
2046                gmSession->SystemMessage("Achievement %lu entry not found.", achievementID);
2047                return false;
2048        }
2049        if( achievement->flags & ACHIEVEMENT_FLAG_COUNTER )
2050        {
2051                gmSession->SystemMessage("Achievement (%lu) |Hachievement:%lu:"I64FMT":0:0:0:-1:0:0:0:0|h[%s]|h is a counter and cannot be completed.",
2052                        achievement->ID, achievement->ID, gmSession->GetPlayer()->GetGUID(), achievement->name);
2053                return false;
2054        }
2055        CompletedAchievement(achievement);
2056        return true;
2057}
2058
2059/**
2060        GM has used a command to make the specified achievement criteria to be completed.
2061        If criteriaID is -1, all achievement criteria get marked as completed
2062        Returns true if able to complete specified achievement criteria successfully.
2063        Returns false if there is any error (already completed not found, ...)
2064*/
2065bool AchievementMgr::GMCompleteCriteria(WorldSession* gmSession, int32 criteriaID)
2066{
2067        if( criteriaID == -1 )
2068        {
2069                uint32 nr = dbcAchievementCriteriaStore.GetNumRows();
2070                AchievementCriteriaEntry const* crt;
2071                for(uint32 i = 0, j = 0; j < nr; ++i)
2072                {
2073                        crt = dbcAchievementCriteriaStore.LookupRow(i);
2074                        if( crt == NULL )
2075                        {
2076                                sLog.outError("Achievement Criteria %lu entry not found.", i);
2077                                continue;
2078                        }
2079                        ++j;
2080                        if( crt->raw.field4 )
2081                        {
2082                                SetCriteriaProgress( crt, crt->raw.field4 );
2083                                CompletedCriteria(crt);
2084                        }
2085                }
2086                m_player->GetSession()->SystemMessage("All achievement criteria completed.");
2087                return true;
2088        }
2089        AchievementCriteriaEntry const* criteria = dbcAchievementCriteriaStore.LookupEntry(criteriaID);
2090        if( !criteria )
2091        {
2092                gmSession->SystemMessage("Achievement criteria %lu not found.", criteriaID);
2093                return false;
2094        }
2095        if( IsCompletedCriteria(criteria) )
2096        {
2097                gmSession->SystemMessage("Achievement criteria %lu already completed.", criteriaID);
2098                return false;
2099        }
2100        AchievementEntry const* achievement = dbcAchievementStore.LookupEntry(criteria->referredAchievement);
2101        if( !achievement )
2102        {
2103                // achievement not found
2104                gmSession->SystemMessage("Referred achievement (%lu) entry not found.", criteria->referredAchievement);
2105                return false;
2106        }
2107        if( achievement->flags & ACHIEVEMENT_FLAG_COUNTER )
2108        {
2109                // can't complete this type of achivement (counter)
2110                gmSession->SystemMessage("Referred achievement (%lu) |Hachievement:%lu:"I64FMT":0:0:0:-1:0:0:0:0|h[%s]|h is a counter and cannot be completed.",
2111                        achievement->ID, achievement->ID, gmSession->GetPlayer()->GetGUID(), achievement->name);
2112                return false;
2113        }
2114
2115        CriteriaProgressMap::iterator itr = m_criteriaProgress.find(criteriaID);
2116        CriteriaProgress *progress;
2117        if( itr == m_criteriaProgress.end() )
2118        {
2119                // not in progress map
2120                progress = new CriteriaProgress(criteriaID, 0);
2121                m_criteriaProgress[criteriaID]=progress;
2122        }
2123        else
2124        {
2125                progress = itr->second;
2126        }
2127
2128        progress->counter = criteria->raw.field4;
2129        SendCriteriaUpdate( progress );
2130        CompletedCriteria(criteria);
2131        return true;
2132}
2133
2134/**
2135        GM has used a command to reset achievement(s) for this player.
2136        If achievementID is -1, all achievements get reset, otherwise only the one specified gets reset.
2137*/
2138void AchievementMgr::GMResetAchievement(int32 achievementID)
2139{
2140        std::ostringstream ss;
2141        if( achievementID == -1 )
2142        {
2143                // reset all achievements
2144                CompletedAchievementMap::iterator itr = m_completedAchievements.begin();
2145                for(; itr != m_completedAchievements.end(); ++itr)
2146                {
2147                        WorldPacket resetData(SMSG_ACHIEVEMENT_DELETED, 4);
2148                        resetData << uint32(itr->first);
2149                        GetPlayer()->GetSession()->SendPacket(&resetData);
2150                }
2151                m_completedAchievements.clear();
2152                ss << "DELETE FROM character_achievement WHERE guid = " << m_player->GetLowGUID();
2153                CharacterDatabase.Execute( ss.str().c_str() );
2154        }
2155        else // reset a single achievement
2156        {
2157                WorldPacket resetData(SMSG_ACHIEVEMENT_DELETED, 4);
2158                resetData << uint32(achievementID);
2159                GetPlayer()->GetSession()->SendPacket(&resetData);
2160                m_completedAchievements.erase(achievementID);
2161                ss << "DELETE FROM character_achievement WHERE guid = " << m_player->GetLowGUID() << " AND achievement = " << achievementID;
2162                CharacterDatabase.Execute( ss.str().c_str() );
2163        }
2164}
2165
2166/**
2167        GM has used a command to reset achievement criteria for this player.
2168        If criteriaID is -1, all achievement criteria get reset, otherwise only the one specified gets reset.
2169*/
2170void AchievementMgr::GMResetCriteria(int32 criteriaID)
2171{
2172        std::ostringstream ss;
2173        if( criteriaID == -1 )
2174        {
2175                // reset all achievement criteria
2176                for(CriteriaProgressMap::iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
2177                {
2178                        WorldPacket resetData(SMSG_CRITERIA_DELETED, 4);
2179                        resetData << uint32(iter->first);
2180                        GetPlayer()->GetSession()->SendPacket(&resetData);
2181                        delete iter->second;
2182                }
2183                m_criteriaProgress.clear();
2184                ss << "DELETE FROM character_achievement_progress WHERE guid = " << m_player->GetLowGUID();
2185                CharacterDatabase.Execute( ss.str().c_str() );
2186        }
2187        else // reset a single achievement criteria
2188        {
2189                WorldPacket resetData(SMSG_CRITERIA_DELETED, 4);
2190                resetData << uint32(criteriaID);
2191                GetPlayer()->GetSession()->SendPacket(&resetData);
2192                m_criteriaProgress.erase(criteriaID);
2193                ss << "DELETE FROM character_achievement_progress WHERE guid = " << m_player->GetLowGUID() << " AND criteria = " << criteriaID;
2194                CharacterDatabase.Execute( ss.str().c_str() );
2195        }
2196        CheckAllAchievementCriteria();
2197}
2198
2199/**
2200        Date/Time (time_t) the achievement was completed, or 0 if achievement not completed yet
2201*/
2202time_t AchievementMgr::GetCompletedTime(AchievementEntry const* achievement)
2203{
2204        CompletedAchievementMap::iterator iter = m_completedAchievements.find(achievement->ID);
2205        if( iter != m_completedAchievements.end() )
2206        {
2207                // achievement is completed, return the date/time it was completed
2208                return iter->second;
2209        }
2210        return 0; // achievement not completed
2211}
2212
2213/**
2214        true if achievementID has been completed by the player, false otherwise.
2215*/
2216bool AchievementMgr::HasCompleted(uint32 achievementID)
2217{
2218        return (m_completedAchievements.find(achievementID) != m_completedAchievements.end());
2219}
2220
2221#endif
Note: See TracBrowser for help on using the browser.