2010-10-07 15:35:36 +02:00
/*
2011-01-01 15:01:13 +01:00
* Copyright (C) 2008-2011 TrinityCore <http://www.trinitycore.org/>
2010-10-07 15:35:36 +02:00
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
2008-12-24 09:58:26 -06:00
*/
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
#include "Common.h"
2009-03-27 09:58:20 -06:00
#include "DBCEnums.h"
2008-12-24 09:58:26 -06:00
#include "ObjectMgr.h"
2011-05-03 15:01:10 +02:00
#include "ArenaTeamMgr.h"
2011-05-04 10:08:09 +02:00
#include "GuildMgr.h"
2008-12-24 09:58:26 -06:00
#include "World.h"
2010-06-08 13:05:47 -06:00
#include "WorldPacket.h"
#include "DatabaseEnv.h"
2009-06-04 21:41:07 +02:00
#include "AchievementMgr.h"
2009-03-06 15:21:44 -06:00
#include "ArenaTeam.h"
2010-06-08 13:05:47 -06:00
#include "CellImpl.h"
#include "GameEventMgr.h"
#include "GridNotifiersImpl.h"
#include "Guild.h"
#include "Language.h"
2009-06-04 21:41:07 +02:00
#include "Player.h"
#include "SpellMgr.h"
2010-07-21 12:14:23 +02:00
#include "DisableMgr.h"
2010-08-07 17:58:45 +02:00
#include "ScriptMgr.h"
2009-07-01 18:36:03 -05:00
#include "MapManager.h"
2010-08-08 04:37:24 +02:00
#include "Battleground.h"
#include "BattlegroundAB.h"
2009-12-25 15:53:37 +01:00
#include "Map.h"
2010-08-08 22:54:58 +06:00
#include "InstanceScript.h"
2008-12-24 09:58:26 -06:00
2009-12-20 15:20:04 +01:00
namespace Trinity
2009-02-21 17:02:56 -06:00
{
class AchievementChatBuilder
{
public :
AchievementChatBuilder ( Player const & pl , ChatMsg msgtype , int32 textId , uint32 ach_id )
: i_player ( pl ), i_msgtype ( msgtype ), i_textId ( textId ), i_achievementId ( ach_id ) {}
2010-09-17 07:04:29 +02:00
void operator ()( WorldPacket & data , LocaleConstant loc_idx )
2009-02-21 17:02:56 -06:00
{
2011-04-29 20:47:02 +02:00
char const * text = sObjectMgr -> GetTrinityString ( i_textId , loc_idx );
2009-10-17 15:51:44 -07:00
2009-02-21 17:02:56 -06:00
data << uint8 ( i_msgtype );
data << uint32 ( LANG_UNIVERSAL );
data << uint64 ( i_player . GetGUID ());
data << uint32 ( 5 );
data << uint64 ( i_player . GetGUID ());
data << uint32 ( strlen ( text ) + 1 );
data << text ;
data << uint8 ( 0 );
data << uint32 ( i_achievementId );
}
2009-10-17 15:51:44 -07:00
2009-02-21 17:02:56 -06:00
private :
Player const & i_player ;
ChatMsg i_msgtype ;
int32 i_textId ;
uint32 i_achievementId ;
};
2009-12-20 15:20:04 +01:00
} // namespace Trinity
2009-02-21 17:02:56 -06:00
2009-04-08 16:24:34 -05:00
bool AchievementCriteriaData :: IsValid ( AchievementCriteriaEntry const * criteria )
{
2010-04-07 19:14:10 +02:00
if ( dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE )
2009-04-08 16:24:34 -05:00
{
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` for criteria (Entry: %u) has wrong data type (%u), ignored." , criteria -> ID , dataType );
2009-04-08 16:24:34 -05:00
return false ;
}
2009-10-17 15:51:44 -07:00
2010-12-17 18:12:46 +01:00
switch ( criteria -> requiredType )
2009-04-08 16:24:34 -05:00
{
2009-06-07 20:54:23 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE :
2009-08-02 10:12:40 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG :
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING :
2011-04-30 12:41:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST : // only hardcoded list
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL :
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA :
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE :
2010-03-22 18:32:38 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL :
2009-08-02 10:12:40 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL :
2009-04-29 18:42:53 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE :
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 :
2010-01-16 19:41:04 +03:00
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET :
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 :
2010-01-25 22:56:26 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT :
2010-08-07 18:31:06 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE :
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL :
2011-04-30 12:41:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST : // only Children's Week achievements
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM : // only Children's Week achievements
2011-05-14 12:26:49 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS :
2009-04-08 16:24:34 -05:00
break ;
default :
2011-06-19 13:51:14 +02:00
if ( dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT )
{
sLog -> outErrorDb ( "Table `achievement_criteria_data` has data for non-supported criteria type (Entry: %u Type: %u), ignored." , criteria -> ID , criteria -> requiredType );
return false ;
}
break ;
2009-04-08 16:24:34 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-17 18:12:46 +01:00
switch ( dataType )
2009-04-08 16:24:34 -05:00
{
case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE :
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE :
2009-12-25 15:53:37 +01:00
case ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT :
2009-04-08 16:24:34 -05:00
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE :
2011-04-28 22:57:08 +02:00
if ( ! creature . id || ! sObjectMgr -> GetCreatureTemplate ( creature . id ))
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing creature id in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , creature . id );
2009-04-08 16:24:34 -05:00
return false ;
}
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE :
2009-06-14 10:00:45 -05:00
if ( ! classRace . class_id && ! classRace . race_id )
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) must not have 0 in either value field, ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType );
2009-04-08 16:24:34 -05:00
return false ;
}
2010-04-07 23:25:02 +02:00
if ( classRace . class_id && (( 1 << ( classRace . class_id - 1 )) & CLASSMASK_ALL_PLAYABLE ) == 0 )
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing class in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , classRace . class_id );
2009-04-08 16:24:34 -05:00
return false ;
}
2010-04-07 23:25:02 +02:00
if ( classRace . race_id && (( 1 << ( classRace . race_id - 1 )) & RACEMASK_ALL_PLAYABLE ) == 0 )
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) has non-existing race in value2 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , classRace . race_id );
2009-04-08 16:24:34 -05:00
return false ;
}
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH :
2009-06-14 10:00:45 -05:00
if ( health . percent < 1 || health . percent > 100 )
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) has wrong percent value in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , health . percent );
2009-04-08 16:24:34 -05:00
return false ;
}
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD :
2009-06-14 10:00:45 -05:00
if ( player_dead . own_team_flag > 1 )
2009-05-24 11:18:23 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD (%u) has wrong boolean value1 (%u)." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , player_dead . own_team_flag );
2009-05-24 11:18:23 -05:00
return false ;
}
2009-04-08 16:34:38 -05:00
return true ;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA :
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA :
{
2011-07-26 23:09:28 +02:00
SpellInfo const * spellEntry = sSpellMgr -> GetSpellInfo ( aura . spell_id );
2009-06-14 10:00:45 -05:00
if ( ! spellEntry )
2009-04-08 16:34:38 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell id in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , ( dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA" ), dataType , aura . spell_id );
2009-04-08 16:34:38 -05:00
return false ;
}
2009-06-14 10:00:45 -05:00
if ( aura . effect_idx >= 3 )
2009-04-08 16:34:38 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has wrong spell effect index in value2 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , ( dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA" ), dataType , aura . effect_idx );
2009-04-08 16:34:38 -05:00
return false ;
}
2011-07-26 23:09:28 +02:00
if ( ! spellEntry -> Effects [ aura . effect_idx ]. ApplyAuraName )
2009-04-08 16:34:38 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) has non-aura spell effect (ID: %u Effect: %u), ignores." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , ( dataType == ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA ? "ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA" : "ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA" ), dataType , aura . spell_id , aura . effect_idx );
2009-04-08 16:34:38 -05:00
return false ;
}
return true ;
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA :
2009-06-14 10:00:45 -05:00
if ( ! GetAreaEntryByAreaID ( area . id ))
2009-04-08 16:34:38 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) has wrong area id in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , area . id );
2009-04-08 16:34:38 -05:00
return false ;
}
return true ;
2009-06-07 20:52:00 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL :
2010-08-21 23:40:53 +02:00
if ( level . minlevel > STRONG_MAX_LEVEL )
2009-06-07 20:52:00 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL (%u) has wrong minlevel in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , level . minlevel );
2009-06-07 20:52:00 -05:00
return false ;
}
return true ;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER :
2009-06-14 10:00:45 -05:00
if ( gender . gender > GENDER_NONE )
2009-06-07 20:52:00 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER (%u) has wrong gender in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , gender . gender );
2009-06-07 20:52:00 -05:00
return false ;
}
return true ;
2010-08-07 16:48:34 +02:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT :
if ( ! ScriptId )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT (%u) does not have ScriptName set, ignored." ,
2010-08-07 16:48:34 +02:00
criteria -> ID , criteria -> requiredType , dataType );
return false ;
}
return true ;
2009-06-07 20:54:23 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY :
2009-12-17 10:35:35 +01:00
if ( difficulty . difficulty >= MAX_DIFFICULTY )
2009-06-07 20:54:23 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY (%u) has wrong difficulty in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , difficulty . difficulty );
2009-06-07 20:54:23 -05:00
return false ;
}
return true ;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT :
2009-06-14 10:00:45 -05:00
if ( map_players . maxcount <= 0 )
2009-06-07 20:54:23 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT (%u) has wrong max players count in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , map_players . maxcount );
2009-06-07 20:54:23 -05:00
return false ;
}
return true ;
2009-06-09 17:20:19 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM :
2009-06-14 10:00:45 -05:00
if ( team . team != ALLIANCE && team . team != HORDE )
2009-06-09 17:20:19 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM (%u) has unknown team in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , team . team );
2009-06-14 09:59:50 -05:00
return false ;
}
return true ;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK :
2010-04-07 19:14:10 +02:00
if ( drunk . state >= MAX_DRUNKEN )
2009-06-14 09:59:50 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK (%u) has unknown drunken state in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , drunk . state );
2009-06-09 17:20:19 -05:00
return false ;
}
return true ;
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY :
if ( ! sHolidaysStore . LookupEntry ( holiday . id ))
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY (%u) has unknown holiday in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , holiday . id );
2009-06-14 10:00:45 -05:00
return false ;
}
return true ;
2009-07-31 11:36:02 +08:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE :
2009-07-31 11:37:03 +08:00
return true ; // not check correctness node indexes
2010-03-22 18:32:38 +01:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM :
if ( equipped_item . item_quality >= MAX_ITEM_QUALITY )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_requirement` (Entry: %u Type: %u) for requirement ACHIEVEMENT_CRITERIA_REQUIRE_S_EQUIPED_ITEM (%u) has unknown quality state in value1 (%u), ignored." ,
2011-04-29 20:47:02 +02:00
criteria -> ID , criteria -> requiredType , dataType , equipped_item . item_quality );
2010-03-22 18:32:38 +01:00
return false ;
}
return true ;
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID :
if ( ! sMapStore . LookupEntry ( map_id . mapId ))
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_requirement` (Entry: %u Type: %u) for requirement ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID (%u) has unknown map id in value1 (%u), ignored." ,
2010-12-17 18:12:46 +01:00
criteria -> ID , criteria -> requiredType , dataType , map_id . mapId );
return false ;
}
return true ;
2009-04-08 16:24:34 -05:00
default :
2011-04-29 20:47:02 +02:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` (Entry: %u Type: %u) has data for non-supported data type (%u), ignored." , criteria -> ID , criteria -> requiredType , dataType );
2009-04-08 16:24:34 -05:00
return false ;
}
}
2009-10-17 15:51:44 -07:00
2009-12-25 15:53:37 +01:00
bool AchievementCriteriaData :: Meets ( uint32 criteria_id , Player const * source , Unit const * target , uint32 miscvalue1 /*= 0*/ ) const
2009-04-08 16:24:34 -05:00
{
2010-12-17 18:12:46 +01:00
switch ( dataType )
2009-04-08 16:24:34 -05:00
{
case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE :
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE :
2010-04-08 08:20:08 +02:00
if ( ! target || target -> GetTypeId () != TYPEID_UNIT )
2009-04-08 16:24:34 -05:00
return false ;
2009-06-07 20:54:23 -05:00
return target -> GetEntry () == creature . id ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE :
2009-10-18 18:38:46 -07:00
if ( ! target || target -> GetTypeId () != TYPEID_PLAYER )
2009-04-08 16:24:34 -05:00
return false ;
2010-04-07 19:14:10 +02:00
if ( classRace . class_id && classRace . class_id != target -> ToPlayer () -> getClass ())
2009-04-08 16:24:34 -05:00
return false ;
2010-04-07 19:14:10 +02:00
if ( classRace . race_id && classRace . race_id != target -> ToPlayer () -> getRace ())
2009-04-08 16:24:34 -05:00
return false ;
return true ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH :
2009-10-18 18:38:46 -07:00
if ( ! target || target -> GetTypeId () != TYPEID_PLAYER )
2009-04-08 16:24:34 -05:00
return false ;
2010-08-26 01:20:57 +06:00
return ! target -> HealthAbovePct ( health . percent );
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD :
2010-08-26 01:20:57 +06:00
if ( target && ! target -> isAlive ())
if ( const Player * player = target -> ToPlayer ())
if ( player -> GetDeathTimer () != 0 )
// flag set == must be same team, not set == different team
return ( player -> GetTeam () == source -> GetTeam ()) == ( player_dead . own_team_flag != 0 );
return false ;
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA :
2011-04-29 20:47:02 +02:00
return source -> HasAuraEffect ( aura . spell_id , aura . effect_idx );
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA :
{
2011-04-29 20:47:02 +02:00
uint32 zone_id , area_id ;
source -> GetZoneAndAreaId ( zone_id , area_id );
2010-04-07 23:25:02 +02:00
return area . id == zone_id || area . id == area_id ;
2009-04-08 16:34:38 -05:00
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA :
2011-04-29 20:47:02 +02:00
return target && target -> HasAuraEffect ( aura . spell_id , aura . effect_idx );
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_VALUE :
return miscvalue1 >= value . minvalue ;
2009-06-07 20:52:00 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_LEVEL :
if ( ! target )
return false ;
return target -> getLevel () >= level . minlevel ;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_GENDER :
if ( ! target )
return false ;
return target -> getGender () == gender . gender ;
2010-08-07 16:48:34 +02:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT :
2010-12-22 21:25:23 +01:00
return sScriptMgr -> OnCriteriaCheck ( this , const_cast < Player *> ( source ), const_cast < Unit *> ( target ));
2009-06-07 20:54:23 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_DIFFICULTY :
2011-09-05 15:21:37 +02:00
if ( source -> GetMap () -> IsRaid ())
if ( source -> GetMap () -> Is25ManRaid () != ( difficulty . difficulty & RAID_DIFFICULTY_MASK_25MAN ))
return false ;
return source -> GetMap () -> GetSpawnMode () >= difficulty . difficulty ;
2009-06-07 20:54:23 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_PLAYER_COUNT :
return source -> GetMap () -> GetPlayersCountExceptGMs () <= map_players . maxcount ;
2009-06-09 17:20:19 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_TEAM :
if ( ! target || target -> GetTypeId () != TYPEID_PLAYER )
return false ;
2010-03-07 15:20:19 +01:00
return target -> ToPlayer () -> GetTeam () == team . team ;
2009-06-14 09:59:50 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_DRUNK :
2010-08-23 07:51:19 +02:00
return Player :: GetDrunkenstateByValue ( source -> GetDrunkValue ()) >= DrunkenState ( drunk . state );
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_HOLIDAY :
return IsHolidayActive ( HolidayIds ( holiday . id ));
2009-07-31 11:36:02 +08:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_BG_LOSS_TEAM_SCORE :
{
2010-08-08 04:37:24 +02:00
Battleground * bg = source -> GetBattleground ();
2010-04-07 19:14:10 +02:00
if ( ! bg )
2009-07-31 11:36:02 +08:00
return false ;
2011-04-29 20:47:02 +02:00
return bg -> IsTeamScoreInRange ( source -> GetTeam () == ALLIANCE ? HORDE : ALLIANCE , bg_loss_team_score . min_score , bg_loss_team_score . max_score );
2009-07-31 11:36:02 +08:00
}
2009-12-25 15:53:37 +01:00
case ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT :
2010-03-22 18:32:38 +01:00
{
2009-12-25 15:53:37 +01:00
if ( ! source -> IsInWorld ())
return false ;
Map * map = source -> GetMap ();
2010-04-20 21:55:47 +02:00
if ( ! map -> IsDungeon ())
2009-12-25 15:53:37 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Achievement system call ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT (%u) for achievement criteria %u for non-dungeon/non-raid map %u" ,
2009-12-25 15:53:37 +01:00
ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT , criteria_id , map -> GetId ());
return false ;
}
2010-12-17 18:12:46 +01:00
InstanceScript * instance = (( InstanceMap * ) map ) -> GetInstanceScript ();
if ( ! instance )
2009-12-25 15:53:37 +01:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Achievement system call ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT (%u) for achievement criteria %u for map %u but map does not have a instance script" ,
2009-12-25 15:53:37 +01:00
ACHIEVEMENT_CRITERIA_DATA_INSTANCE_SCRIPT , criteria_id , map -> GetId ());
return false ;
}
2010-12-17 18:12:46 +01:00
return instance -> CheckAchievementCriteriaMeet ( criteria_id , source , target , miscvalue1 );
2010-03-22 18:32:38 +01:00
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_EQUIPED_ITEM :
{
2011-04-28 22:42:33 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( miscvalue1 );
2010-03-22 18:32:38 +01:00
if ( ! pProto )
return false ;
return pProto -> ItemLevel >= equipped_item . item_level && pProto -> Quality >= equipped_item . item_quality ;
}
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_DATA_TYPE_MAP_ID :
return source -> GetMapId () == map_id . mapId ;
default :
break ;
2009-04-08 16:24:34 -05:00
}
return false ;
}
2009-10-17 15:51:44 -07:00
2009-06-01 21:51:34 -05:00
bool AchievementCriteriaDataSet :: Meets ( Player const * source , Unit const * target , uint32 miscvalue /*= 0*/ ) const
2009-04-08 16:34:38 -05:00
{
2009-10-17 16:20:24 -07:00
for ( Storage :: const_iterator itr = storage . begin (); itr != storage . end (); ++ itr )
2010-04-07 19:14:10 +02:00
if ( ! itr -> Meets ( criteria_id , source , target , miscvalue ))
2009-04-08 16:34:38 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-08 16:34:38 -05:00
return true ;
}
2009-10-17 15:51:44 -07:00
2011-06-12 01:47:45 +02:00
AchievementMgr :: AchievementMgr ( Player * player )
2008-12-24 09:58:26 -06:00
{
m_player = player ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
AchievementMgr ::~ AchievementMgr ()
{
}
2009-10-17 15:51:44 -07:00
2009-02-06 15:40:48 -06:00
void AchievementMgr :: Reset ()
{
2010-04-08 08:20:08 +02:00
for ( CompletedAchievementMap :: const_iterator iter = m_completedAchievements . begin (); iter != m_completedAchievements . end (); ++ iter )
2009-02-06 15:40:48 -06:00
{
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_ACHIEVEMENT_DELETED , 4 );
2009-02-06 15:40:48 -06:00
data << uint32 ( iter -> first );
m_player -> SendDirectMessage ( & data );
}
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( CriteriaProgressMap :: const_iterator iter = m_criteriaProgress . begin (); iter != m_criteriaProgress . end (); ++ iter )
2009-02-06 15:40:48 -06:00
{
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_CRITERIA_DELETED , 4 );
2009-02-06 15:40:48 -06:00
data << uint32 ( iter -> first );
m_player -> SendDirectMessage ( & data );
}
2009-10-17 15:51:44 -07:00
2009-02-06 15:40:48 -06:00
m_completedAchievements . clear ();
m_criteriaProgress . clear ();
DeleteFromDB ( m_player -> GetGUIDLow ());
2009-10-17 15:51:44 -07:00
2009-02-06 15:40:48 -06:00
// re-fill data
CheckAllAchievementCriteria ();
}
2009-10-17 15:51:44 -07:00
2010-08-07 18:31:06 +02:00
void AchievementMgr :: ResetAchievementCriteria ( AchievementCriteriaTypes type , uint32 miscvalue1 , uint32 miscvalue2 , bool evenIfCriteriaComplete )
2009-04-23 22:07:37 -05:00
{
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_ACHIEVEMENTSYS , "AchievementMgr::ResetAchievementCriteria(%u, %u, %u)" , type , miscvalue1 , miscvalue2 );
2009-10-17 15:51:44 -07:00
2011-07-02 02:14:49 +02:00
// disable for gamemasters with GM-mode enabled
2011-07-02 02:41:03 +02:00
if ( m_player -> isGameMaster ())
2009-04-23 22:07:37 -05:00
return ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
AchievementCriteriaEntryList const & achievementCriteriaList = sAchievementMgr -> GetAchievementCriteriaByType ( type );
2010-04-08 08:20:08 +02:00
for ( AchievementCriteriaEntryList :: const_iterator i = achievementCriteriaList . begin (); i != achievementCriteriaList . end (); ++ i )
2009-04-23 22:07:37 -05:00
{
AchievementCriteriaEntry const * achievementCriteria = ( * i );
2009-10-17 15:51:44 -07:00
2009-04-23 22:07:37 -05:00
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( achievementCriteria -> referredAchievement );
if ( ! achievement )
continue ;
2009-10-17 15:51:44 -07:00
2010-08-07 18:31:06 +02:00
// don't update already completed criteria if not forced or achievement already complete
2010-08-07 23:46:00 +02:00
if (( IsCompletedCriteria ( achievementCriteria , achievement ) && ! evenIfCriteriaComplete ) || HasAchieved ( achievement ))
2009-04-23 22:07:37 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-08-07 18:31:06 +02:00
for ( uint8 j = 0 ; j < MAX_CRITERIA_REQUIREMENTS ; ++ j )
2011-03-26 05:33:46 +02:00
if ( achievementCriteria -> additionalRequirements [ j ]. additionalRequirement_type == miscvalue1 &&
( ! achievementCriteria -> additionalRequirements [ j ]. additionalRequirement_value ||
achievementCriteria -> additionalRequirements [ j ]. additionalRequirement_value == miscvalue2 ))
2010-08-07 18:31:06 +02:00
{
2010-08-13 13:48:59 +02:00
RemoveCriteriaProgress ( achievementCriteria );
2009-04-23 22:07:37 -05:00
break ;
2010-08-07 18:31:06 +02:00
}
2009-04-23 22:07:37 -05:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-06 15:40:48 -06:00
void AchievementMgr :: DeleteFromDB ( uint32 lowguid )
{
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2011-04-29 20:47:02 +02:00
trans -> PAppend ( "DELETE FROM character_achievement WHERE guid = %u" , lowguid );
trans -> PAppend ( "DELETE FROM character_achievement_progress WHERE guid = %u" , lowguid );
2010-08-21 03:19:25 +02:00
CharacterDatabase . CommitTransaction ( trans );
2009-02-06 15:40:48 -06:00
}
2009-10-17 15:51:44 -07:00
2010-08-21 03:19:25 +02:00
void AchievementMgr :: SaveToDB ( SQLTransaction & trans )
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( ! m_completedAchievements . empty ())
2008-12-24 09:58:26 -06:00
{
bool need_execute = false ;
std :: ostringstream ssdel ;
std :: ostringstream ssins ;
2010-04-08 08:20:08 +02:00
for ( CompletedAchievementMap :: iterator iter = m_completedAchievements . begin (); iter != m_completedAchievements . end (); ++ iter )
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( ! iter -> second . changed )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
/// first new/changed record prefix
2010-04-07 19:14:10 +02:00
if ( ! need_execute )
2008-12-24 09:58:26 -06:00
{
ssdel << "DELETE FROM character_achievement WHERE guid = " << GetPlayer () -> GetGUIDLow () << " AND achievement IN (" ;
ssins << "INSERT INTO character_achievement (guid, achievement, date) VALUES " ;
need_execute = true ;
}
/// next new/changed record prefix
else
{
2011-07-29 14:18:28 +02:00
ssdel << ',' ;
ssins << ',' ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// new/changed record data
ssdel << iter -> first ;
2011-07-29 14:18:28 +02:00
ssins << '(' << GetPlayer () -> GetGUIDLow () << ',' << iter -> first << ',' << uint64 ( iter -> second . date ) << ')' ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
/// mark as saved in db
iter -> second . changed = false ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( need_execute )
2011-07-29 14:18:28 +02:00
ssdel << ')' ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( need_execute )
2008-12-24 09:58:26 -06:00
{
2010-08-21 03:19:25 +02:00
trans -> Append ( ssdel . str (). c_str ());
trans -> Append ( ssins . str (). c_str ());
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! m_criteriaProgress . empty ())
2008-12-24 09:58:26 -06:00
{
/// prepare deleting and insert
2009-01-20 19:59:43 -06:00
bool need_execute_del = false ;
bool need_execute_ins = false ;
2008-12-24 09:58:26 -06:00
std :: ostringstream ssdel ;
std :: ostringstream ssins ;
2010-04-08 08:20:08 +02:00
for ( CriteriaProgressMap :: iterator iter = m_criteriaProgress . begin (); iter != m_criteriaProgress . end (); ++ iter )
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( ! iter -> second . changed )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
// deleted data (including 0 progress state)
2008-12-24 09:58:26 -06:00
{
2009-01-20 19:59:43 -06:00
/// first new/changed record prefix (for any counter value)
2010-04-07 19:14:10 +02:00
if ( ! need_execute_del )
2009-01-20 19:59:43 -06:00
{
ssdel << "DELETE FROM character_achievement_progress WHERE guid = " << GetPlayer () -> GetGUIDLow () << " AND criteria IN (" ;
need_execute_del = true ;
}
/// next new/changed record prefix
else
2011-07-29 14:18:28 +02:00
ssdel << ',' ;
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
// new/changed record data
ssdel << iter -> first ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
// store data only for real progress
2010-04-07 19:14:10 +02:00
if ( iter -> second . counter != 0 )
2008-12-24 09:58:26 -06:00
{
2009-01-20 19:59:43 -06:00
/// first new/changed record prefix
2010-04-07 19:14:10 +02:00
if ( ! need_execute_ins )
2009-01-20 19:59:43 -06:00
{
ssins << "INSERT INTO character_achievement_progress (guid, criteria, counter, date) VALUES " ;
need_execute_ins = true ;
}
/// next new/changed record prefix
else
2011-07-29 14:18:28 +02:00
ssins << ',' ;
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
// new/changed record data
2011-07-29 14:18:28 +02:00
ssins << '(' << GetPlayer () -> GetGUIDLow () << ',' << iter -> first << ',' << iter -> second . counter << ',' << iter -> second . date << ')' ;
2009-01-20 19:59:43 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
/// mark as updated in db
2008-12-24 09:58:26 -06:00
iter -> second . changed = false ;
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( need_execute_del ) // DELETE ... IN (.... _)_
2011-07-29 14:18:28 +02:00
ssdel << ')' ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( need_execute_del || need_execute_ins )
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( need_execute_del )
2010-08-21 03:19:25 +02:00
trans -> Append ( ssdel . str (). c_str ());
2010-04-07 19:14:10 +02:00
if ( need_execute_ins )
2010-08-21 03:19:25 +02:00
trans -> Append ( ssins . str (). c_str ());
2008-12-24 09:58:26 -06:00
}
}
}
2009-10-17 15:51:44 -07:00
2010-09-20 18:20:40 +02:00
void AchievementMgr :: LoadFromDB ( PreparedQueryResult achievementResult , PreparedQueryResult criteriaResult )
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( achievementResult )
2008-12-24 09:58:26 -06:00
{
do
{
2010-09-25 17:10:00 +02:00
Field * fields = achievementResult -> Fetch ();
2011-01-28 15:34:53 +01:00
uint32 achievementid = fields [ 0 ]. GetUInt16 ();
2009-10-17 15:51:44 -07:00
2011-07-29 14:18:28 +02:00
// must not happen: cleanup at server startup in sAchievementMgr->LoadCompletedAchievements()
2011-01-28 15:34:53 +01:00
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( achievementid );
if ( ! achievement )
2009-05-08 19:22:17 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-01-28 15:34:53 +01:00
CompletedAchievementData & ca = m_completedAchievements [ achievementid ];
2011-01-19 02:53:44 +01:00
ca . date = time_t ( fields [ 1 ]. GetUInt32 ());
2008-12-24 09:58:26 -06:00
ca . changed = false ;
2011-01-28 15:34:53 +01:00
// title achievement rewards are retroactive
if ( AchievementReward const * reward = sAchievementMgr -> GetAchievementReward ( achievement ))
if ( uint32 titleId = reward -> titleId [ GetPlayer () -> GetTeam () == ALLIANCE ? 0 : 1 ])
if ( CharTitlesEntry const * titleEntry = sCharTitlesStore . LookupEntry ( titleId ))
if ( ! GetPlayer () -> HasTitle ( titleEntry ))
GetPlayer () -> SetTitle ( titleEntry );
} while ( achievementResult -> NextRow ());
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( criteriaResult )
2008-12-24 09:58:26 -06:00
{
do
{
2010-09-25 17:10:00 +02:00
Field * fields = criteriaResult -> Fetch ();
2011-01-19 02:53:44 +01:00
uint32 id = fields [ 0 ]. GetUInt16 ();
2010-09-24 22:16:21 +02:00
uint32 counter = fields [ 1 ]. GetUInt32 ();
2011-01-19 02:53:44 +01:00
time_t date = time_t ( fields [ 2 ]. GetUInt32 ());
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
AchievementCriteriaEntry const * criteria = sAchievementCriteriaStore . LookupEntry ( id );
2009-05-08 19:22:17 -05:00
if ( ! criteria )
{
// we will remove not existed criteria for all characters
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Non-existing achievement criteria %u data removed from table `character_achievement_progress`." , id );
CharacterDatabase . PExecute ( "DELETE FROM character_achievement_progress WHERE criteria = %u" , id );
2009-05-08 19:22:17 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-12-24 10:20:15 +01:00
if ( criteria -> timeLimit && time_t ( date + criteria -> timeLimit ) < time ( NULL ))
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
CriteriaProgress & progress = m_criteriaProgress [ id ];
progress . counter = counter ;
progress . date = date ;
progress . changed = false ;
2011-01-28 15:34:53 +01:00
} while ( criteriaResult -> NextRow ());
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
void AchievementMgr :: SendAchievementEarned ( AchievementEntry const * achievement ) const
2008-12-24 09:58:26 -06:00
{
2010-04-07 19:14:10 +02:00
if ( GetPlayer () -> GetSession () -> PlayerLoading ())
2009-03-31 07:43:20 -06:00
return ;
2009-10-17 15:51:44 -07:00
2010-04-27 22:22:13 +02:00
// Don't send for achievements with ACHIEVEMENT_FLAG_TRACKING
2011-03-04 12:11:20 +01:00
if ( achievement -> flags & ACHIEVEMENT_FLAG_HIDDEN )
2010-04-27 22:22:13 +02:00
return ;
2009-05-04 13:13:07 -05:00
#ifdef TRINITY_DEBUG
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_ACHIEVEMENTSYS , "AchievementMgr::SendAchievementEarned(%u)" , achievement -> ID );
2009-03-09 17:41:50 -06:00
#endif
2009-10-17 15:51:44 -07:00
2011-05-04 10:08:09 +02:00
if ( Guild * guild = sGuildMgr -> GetGuildById ( GetPlayer () -> GetGuildId ()))
2008-12-24 09:58:26 -06:00
{
2011-04-29 20:47:02 +02:00
Trinity :: AchievementChatBuilder say_builder ( * GetPlayer (), CHAT_MSG_GUILD_ACHIEVEMENT , LANG_ACHIEVEMENT_EARNED , achievement -> ID );
2009-12-20 15:20:04 +01:00
Trinity :: LocalizedPacketDo < Trinity :: AchievementChatBuilder > say_do ( say_builder );
2011-04-29 20:47:02 +02:00
guild -> BroadcastWorker ( say_do , GetPlayer ());
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( achievement -> flags & ( ACHIEVEMENT_FLAG_REALM_FIRST_KILL | ACHIEVEMENT_FLAG_REALM_FIRST_REACH ))
2008-12-24 09:58:26 -06:00
{
// broadcast realm first reached
WorldPacket data ( SMSG_SERVER_FIRST_ACHIEVEMENT , strlen ( GetPlayer () -> GetName ()) + 1 + 8 + 4 + 4 );
data << GetPlayer () -> GetName ();
data << uint64 ( GetPlayer () -> GetGUID ());
data << uint32 ( achievement -> ID );
2009-02-21 17:02:56 -06:00
data << uint32 ( 0 ); // 1=link supplied string as player name, 0=display plain string
2010-12-23 23:25:44 +01:00
sWorld -> SendGlobalMessage ( & data );
2008-12-24 09:58:26 -06:00
}
2009-12-17 19:09:40 +01:00
// if player is in world he can tell his friends about new achievement
else if ( GetPlayer () -> IsInWorld ())
2008-12-24 09:58:26 -06:00
{
2009-12-20 15:20:04 +01:00
CellPair p = Trinity :: ComputeCellPair ( GetPlayer () -> GetPositionX (), GetPlayer () -> GetPositionY ());
2009-10-17 15:51:44 -07:00
2009-02-21 17:02:56 -06:00
Cell cell ( p );
cell . data . Part . reserved = ALL_DISTRICT ;
cell . SetNoCreate ();
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
Trinity :: AchievementChatBuilder say_builder ( * GetPlayer (), CHAT_MSG_ACHIEVEMENT , LANG_ACHIEVEMENT_EARNED , achievement -> ID );
2009-12-20 15:20:04 +01:00
Trinity :: LocalizedPacketDo < Trinity :: AchievementChatBuilder > say_do ( say_builder );
2011-03-04 12:11:20 +01:00
Trinity :: PlayerDistWorker < Trinity :: LocalizedPacketDo < Trinity :: AchievementChatBuilder > > say_worker ( GetPlayer (), sWorld -> getFloatConfig ( CONFIG_LISTEN_RANGE_SAY ), say_do );
2009-12-20 15:20:04 +01:00
TypeContainerVisitor < Trinity :: PlayerDistWorker < Trinity :: LocalizedPacketDo < Trinity :: AchievementChatBuilder > > , WorldTypeMapContainer > message ( say_worker );
2010-12-23 23:25:44 +01:00
cell . Visit ( p , message , * GetPlayer () -> GetMap (), * GetPlayer (), sWorld -> getFloatConfig ( CONFIG_LISTEN_RANGE_SAY ));
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
WorldPacket data ( SMSG_ACHIEVEMENT_EARNED , 8 + 4 + 8 );
data . append ( GetPlayer () -> GetPackGUID ());
data << uint32 ( achievement -> ID );
2009-12-24 10:20:15 +01:00
data << uint32 ( secsToTimeBitFields ( time ( NULL )));
2008-12-24 09:58:26 -06:00
data << uint32 ( 0 );
2010-12-23 23:25:44 +01:00
GetPlayer () -> SendMessageToSetInRange ( & data , sWorld -> getFloatConfig ( CONFIG_LISTEN_RANGE_SAY ), true );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
void AchievementMgr :: SendCriteriaUpdate ( AchievementCriteriaEntry const * entry , CriteriaProgress const * progress , uint32 timeElapsed , bool timedCompleted ) const
2008-12-24 09:58:26 -06:00
{
WorldPacket data ( SMSG_CRITERIA_UPDATE , 8 + 4 + 8 );
2010-04-27 22:22:13 +02:00
data << uint32 ( entry -> ID );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// the counter is packed like a packed Guid
data . appendPackGUID ( progress -> counter );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
data . append ( GetPlayer () -> GetPackGUID ());
2010-04-27 22:22:13 +02:00
if ( ! entry -> timeLimit )
data << uint32 ( 0 );
else
data << uint32 ( timedCompleted ? 0 : 1 ); // this are some flags, 1 is for keeping the counter at 0 in client
2008-12-24 09:58:26 -06:00
data << uint32 ( secsToTimeBitFields ( progress -> date ));
2010-04-27 22:22:13 +02:00
data << uint32 ( timeElapsed ); // time elapsed in seconds
data << uint32 ( 0 ); // unk
2009-03-24 17:43:16 -06:00
GetPlayer () -> SendDirectMessage ( & data );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
/**
* called at player login. The player might have fulfilled some achievements when the achievement system wasn't working yet
*/
void AchievementMgr :: CheckAllAchievementCriteria ()
{
// suppress sending packets
2009-10-17 16:20:24 -07:00
for ( uint32 i = 0 ; i < ACHIEVEMENT_CRITERIA_TYPE_TOTAL ; ++ i )
2008-12-24 09:58:26 -06:00
UpdateAchievementCriteria ( AchievementCriteriaTypes ( i ));
}
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
static const uint32 achievIdByArenaSlot [ MAX_ARENA_SLOT ] = { 1057 , 1107 , 1108 };
2011-03-26 05:33:46 +02:00
static const uint32 achievIdForDungeon [][ 4 ] =
2009-03-06 15:21:44 -06:00
{
2011-04-29 20:47:02 +02:00
// ach_cr_id, is_dungeon, is_raid, is_heroic_dungeon
2009-03-06 15:21:44 -06:00
{ 321 , true , true , true },
{ 916 , false , true , false },
{ 917 , false , true , false },
{ 918 , true , false , false },
{ 2219 , false , false , true },
{ 0 , false , false , false }
};
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
/**
* this function will be called whenever the user might have done a criteria relevant action
*/
2011-04-21 23:32:45 +02:00
void AchievementMgr :: UpdateAchievementCriteria ( AchievementCriteriaTypes type , uint32 miscValue1 /*= 0*/ , uint32 miscValue2 /*= 0*/ , Unit * unit /*= NULL*/ )
2008-12-24 09:58:26 -06:00
{
2011-04-21 23:32:45 +02:00
sLog -> outDebug ( LOG_FILTER_ACHIEVEMENTSYS , "AchievementMgr::UpdateAchievementCriteria(%u, %u, %u)" , type , miscValue1 , miscValue2 );
2009-10-17 15:51:44 -07:00
2011-07-02 02:14:49 +02:00
// disable for gamemasters with GM-mode enabled
2011-07-02 02:41:03 +02:00
if ( m_player -> isGameMaster ())
2009-01-25 16:35:14 -06:00
return ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
AchievementCriteriaEntryList const & achievementCriteriaList = sAchievementMgr -> GetAchievementCriteriaByType ( type );
2010-04-08 08:20:08 +02:00
for ( AchievementCriteriaEntryList :: const_iterator i = achievementCriteriaList . begin (); i != achievementCriteriaList . end (); ++ i )
2008-12-24 09:58:26 -06:00
{
AchievementCriteriaEntry const * achievementCriteria = ( * i );
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( achievementCriteria -> referredAchievement );
2009-04-03 16:36:20 -06:00
if ( ! achievement )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
if ( ! CanUpdateCriteria ( achievementCriteria , achievement ))
2009-04-03 16:36:20 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
switch ( type )
{
2009-03-05 09:22:43 -06:00
// std. case: increment at 1
2009-05-03 22:30:31 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS :
2009-05-05 14:50:06 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL :
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION :
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS : /* FIXME: for online player only currently */
2009-05-31 16:26:39 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED :
2009-05-05 14:49:15 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED :
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN :
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS :
2010-09-03 20:11:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS :
2009-03-05 09:22:43 -06:00
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-05 09:22:43 -06:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
2008-12-24 09:58:26 -06:00
break ;
2009-03-05 09:22:43 -06:00
// std case: increment at miscvalue1
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS :
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS :
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD :
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TRAVELLING :
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER :
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL :
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY :
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS : /* FIXME: for online player only currently */
2009-04-23 22:07:04 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_DAMAGE_RECEIVED :
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL_HEALING_RECEIVED :
2009-03-05 09:22:43 -06:00
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-05 09:22:43 -06:00
continue ;
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_ACCUMULATE );
2009-03-05 09:22:43 -06:00
break ;
// std case: high value at miscvalue1
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD : /* FIXME: for online player only currently */
2009-04-23 22:07:04 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_DEALT :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HIT_RECEIVED :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEAL_CASTED :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALING_RECEIVED :
2009-03-05 09:22:43 -06:00
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-05 09:22:43 -06:00
continue ;
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_HIGHEST );
2008-12-24 09:58:26 -06:00
break ;
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
// specialized cases
2011-04-30 12:41:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
if ( ! miscValue1 )
continue ;
2009-10-17 15:51:44 -07:00
2011-04-30 12:41:14 +02:00
if ( achievement -> categoryId == CATEGORY_CHILDRENS_WEEK )
{
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
if ( ! data || ! data -> Meets ( GetPlayer (), NULL ))
continue ;
}
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
2009-07-31 11:36:02 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-07-31 11:36:02 +08:00
continue ;
if ( achievementCriteria -> win_bg . bgMapID != GetPlayer () -> GetMapId ())
continue ;
2009-10-17 15:51:44 -07:00
2010-08-13 13:48:59 +02:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
2010-08-13 13:48:59 +02:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_ACCUMULATE );
2009-07-31 11:36:02 +08:00
break ;
}
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE :
2009-06-07 20:54:23 -05:00
{
2008-12-24 09:58:26 -06:00
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( achievementCriteria -> kill_creature . creatureID != miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-07 20:54:23 -05:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
2009-06-07 20:54:23 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue2 , PROGRESS_ACCUMULATE );
2009-03-05 09:22:43 -06:00
break ;
2009-06-07 20:54:23 -05:00
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL :
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> getLevel ());
2008-12-24 09:58:26 -06:00
break ;
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL :
2009-03-28 18:00:33 -06:00
// update at loading or specific skill update
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> reach_skill_level . skillID )
2009-03-28 18:00:33 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( uint32 skillvalue = GetPlayer () -> GetBaseSkillValue ( achievementCriteria -> reach_skill_level . skillID ))
2008-12-24 09:58:26 -06:00
SetCriteriaProgress ( achievementCriteria , skillvalue );
break ;
2009-03-28 17:58:21 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL :
2009-03-28 18:00:33 -06:00
// update at loading or specific skill update
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> learn_skill_level . skillID )
2009-03-28 18:00:33 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( uint32 maxSkillvalue = GetPlayer () -> GetPureMaxSkillValue ( achievementCriteria -> learn_skill_level . skillID ))
2009-03-28 17:58:21 -06:00
SetCriteriaProgress ( achievementCriteria , maxSkillvalue );
break ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT :
2010-04-07 19:14:10 +02:00
if ( m_completedAchievements . find ( achievementCriteria -> complete_achievement . linkedAchievement ) != m_completedAchievements . end ())
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 );
break ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT :
{
2011-07-08 10:54:46 +02:00
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetRewardedQuestCount ());
2008-12-24 09:58:26 -06:00
break ;
}
2010-06-14 18:33:46 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY :
{
2010-12-23 23:25:44 +01:00
time_t nextDailyResetTime = sWorld -> GetNextDailyQuestsResetTime ();
2010-06-14 18:33:46 +02:00
CriteriaProgress * progress = GetCriteriaProgress ( achievementCriteria );
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 ) // Login case.
2010-06-14 18:33:46 +02:00
{
// reset if player missed one day.
if ( progress && progress -> date < ( nextDailyResetTime - 2 * DAY ))
SetCriteriaProgress ( achievementCriteria , 0 , PROGRESS_SET );
continue ;
}
ProgressType progressType ;
2010-08-08 19:45:53 +02:00
if ( ! progress )
2010-06-14 18:33:46 +02:00
// 1st time. Start count.
progressType = PROGRESS_SET ;
else if ( progress -> date < ( nextDailyResetTime - 2 * DAY ))
// last progress is older than 2 days. Player missed 1 day => Retart count.
progressType = PROGRESS_SET ;
else if ( progress -> date < ( nextDailyResetTime - DAY ))
// last progress is between 1 and 2 days. => 1st time of the day.
progressType = PROGRESS_ACCUMULATE ;
else
// last progress is within the day before the reset => Already counted today.
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , progressType );
break ;
}
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE :
{
2009-04-11 23:13:00 -05:00
// speedup for non-login case
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> complete_quests_in_zone . zoneID )
2009-04-11 23:13:00 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-07-08 10:54:46 +02:00
uint32 counter = 0 ;
const RewardedQuestSet & rewQuests = GetPlayer () -> getRewardedQuests ();
for ( RewardedQuestSet :: const_iterator itr = rewQuests . begin (); itr != rewQuests . end (); ++ itr )
2008-12-24 09:58:26 -06:00
{
2010-12-26 04:16:18 +01:00
Quest const * quest = sObjectMgr -> GetQuestTemplate ( * itr );
if ( quest && quest -> GetZoneOrSort () >= 0 && uint32 ( quest -> GetZoneOrSort ()) == achievementCriteria -> complete_quests_in_zone . zoneID )
2011-07-08 10:54:46 +02:00
++ counter ;
2008-12-24 09:58:26 -06:00
}
SetCriteriaProgress ( achievementCriteria , counter );
break ;
}
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( GetPlayer () -> GetMapId () != achievementCriteria -> complete_battleground . mapID )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_ACCUMULATE );
2009-01-20 19:59:43 -06:00
break ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( GetPlayer () -> GetMapId () != achievementCriteria -> death_at_map . mapID )
2008-12-24 09:58:26 -06:00
continue ;
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
2008-12-24 09:58:26 -06:00
break ;
2009-03-06 15:21:44 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DEATH :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-06 15:21:44 -06:00
continue ;
2009-04-08 16:39:22 -05:00
// skip wrong arena achievements, if not achievIdByArenaSlot then normal total death counter
bool notfit = false ;
2009-10-17 16:20:24 -07:00
for ( int j = 0 ; j < MAX_ARENA_SLOT ; ++ j )
2009-04-08 16:39:22 -05:00
{
2010-04-07 19:14:10 +02:00
if ( achievIdByArenaSlot [ j ] == achievement -> ID )
2009-04-08 16:39:22 -05:00
{
2010-08-08 04:37:24 +02:00
Battleground * bg = GetPlayer () -> GetBattleground ();
2010-04-07 19:14:10 +02:00
if ( ! bg || ! bg -> isArena () || ArenaTeam :: GetSlotByType ( bg -> GetArenaType ()) != j )
2009-04-08 16:39:22 -05:00
notfit = true ;
2009-10-17 15:51:44 -07:00
2009-04-08 16:39:22 -05:00
break ;
}
}
2010-04-07 19:14:10 +02:00
if ( notfit )
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
Map const * map = GetPlayer () -> IsInWorld () ? GetPlayer () -> GetMap () : sMapMgr -> FindMap ( GetPlayer () -> GetMapId (), GetPlayer () -> GetInstanceId ());
2010-04-07 19:14:10 +02:00
if ( ! map || ! map -> IsDungeon ())
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
// search case
bool found = false ;
2011-03-26 05:33:46 +02:00
for ( int j = 0 ; achievIdForDungeon [ j ][ 0 ]; ++ j )
2009-03-06 15:21:44 -06:00
{
2011-03-26 05:33:46 +02:00
if ( achievIdForDungeon [ j ][ 0 ] == achievement -> ID )
2009-03-06 15:21:44 -06:00
{
2010-04-07 19:14:10 +02:00
if ( map -> IsRaid ())
2009-03-06 15:21:44 -06:00
{
// if raid accepted (ignore difficulty)
2011-03-26 05:33:46 +02:00
if ( ! achievIdForDungeon [ j ][ 2 ])
2009-03-06 15:21:44 -06:00
break ; // for
}
2010-04-07 23:25:02 +02:00
else if ( GetPlayer () -> GetDungeonDifficulty () == DUNGEON_DIFFICULTY_NORMAL )
2009-03-06 15:21:44 -06:00
{
// dungeon in normal mode accepted
2011-03-26 05:33:46 +02:00
if ( ! achievIdForDungeon [ j ][ 1 ])
2009-03-06 15:21:44 -06:00
break ; // for
}
else
{
// dungeon in heroic mode accepted
2011-03-26 05:33:46 +02:00
if ( ! achievIdForDungeon [ j ][ 3 ])
2009-03-06 15:21:44 -06:00
break ; // for
}
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
found = true ;
break ; // for
}
}
2010-04-07 19:14:10 +02:00
if ( ! found )
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
//FIXME: work only for instances where max == min for players
2010-04-07 19:14:10 +02:00
if ((( InstanceMap * ) map ) -> GetMaxPlayers () != achievementCriteria -> death_in_dungeon . manLimit )
2009-03-06 15:21:44 -06:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
}
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> killed_by_creature . creatureEntry )
2008-12-24 09:58:26 -06:00
continue ;
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
2008-12-24 09:58:26 -06:00
break ;
2009-03-06 15:21:44 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
// if team check required: must kill by opposition faction
2011-04-21 23:32:45 +02:00
if ( achievement -> ID == 318 && miscValue2 == GetPlayer () -> GetTeam ())
2009-03-06 15:21:44 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-06 15:21:44 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-14 10:00:45 -05:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
2009-06-14 10:00:45 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// miscvalue1 is the ingame fallheight*100 as stored in dbc
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 );
2008-12-24 09:58:26 -06:00
break ;
}
2009-03-06 15:21:44 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-06 15:21:44 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue2 != achievementCriteria -> death_from . type )
2009-03-06 15:21:44 -06:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST :
2009-06-14 10:00:45 -05:00
{
2009-04-18 20:49:56 -05:00
// if miscvalues != 0, it contains the questID.
2011-04-21 23:32:45 +02:00
if ( miscValue1 )
2009-04-18 20:49:56 -05:00
{
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> complete_quest . questID )
2009-06-14 10:00:45 -05:00
continue ;
2009-04-18 20:49:56 -05:00
}
else
{
// login case.
2010-04-07 19:14:10 +02:00
if ( ! GetPlayer () -> GetQuestRewardStatus ( achievementCriteria -> complete_quest . questID ))
2009-06-14 10:00:45 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-06-19 14:07:07 +02:00
if ( achievement -> ID == 1282 )
2009-06-14 10:00:45 -05:00
{
2011-06-19 14:07:07 +02:00
// those requirements couldn't be found in the dbc
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
continue ;
break ;
2009-04-18 20:49:56 -05:00
}
2009-06-14 10:00:45 -05:00
SetCriteriaProgress ( achievementCriteria , 1 );
2008-12-24 09:58:26 -06:00
break ;
2009-06-14 10:00:45 -05:00
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET :
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 :
2010-01-16 19:41:04 +03:00
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> be_spell_target . spellID )
2008-12-24 09:58:26 -06:00
continue ;
2010-01-16 19:41:04 +03:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2010-04-07 19:14:10 +02:00
if ( ! data )
2010-01-16 19:41:04 +03:00
continue ;
2011-04-29 20:47:02 +02:00
if ( ! data -> Meets ( GetPlayer (), unit ))
2010-01-16 19:41:04 +03:00
continue ;
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2010-01-16 19:41:04 +03:00
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL :
2009-09-11 13:20:38 -07:00
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 :
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> cast_spell . spellID )
2008-12-24 09:58:26 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-09-11 13:20:38 -07:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2010-04-07 19:14:10 +02:00
if ( ! data )
2009-09-11 13:20:38 -07:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
if ( ! data -> Meets ( GetPlayer (), unit ))
2009-09-11 13:20:38 -07:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-09-11 13:20:38 -07:00
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL :
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> learn_spell . spellID )
2009-03-17 14:55:16 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( GetPlayer () -> HasSpell ( achievementCriteria -> learn_spell . spellID ))
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 );
2008-12-24 09:58:26 -06:00
break ;
2009-04-29 18:42:53 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE :
{
2011-03-26 05:33:46 +02:00
// miscvalue1=loot_type (note: 0 = LOOT_CORPSE and then it ignored)
2009-04-29 18:42:53 -05:00
// miscvalue2=count of item loot
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || ! miscValue2 )
2009-04-29 18:42:53 -05:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> loot_type . lootType )
2009-04-29 18:42:53 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-29 18:42:53 -05:00
// zone specific
2010-04-07 23:25:02 +02:00
if ( achievementCriteria -> loot_type . lootTypeCount == 1 )
2009-04-29 18:42:53 -05:00
{
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
2009-04-29 18:42:53 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue2 , PROGRESS_ACCUMULATE );
2009-04-29 18:42:53 -05:00
break ;
}
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM :
// speedup for non-login case
2011-04-21 23:32:45 +02:00
if ( miscValue1 && achievementCriteria -> own_item . itemID != miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetItemCount ( achievementCriteria -> own_item . itemID , true ));
break ;
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA :
// miscvalue1 contains the personal rating
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 ) // no update at login
2009-06-01 21:51:34 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-01 21:51:34 -05:00
// additional requirements
2011-03-26 05:33:46 +02:00
if ( achievementCriteria -> additionalRequirements [ 0 ]. additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE )
2009-06-01 21:51:34 -05:00
{
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit , miscValue1 ))
2009-06-01 21:51:34 -05:00
{
// reset the progress as we have a win without the requirement.
SetCriteriaProgress ( achievementCriteria , 0 );
continue ;
}
}
2009-10-17 15:51:44 -07:00
2009-06-01 21:51:34 -05:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-30 12:41:14 +02:00
2011-04-21 23:32:45 +02:00
if ( achievementCriteria -> use_item . itemID != miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-30 12:41:14 +02:00
// Children's Week achievements have extra requirements
if ( achievement -> categoryId == CATEGORY_CHILDRENS_WEEK )
{
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
if ( ! data || ! data -> Meets ( GetPlayer (), NULL ))
continue ;
}
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
2008-12-24 09:58:26 -06:00
break ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM :
// You _have_ to loot that item, just owning it when logging in does _not_ count!
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> own_item . itemID )
2008-12-24 09:58:26 -06:00
continue ;
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue2 , PROGRESS_ACCUMULATE );
2008-12-24 09:58:26 -06:00
break ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA :
2008-12-24 09:58:26 -06:00
{
2009-03-05 09:22:43 -06:00
WorldMapOverlayEntry const * worldOverlayEntry = sWorldMapOverlayStore . LookupEntry ( achievementCriteria -> explore_area . areaReference );
2010-04-07 19:14:10 +02:00
if ( ! worldOverlayEntry )
2009-03-05 09:22:43 -06:00
break ;
2009-10-17 15:51:44 -07:00
2009-03-26 14:02:11 -06:00
bool matchFound = false ;
2009-04-27 18:45:41 -05:00
for ( int j = 0 ; j < MAX_WORLD_MAP_OVERLAY_AREA_IDX ; ++ j )
2009-03-26 14:02:11 -06:00
{
2009-04-27 18:45:41 -05:00
uint32 area_id = worldOverlayEntry -> areatableID [ j ];
2010-04-07 19:14:10 +02:00
if ( ! area_id ) // array have 0 only in empty tail
2009-03-26 14:02:11 -06:00
break ;
2009-10-17 15:51:44 -07:00
2009-04-27 18:45:41 -05:00
int32 exploreFlag = GetAreaFlagByAreaID ( area_id );
2010-04-07 19:14:10 +02:00
if ( exploreFlag < 0 )
2009-04-27 18:45:41 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-26 14:02:11 -06:00
uint32 playerIndexOffset = uint32 ( exploreFlag ) / 32 ;
uint32 mask = 1 << ( uint32 ( exploreFlag ) % 32 );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( GetPlayer () -> GetUInt32Value ( PLAYER_EXPLORED_ZONES_1 + playerIndexOffset ) & mask )
2009-03-26 14:02:11 -06:00
{
matchFound = true ;
break ;
}
}
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( matchFound )
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 );
2008-12-24 09:58:26 -06:00
break ;
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT :
2009-05-24 11:17:03 -05:00
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetBankBagSlotCount ());
2008-12-24 09:58:26 -06:00
break ;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION :
{
2009-03-17 14:55:16 -06:00
// skip faction check only at loading
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> gain_reputation . factionID )
2009-03-17 14:55:16 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-26 13:53:32 -06:00
int32 reputation = GetPlayer () -> GetReputationMgr (). GetReputation ( achievementCriteria -> gain_reputation . factionID );
2008-12-24 09:58:26 -06:00
if ( reputation > 0 )
SetCriteriaProgress ( achievementCriteria , reputation );
break ;
}
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION :
{
2009-03-26 14:03:55 -06:00
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetReputationMgr (). GetExaltedFactionCount ());
2008-12-24 09:58:26 -06:00
break ;
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP :
2008-12-24 09:58:26 -06:00
{
2009-03-05 09:22:43 -06:00
// skip for login case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-05 09:22:43 -06:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 );
break ;
}
2010-01-24 16:26:33 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM :
{
// miscvalue1 = itemid
// miscvalue2 = itemSlot
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2010-01-24 16:26:33 +01:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue2 != achievementCriteria -> equip_epic_item . itemSlot )
2010-01-24 16:26:33 +01:00
continue ;
2010-03-22 18:32:38 +01:00
// check item level and quality via achievement_criteria_data
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-21 23:32:45 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), 0 , miscValue1 ))
2010-01-24 16:26:33 +01:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 );
break ;
}
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT :
{
// miscvalue1 = itemid
// miscvalue2 = diced value
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-05 09:22:43 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue2 != achievementCriteria -> roll_greed_on_loot . rollValue )
2009-03-05 09:22:43 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-28 22:42:33 +02:00
ItemTemplate const * pProto = sObjectMgr -> GetItemTemplate ( miscValue1 );
2010-01-24 16:26:33 +01:00
if ( ! pProto )
continue ;
2009-10-17 15:51:44 -07:00
2010-01-24 16:26:33 +01:00
// check item level via achievement_criteria_data
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2010-01-24 16:26:33 +01:00
if ( ! data || ! data -> Meets ( GetPlayer (), 0 , pProto -> ItemLevel ))
2009-03-05 09:22:43 -06:00
continue ;
2010-01-24 16:26:33 +01:00
2009-03-05 09:22:43 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
2009-03-06 18:14:05 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE :
{
// miscvalue1 = emote
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-06 18:14:05 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> do_emote . emoteID )
2009-03-06 18:14:05 -06:00
continue ;
2010-04-07 19:14:10 +02:00
if ( achievementCriteria -> do_emote . count )
2009-03-06 18:14:05 -06:00
{
2009-04-08 16:34:38 -05:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2011-04-29 20:47:02 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
2009-03-06 18:14:05 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-03-06 18:14:05 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
2009-04-23 22:07:37 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE :
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE :
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-04-23 22:07:37 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-21 21:14:49 +02:00
if ( achievementCriteria -> additionalRequirements [ 0 ]. additionalRequirement_type == ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP )
2009-04-23 22:07:37 -05:00
{
2011-03-26 05:33:46 +02:00
if ( GetPlayer () -> GetMapId () != achievementCriteria -> additionalRequirements [ 0 ]. additionalRequirement_value )
2009-04-23 22:07:37 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-23 22:07:37 -05:00
// map specific case (BG in fact) expected player targeted damage/heal
2010-04-07 19:14:10 +02:00
if ( ! unit || unit -> GetTypeId () != TYPEID_PLAYER )
2009-04-23 22:07:37 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_ACCUMULATE );
2009-04-23 22:07:37 -05:00
break ;
}
2009-03-17 14:54:32 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM :
// miscvalue1 = item_id
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-03-17 14:54:32 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> equip_item . itemID )
2009-03-17 14:54:32 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-05-31 16:27:16 -05:00
SetCriteriaProgress ( achievementCriteria , 1 );
2009-04-03 16:37:06 -06:00
break ;
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT :
// miscvalue1 = go entry
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-04-03 16:37:06 -06:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> use_gameobject . goEntry )
2009-04-03 16:37:06 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-17 15:22:27 -05:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT :
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-04-17 15:22:27 -05:00
continue ;
2011-04-21 23:32:45 +02:00
if ( miscValue1 != achievementCriteria -> fish_in_gameobject . goEntry )
2009-04-17 15:22:27 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-17 14:54:32 -06:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS :
2009-03-17 14:54:32 -06:00
{
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> learn_skillline_spell . skillLine )
2009-03-17 14:55:16 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-03-17 14:54:32 -06:00
uint32 spellCount = 0 ;
for ( PlayerSpellMap :: const_iterator spellIter = GetPlayer () -> GetSpellMap (). begin ();
spellIter != GetPlayer () -> GetSpellMap (). end ();
++ spellIter )
2009-03-05 09:22:43 -06:00
{
2010-12-22 21:25:23 +01:00
SkillLineAbilityMapBounds bounds = sSpellMgr -> GetSkillLineAbilityMapBounds ( spellIter -> first );
2009-10-17 16:20:24 -07:00
for ( SkillLineAbilityMap :: const_iterator skillIter = bounds . first ; skillIter != bounds . second ; ++ skillIter )
2009-03-05 09:22:43 -06:00
{
2010-04-07 19:14:10 +02:00
if ( skillIter -> second -> skillId == achievementCriteria -> learn_skillline_spell . skillLine )
2009-03-17 14:54:32 -06:00
spellCount ++ ;
2009-03-05 09:22:43 -06:00
}
}
2009-03-17 14:54:32 -06:00
SetCriteriaProgress ( achievementCriteria , spellCount );
break ;
}
2009-08-02 10:12:40 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL :
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2009-08-02 10:12:40 +08:00
continue ;
2009-10-17 15:51:44 -07:00
2009-08-27 20:27:55 -05:00
if ( achievementCriteria -> win_duel . duelCount )
2009-08-02 10:12:40 +08:00
{
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2009-08-27 20:27:55 -05:00
if ( ! data )
2009-08-02 10:12:40 +08:00
continue ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
if ( ! data -> Meets ( GetPlayer (), unit ))
2009-08-02 10:12:40 +08:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-08-02 10:12:40 +08:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-03-26 14:03:55 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION :
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetReputationMgr (). GetReveredFactionCount ());
break ;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION :
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetReputationMgr (). GetHonoredFactionCount ());
break ;
case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS :
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetReputationMgr (). GetVisibleFactionCount ());
break ;
2010-03-22 18:32:38 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM :
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM :
{
// AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2010-03-22 18:32:38 +01:00
continue ;
2011-04-28 22:42:33 +02:00
ItemTemplate const * proto = sObjectMgr -> GetItemTemplate ( miscValue1 );
2010-03-22 18:32:38 +01:00
if ( ! proto || proto -> Quality < ITEM_QUALITY_EPIC )
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
2009-04-20 20:33:43 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE :
{
2011-04-21 23:32:45 +02:00
if ( miscValue1 && miscValue1 != achievementCriteria -> learn_skill_line . skillLine )
2009-04-20 20:33:43 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-20 20:33:43 -05:00
uint32 spellCount = 0 ;
for ( PlayerSpellMap :: const_iterator spellIter = GetPlayer () -> GetSpellMap (). begin ();
spellIter != GetPlayer () -> GetSpellMap (). end ();
++ spellIter )
{
2010-12-22 21:25:23 +01:00
SkillLineAbilityMapBounds bounds = sSpellMgr -> GetSkillLineAbilityMapBounds ( spellIter -> first );
2009-10-17 16:20:24 -07:00
for ( SkillLineAbilityMap :: const_iterator skillIter = bounds . first ; skillIter != bounds . second ; ++ skillIter )
2009-08-27 20:27:55 -05:00
if ( skillIter -> second -> skillId == achievementCriteria -> learn_skill_line . skillLine )
2009-04-20 20:33:43 -05:00
spellCount ++ ;
}
SetCriteriaProgress ( achievementCriteria , spellCount );
break ;
}
2009-04-22 18:03:07 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL :
2009-09-04 19:50:00 -04:00
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetUInt32Value ( PLAYER_FIELD_LIFETIME_HONORABLE_KILLS ));
2009-04-22 18:03:07 -05:00
break ;
2009-05-06 16:38:36 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS :
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> hk_class . classID )
2009-05-06 16:38:36 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-05-06 16:38:36 -05:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE :
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> hk_race . raceID )
2009-05-06 16:38:36 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-05-06 16:38:36 -05:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2009-05-05 14:48:48 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED :
SetCriteriaProgress ( achievementCriteria , GetPlayer () -> GetMoney (), PROGRESS_HIGHEST );
break ;
2010-08-06 14:56:41 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS :
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2010-08-06 14:56:41 +02:00
{
uint32 points = 0 ;
for ( CompletedAchievementMap :: iterator itr = m_completedAchievements . begin (); itr != m_completedAchievements . end (); ++ itr )
if ( AchievementEntry const * pAchievement = sAchievementStore . LookupEntry ( itr -> first ))
points += pAchievement -> points ;
SetCriteriaProgress ( achievementCriteria , points , PROGRESS_SET );
}
else
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_ACCUMULATE );
2010-08-06 14:56:41 +02:00
break ;
}
2010-08-07 18:31:06 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE :
2010-08-13 13:48:59 +02:00
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> bg_objective . objectiveId )
2010-08-07 18:31:06 +02:00
continue ;
2010-08-13 13:48:59 +02:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2010-08-13 13:48:59 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
continue ;
2010-08-07 18:31:06 +02:00
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
2010-08-13 13:48:59 +02:00
}
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL :
2010-08-13 13:48:59 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL :
2011-05-14 12:26:49 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS :
2010-08-13 13:48:59 +02:00
{
2010-12-17 18:12:46 +01:00
// skip login update
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 )
2010-12-17 18:12:46 +01:00
continue ;
2011-05-14 12:26:49 +02:00
2010-08-13 13:48:59 +02:00
// those requirements couldn't be found in the dbc
2010-12-22 21:25:23 +01:00
AchievementCriteriaDataSet const * data = sAchievementMgr -> GetCriteriaDataSet ( achievementCriteria );
2010-08-13 13:48:59 +02:00
if ( ! data || ! data -> Meets ( GetPlayer (), unit ))
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA :
{
2011-04-21 23:32:45 +02:00
if ( ! miscValue1 || miscValue1 != achievementCriteria -> honorable_kill_at_area . areaID )
2010-12-17 18:12:46 +01:00
continue ;
SetCriteriaProgress ( achievementCriteria , 1 , PROGRESS_ACCUMULATE );
break ;
}
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING :
{
2011-05-25 23:39:17 +02:00
uint32 reqTeamType = achievementCriteria -> highest_team_rating . teamtype ;
2010-12-17 18:12:46 +01:00
2011-04-21 23:32:45 +02:00
if ( miscValue1 )
2010-12-17 18:12:46 +01:00
{
2011-04-21 23:32:45 +02:00
if ( miscValue2 != reqTeamType )
2010-12-17 18:12:46 +01:00
continue ;
2011-04-21 23:32:45 +02:00
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_HIGHEST );
2010-12-17 18:12:46 +01:00
}
else // login case
{
for ( uint32 arena_slot = 0 ; arena_slot < MAX_ARENA_SLOT ; ++ arena_slot )
2011-05-25 23:39:17 +02:00
{
uint32 teamId = GetPlayer () -> GetArenaTeamId ( arena_slot );
if ( ! teamId )
continue ;
ArenaTeam * team = sArenaTeamMgr -> GetArenaTeamById ( teamId );
if ( ! team || team -> GetType () != reqTeamType )
continue ;
SetCriteriaProgress ( achievementCriteria , team -> GetStats (). Rating , PROGRESS_HIGHEST );
break ;
}
}
break ;
}
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING :
{
uint32 reqTeamType = achievementCriteria -> highest_personal_rating . teamtype ;
if ( miscValue1 )
{
if ( miscValue2 != reqTeamType )
continue ;
SetCriteriaProgress ( achievementCriteria , miscValue1 , PROGRESS_HIGHEST );
}
else // login case
{
for ( uint32 arena_slot = 0 ; arena_slot < MAX_ARENA_SLOT ; ++ arena_slot )
{
uint32 teamId = GetPlayer () -> GetArenaTeamId ( arena_slot );
if ( ! teamId )
continue ;
ArenaTeam * team = sArenaTeamMgr -> GetArenaTeamById ( teamId );
if ( ! team || team -> GetType () != reqTeamType )
continue ;
if ( ArenaTeamMember const * member = team -> GetMember ( GetPlayer () -> GetGUID ()))
{
SetCriteriaProgress ( achievementCriteria , member -> PersonalRating , PROGRESS_HIGHEST );
break ;
}
}
2010-12-17 18:12:46 +01:00
}
break ;
}
2009-03-05 09:22:43 -06:00
// std case: not exist in DBC, not triggered in code as result
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_POWER :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_STAT :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_RATING :
break ;
// FIXME: not triggered in code as result, need to implement
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_RAID :
case ACHIEVEMENT_CRITERIA_TYPE_WIN_ARENA :
case ACHIEVEMENT_CRITERIA_TYPE_PLAY_ARENA :
case ACHIEVEMENT_CRITERIA_TYPE_OWN_RANK :
case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE :
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE :
case ACHIEVEMENT_CRITERIA_TYPE_TOTAL :
break ; // Not implemented yet :(
2008-12-24 09:58:26 -06:00
}
2010-09-03 20:11:14 +02:00
2011-03-04 12:11:20 +01:00
if ( IsCompletedCriteria ( achievementCriteria , achievement ))
2009-04-29 00:31:03 -05:00
CompletedCriteriaFor ( achievement );
2009-10-17 15:51:44 -07:00
2009-07-30 10:19:03 +08:00
// check again the completeness for SUMM and REQ COUNT achievements,
2009-04-11 23:13:00 -05:00
// as they don't depend on the completed criteria but on the sum of the progress of each individual criteria
if ( achievement -> flags & ACHIEVEMENT_FLAG_SUMM )
if ( IsCompletedAchievement ( achievement ))
CompletedAchievement ( achievement );
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
if ( AchievementEntryList const * achRefList = sAchievementMgr -> GetAchievementByReferencedId ( achievement -> ID ))
2009-10-17 16:20:24 -07:00
for ( AchievementEntryList :: const_iterator itr = achRefList -> begin (); itr != achRefList -> end (); ++ itr )
2010-04-07 19:14:10 +02:00
if ( IsCompletedAchievement ( * itr ))
2009-04-03 16:36:20 -06:00
CompletedAchievement ( * itr );
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2009-02-27 12:55:14 -06:00
static const uint32 achievIdByClass [ MAX_CLASSES ] = { 0 , 459 , 465 , 462 , 458 , 464 , 461 , 467 , 460 , 463 , 0 , 466 };
static const uint32 achievIdByRace [ MAX_RACES ] = { 0 , 1408 , 1410 , 1407 , 1409 , 1413 , 1411 , 1404 , 1412 , 0 , 1405 , 1406 };
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
bool AchievementMgr :: IsCompletedCriteria ( AchievementCriteriaEntry const * achievementCriteria , AchievementEntry const * achievement )
2008-12-24 09:58:26 -06:00
{
// counter can never complete
2010-04-07 19:14:10 +02:00
if ( achievement -> flags & ACHIEVEMENT_FLAG_COUNTER )
2008-12-24 09:58:26 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( achievement -> flags & ( ACHIEVEMENT_FLAG_REALM_FIRST_REACH | ACHIEVEMENT_FLAG_REALM_FIRST_KILL ))
2008-12-24 09:58:26 -06:00
{
// someone on this realm has already completed that achievement
2010-12-22 21:25:23 +01:00
if ( sAchievementMgr -> IsRealmCompleted ( achievement ))
2008-12-24 09:58:26 -06:00
return false ;
}
2009-10-17 15:51:44 -07:00
2010-06-14 18:33:46 +02:00
CriteriaProgress const * progress = GetCriteriaProgress ( achievementCriteria );
if ( ! progress )
2008-12-24 09:58:26 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2010-12-17 18:12:46 +01:00
switch ( achievementCriteria -> requiredType )
2008-12-24 09:58:26 -06:00
{
2009-07-31 11:36:02 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG :
return progress -> counter >= achievementCriteria -> win_bg . winCount ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE :
return progress -> counter >= achievementCriteria -> kill_creature . creatureCount ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_REACH_LEVEL :
2009-02-27 12:55:14 -06:00
{
2009-03-05 09:22:43 -06:00
// skip wrong class achievements
2009-10-17 16:20:24 -07:00
for ( int i = 1 ; i < MAX_CLASSES ; ++ i )
2010-04-07 19:14:10 +02:00
if ( achievIdByClass [ i ] == achievement -> ID && i != GetPlayer () -> getClass ())
2009-03-05 09:22:43 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
// skip wrong race achievements
2009-10-17 16:20:24 -07:00
for ( int i = 1 ; i < MAX_RACES ; ++ i )
2010-04-07 19:14:10 +02:00
if ( achievIdByRace [ i ] == achievement -> ID && i != GetPlayer () -> getRace ())
2009-03-05 09:22:43 -06:00
return false ;
2009-10-17 15:51:44 -07:00
2009-03-05 09:22:43 -06:00
// appropriate class/race or not class/race specific
return progress -> counter >= achievementCriteria -> reach_level . level ;
2009-02-27 12:55:14 -06:00
}
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_REACH_SKILL_LEVEL :
return progress -> counter >= achievementCriteria -> reach_skill_level . skillLevel ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT :
return progress -> counter >= 1 ;
2009-01-02 11:03:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST_COUNT :
return progress -> counter >= achievementCriteria -> complete_quest_count . totalQuestCount ;
2010-06-14 18:33:46 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST_DAILY :
return progress -> counter >= achievementCriteria -> complete_daily_quest_daily . numberOfDays ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUESTS_IN_ZONE :
return progress -> counter >= achievementCriteria -> complete_quests_in_zone . questCount ;
2009-05-06 16:38:58 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_DAMAGE_DONE :
case ACHIEVEMENT_CRITERIA_TYPE_HEALING_DONE :
return progress -> counter >= achievementCriteria -> healing_done . count ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST :
return progress -> counter >= achievementCriteria -> complete_daily_quest . questCount ;
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING :
return progress -> counter >= achievementCriteria -> fall_without_dying . fallHeight ;
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST :
return progress -> counter >= 1 ;
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET :
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 :
return progress -> counter >= achievementCriteria -> be_spell_target . spellCount ;
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL :
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 :
return progress -> counter >= achievementCriteria -> cast_spell . castCount ;
2010-08-07 18:31:06 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE :
return progress -> counter >= achievementCriteria -> bg_objective . completeCount ;
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL_AT_AREA :
return progress -> counter >= achievementCriteria -> honorable_kill_at_area . killCount ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SPELL :
return progress -> counter >= 1 ;
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL :
case ACHIEVEMENT_CRITERIA_TYPE_EARN_HONORABLE_KILL :
return progress -> counter >= achievementCriteria -> honorable_kill . killCount ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_OWN_ITEM :
return progress -> counter >= achievementCriteria -> own_item . itemCount ;
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA :
return progress -> counter >= achievementCriteria -> win_rated_arena . count ;
2011-05-25 23:39:17 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_PERSONAL_RATING :
return progress -> counter >= achievementCriteria -> highest_personal_rating . PersonalRating ;
2009-05-06 16:38:58 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LEVEL :
return progress -> counter >= ( achievementCriteria -> learn_skill_level . skillLevel * 75 );
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM :
return progress -> counter >= achievementCriteria -> use_item . itemCount ;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_ITEM :
return progress -> counter >= achievementCriteria -> loot_item . itemCount ;
case ACHIEVEMENT_CRITERIA_TYPE_EXPLORE_AREA :
return progress -> counter >= 1 ;
case ACHIEVEMENT_CRITERIA_TYPE_BUY_BANK_SLOT :
return progress -> counter >= achievementCriteria -> buy_bank_slot . numberOfSlots ;
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REPUTATION :
return progress -> counter >= achievementCriteria -> gain_reputation . reputationAmount ;
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_EXALTED_REPUTATION :
return progress -> counter >= achievementCriteria -> gain_exalted_reputation . numberOfExaltedFactions ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_VISIT_BARBER_SHOP :
return progress -> counter >= achievementCriteria -> visit_barber . numberOfVisits ;
2010-01-24 16:26:33 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM :
2010-03-22 18:32:38 +01:00
return progress -> counter >= achievementCriteria -> equip_epic_item . count ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT :
return progress -> counter >= achievementCriteria -> roll_greed_on_loot . count ;
2009-05-06 16:38:58 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_HK_CLASS :
return progress -> counter >= achievementCriteria -> hk_class . count ;
case ACHIEVEMENT_CRITERIA_TYPE_HK_RACE :
return progress -> counter >= achievementCriteria -> hk_race . count ;
2009-03-06 18:14:05 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE :
return progress -> counter >= achievementCriteria -> do_emote . count ;
2009-03-17 14:54:32 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_ITEM :
return progress -> counter >= achievementCriteria -> equip_item . count ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD :
return progress -> counter >= achievementCriteria -> quest_reward_money . goldInCopper ;
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_MONEY :
return progress -> counter >= achievementCriteria -> loot_money . goldInCopper ;
2009-04-03 16:37:06 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_USE_GAMEOBJECT :
return progress -> counter >= achievementCriteria -> use_gameobject . useCount ;
2010-08-13 13:48:59 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL :
return progress -> counter >= achievementCriteria -> special_pvp_kill . killCount ;
2009-04-18 20:49:56 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_FISH_IN_GAMEOBJECT :
return progress -> counter >= achievementCriteria -> fish_in_gameobject . lootCount ;
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILLLINE_SPELLS :
2009-04-20 20:33:43 -05:00
return progress -> counter >= achievementCriteria -> learn_skillline_spell . spellCount ;
2009-05-05 14:50:06 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL :
return progress -> counter >= achievementCriteria -> win_duel . duelCount ;
2009-05-06 16:38:58 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE :
return progress -> counter >= achievementCriteria -> loot_type . lootTypeCount ;
2009-04-20 20:33:43 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LEARN_SKILL_LINE :
return progress -> counter >= achievementCriteria -> learn_skill_line . spellCount ;
2010-08-06 14:56:41 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS :
return progress -> counter >= 9000 ;
2010-09-03 20:11:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS :
return progress -> counter >= achievementCriteria -> use_lfg . dungeonsComplete ;
2011-05-14 12:26:49 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS :
return progress -> counter >= achievementCriteria -> get_killing_blow . killCount ;
2008-12-24 09:58:26 -06:00
// handle all statistic-only criteria here
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND :
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP :
2009-03-06 15:21:44 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DEATH :
case ACHIEVEMENT_CRITERIA_TYPE_DEATH_IN_DUNGEON :
2008-12-24 09:58:26 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_CREATURE :
case ACHIEVEMENT_CRITERIA_TYPE_KILLED_BY_PLAYER :
2009-03-06 15:21:44 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_DEATHS_FROM :
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_TEAM_RATING :
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_VENDORS :
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_TALENTS :
2009-05-05 14:49:15 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_NUMBER_OF_TALENT_RESETS :
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_AT_BARBER :
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_SPENT_FOR_MAIL :
2009-05-05 14:50:06 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOSE_DUEL :
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_GOLD_EARNED_BY_AUCTIONS :
case ACHIEVEMENT_CRITERIA_TYPE_CREATE_AUCTION :
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_BID :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_AUCTION_SOLD :
2009-05-05 14:48:48 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_GOLD_VALUE_OWNED :
2010-05-21 16:49:19 -03:00
case ACHIEVEMENT_CRITERIA_TYPE_WON_AUCTIONS :
2009-03-26 14:03:55 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_REVERED_REPUTATION :
case ACHIEVEMENT_CRITERIA_TYPE_GAIN_HONORED_REPUTATION :
case ACHIEVEMENT_CRITERIA_TYPE_KNOWN_FACTIONS :
2010-03-22 18:32:38 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_EPIC_ITEM :
case ACHIEVEMENT_CRITERIA_TYPE_RECEIVE_EPIC_ITEM :
2009-05-31 16:26:39 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED :
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED :
2009-03-05 09:22:43 -06:00
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_HEALTH :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_SPELLPOWER :
case ACHIEVEMENT_CRITERIA_TYPE_HIGHEST_ARMOR :
2009-05-05 14:49:15 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED :
case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN :
case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS :
2010-12-17 18:12:46 +01:00
default :
break ;
2008-12-24 09:58:26 -06:00
}
return false ;
}
2009-10-17 15:51:44 -07:00
2009-04-29 00:31:03 -05:00
void AchievementMgr :: CompletedCriteriaFor ( AchievementEntry const * achievement )
2008-12-24 09:58:26 -06:00
{
// counter can never complete
2010-04-07 19:14:10 +02:00
if ( achievement -> flags & ACHIEVEMENT_FLAG_COUNTER )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
// already completed and stored
2010-03-15 04:37:28 +01:00
if ( HasAchieved ( achievement ))
2009-04-03 16:36:20 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-04-05 17:05:15 -05:00
if ( IsCompletedAchievement ( achievement ))
2008-12-24 09:58:26 -06:00
CompletedAchievement ( achievement );
}
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
bool AchievementMgr :: IsCompletedAchievement ( AchievementEntry const * entry )
2008-12-24 09:58:26 -06:00
{
2009-04-11 23:13:00 -05:00
// counter can never complete
2010-04-07 19:14:10 +02:00
if ( entry -> flags & ACHIEVEMENT_FLAG_COUNTER )
2009-04-11 23:13:00 -05:00
return false ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
// for achievement with referenced achievement criterias get from referenced and counter from self
uint32 achievmentForTestId = entry -> refAchievement ? entry -> refAchievement : entry -> ID ;
uint32 achievmentForTestCount = entry -> count ;
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
AchievementCriteriaEntryList const * cList = sAchievementMgr -> GetAchievementCriteriaByAchievement ( achievmentForTestId );
2010-04-07 19:14:10 +02:00
if ( ! cList )
2009-04-03 16:36:20 -06:00
return false ;
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-04-11 23:13:00 -05:00
// For SUMM achievements, we have to count the progress of each criteria of the achievement.
// Oddly, the target count is NOT countained in the achievement, but in each individual criteria
if ( entry -> flags & ACHIEVEMENT_FLAG_SUMM )
{
2009-10-17 16:20:24 -07:00
for ( AchievementCriteriaEntryList :: const_iterator itr = cList -> begin (); itr != cList -> end (); ++ itr )
2009-04-11 23:13:00 -05:00
{
AchievementCriteriaEntry const * criteria = * itr ;
2009-10-17 15:51:44 -07:00
2010-06-14 18:33:46 +02:00
CriteriaProgress const * progress = GetCriteriaProgress ( criteria );
if ( ! progress )
2009-04-11 23:13:00 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-11 23:13:00 -05:00
count += progress -> counter ;
2009-10-17 15:51:44 -07:00
2009-04-11 23:13:00 -05:00
// for counters, field4 contains the main count requirement
if ( count >= criteria -> raw . count )
return true ;
}
return false ;
}
2009-10-17 15:51:44 -07:00
2009-07-30 10:19:03 +08:00
// Default case - need complete all or
2009-04-11 23:13:00 -05:00
bool completed_all = true ;
2009-10-17 16:20:24 -07:00
for ( AchievementCriteriaEntryList :: const_iterator itr = cList -> begin (); itr != cList -> end (); ++ itr )
2008-12-24 09:58:26 -06:00
{
2009-04-03 16:36:20 -06:00
AchievementCriteriaEntry const * criteria = * itr ;
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
bool completed = IsCompletedCriteria ( criteria , entry );
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
// found an uncompleted criteria, but DONT return false yet - there might be a completed criteria with ACHIEVEMENT_CRITERIA_COMPLETE_FLAG_ALL
2010-04-07 19:14:10 +02:00
if ( completed )
2009-04-03 16:36:20 -06:00
++ count ;
else
completed_all = false ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
// completed as have req. count of completed criterias
2010-04-07 19:14:10 +02:00
if ( achievmentForTestCount > 0 && achievmentForTestCount <= count )
2009-04-03 16:36:20 -06:00
return true ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
// all criterias completed requirement
2010-04-07 23:25:02 +02:00
if ( completed_all && achievmentForTestCount == 0 )
2009-04-03 16:36:20 -06:00
return true ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
return false ;
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2010-06-14 18:33:46 +02:00
CriteriaProgress * AchievementMgr :: GetCriteriaProgress ( AchievementCriteriaEntry const * entry )
{
CriteriaProgressMap :: iterator iter = m_criteriaProgress . find ( entry -> ID );
if ( iter == m_criteriaProgress . end ())
return NULL ;
return & ( iter -> second );
}
2009-03-05 09:22:43 -06:00
void AchievementMgr :: SetCriteriaProgress ( AchievementCriteriaEntry const * entry , uint32 changeValue , ProgressType ptype )
2008-12-24 09:58:26 -06:00
{
2010-04-27 22:22:13 +02:00
// Don't allow to cheat - doing timed achievements without timer active
TimedAchievementMap :: iterator timedIter = m_timedAchievements . find ( entry -> ID );
if ( entry -> timeLimit && timedIter == m_timedAchievements . end ())
return ;
2011-02-20 20:16:34 +01:00
sLog -> outDebug ( LOG_FILTER_ACHIEVEMENTSYS , "AchievementMgr::SetCriteriaProgress(%u, %u) for (GUID:%u)" , entry -> ID , changeValue , m_player -> GetGUIDLow ());
2009-10-17 15:51:44 -07:00
2010-06-14 18:33:46 +02:00
CriteriaProgress * progress = GetCriteriaProgress ( entry );
if ( ! progress )
2008-12-24 09:58:26 -06:00
{
2010-04-27 22:22:13 +02:00
// not create record for 0 counter but allow it for timed achievements
// we will need to send 0 progress to client to start the timer
if ( changeValue == 0 && ! entry -> timeLimit )
2009-01-20 19:59:43 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
progress = & m_criteriaProgress [ entry -> ID ];
2009-03-05 09:22:43 -06:00
progress -> counter = changeValue ;
2008-12-24 09:58:26 -06:00
}
else
{
2009-04-27 18:42:35 -05:00
uint32 newValue = 0 ;
2010-12-17 18:12:46 +01:00
switch ( ptype )
2009-03-05 09:22:43 -06:00
{
case PROGRESS_SET :
newValue = changeValue ;
2009-04-03 16:39:21 -06:00
break ;
2009-03-05 09:22:43 -06:00
case PROGRESS_ACCUMULATE :
2009-03-06 18:14:05 -06:00
{
// avoid overflow
uint32 max_value = std :: numeric_limits < uint32 >:: max ();
newValue = max_value - progress -> counter > changeValue ? progress -> counter + changeValue : max_value ;
2009-04-03 16:39:21 -06:00
break ;
2009-03-06 18:14:05 -06:00
}
2009-03-05 09:22:43 -06:00
case PROGRESS_HIGHEST :
newValue = progress -> counter < changeValue ? changeValue : progress -> counter ;
2009-04-03 16:39:21 -06:00
break ;
2009-03-05 09:22:43 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-20 19:59:43 -06:00
// not update (not mark as changed) if counter will have same value
2010-04-27 22:22:13 +02:00
if ( progress -> counter == newValue && ! entry -> timeLimit )
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
progress -> counter = newValue ;
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
progress -> changed = true ;
2010-06-14 18:33:46 +02:00
progress -> date = time ( NULL ); // set the date to the latest update.
2009-10-17 15:51:44 -07:00
2010-04-27 22:22:13 +02:00
uint32 timeElapsed = 0 ;
bool timedCompleted = false ;
2010-04-07 19:14:10 +02:00
if ( entry -> timeLimit )
2008-12-24 09:58:26 -06:00
{
2010-08-06 14:56:41 +02:00
// has to exist else we wouldn't be here
2010-04-27 22:22:13 +02:00
timedCompleted = IsCompletedCriteria ( entry , sAchievementStore . LookupEntry ( entry -> referredAchievement ));
// Client expects this in packet
2010-07-12 00:30:17 +02:00
timeElapsed = entry -> timeLimit - ( timedIter -> second / IN_MILLISECONDS );
2010-04-27 22:22:13 +02:00
// Remove the timer, we wont need it anymore
if ( timedCompleted )
m_timedAchievements . erase ( timedIter );
}
2009-10-17 15:51:44 -07:00
2010-04-27 22:22:13 +02:00
SendCriteriaUpdate ( entry , progress , timeElapsed , timedCompleted );
}
2010-08-13 13:48:59 +02:00
void AchievementMgr :: RemoveCriteriaProgress ( const AchievementCriteriaEntry * entry )
{
CriteriaProgressMap :: iterator criteriaProgress = m_criteriaProgress . find ( entry -> ID );
if ( criteriaProgress == m_criteriaProgress . end ())
return ;
2011-04-29 20:47:02 +02:00
WorldPacket data ( SMSG_CRITERIA_DELETED , 4 );
2010-08-13 13:48:59 +02:00
data << uint32 ( entry -> ID );
m_player -> SendDirectMessage ( & data );
m_criteriaProgress . erase ( criteriaProgress );
}
2010-04-27 22:22:13 +02:00
void AchievementMgr :: UpdateTimedAchievements ( uint32 timeDiff )
{
if ( ! m_timedAchievements . empty ())
{
for ( TimedAchievementMap :: iterator itr = m_timedAchievements . begin (); itr != m_timedAchievements . end ();)
{
// Time is up, remove timer and reset progress
if ( itr -> second <= timeDiff )
{
AchievementCriteriaEntry const * entry = sAchievementCriteriaStore . LookupEntry ( itr -> first );
2010-08-13 13:48:59 +02:00
RemoveCriteriaProgress ( entry );
2010-04-27 22:22:13 +02:00
m_timedAchievements . erase ( itr ++ );
}
else
{
itr -> second -= timeDiff ;
++ itr ;
}
}
}
}
2010-08-12 13:38:31 +02:00
void AchievementMgr :: StartTimedAchievement ( AchievementCriteriaTimedTypes type , uint32 entry , uint32 timeLost /*= 0*/ )
2010-04-27 22:22:13 +02:00
{
2010-12-22 21:25:23 +01:00
AchievementCriteriaEntryList const & achievementCriteriaList = sAchievementMgr -> GetTimedAchievementCriteriaByType ( type );
2010-04-27 22:22:13 +02:00
for ( AchievementCriteriaEntryList :: const_iterator i = achievementCriteriaList . begin (); i != achievementCriteriaList . end (); ++ i )
{
if (( * i ) -> timerStartEvent != entry )
continue ;
AchievementEntry const * achievement = sAchievementStore . LookupEntry (( * i ) -> referredAchievement );
if ( m_timedAchievements . find (( * i ) -> ID ) == m_timedAchievements . end () && ! IsCompletedCriteria ( * i , achievement ))
{
// Start the timer
2010-08-12 13:38:31 +02:00
if (( * i ) -> timeLimit * IN_MILLISECONDS > timeLost )
{
m_timedAchievements [( * i ) -> ID ] = ( * i ) -> timeLimit * IN_MILLISECONDS - timeLost ;
2010-04-27 22:22:13 +02:00
2010-08-12 13:38:31 +02:00
// and at client too
SetCriteriaProgress ( * i , 0 , PROGRESS_SET );
}
2010-04-27 22:22:13 +02:00
}
}
}
void AchievementMgr :: RemoveTimedAchievement ( AchievementCriteriaTimedTypes type , uint32 entry )
{
2010-12-22 21:25:23 +01:00
AchievementCriteriaEntryList const & achievementCriteriaList = sAchievementMgr -> GetTimedAchievementCriteriaByType ( type );
2010-04-27 22:22:13 +02:00
for ( AchievementCriteriaEntryList :: const_iterator i = achievementCriteriaList . begin (); i != achievementCriteriaList . end (); ++ i )
{
if (( * i ) -> timerStartEvent != entry )
continue ;
TimedAchievementMap :: iterator timedIter = m_timedAchievements . find (( * i ) -> ID );
// We don't have timer for this achievement
if ( timedIter == m_timedAchievements . end ())
continue ;
2010-08-13 13:48:59 +02:00
// remove progress
RemoveCriteriaProgress ( * i );
2010-04-27 22:22:13 +02:00
// Remove the timer
m_timedAchievements . erase ( timedIter );
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2011-07-02 02:14:49 +02:00
void AchievementMgr :: CompletedAchievement ( AchievementEntry const * achievement )
2008-12-24 09:58:26 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outDetail ( "AchievementMgr::CompletedAchievement(%u)" , achievement -> ID );
2009-10-17 15:51:44 -07:00
2011-07-02 02:14:49 +02:00
// disable for gamemasters with GM-mode enabled
2011-07-02 02:41:03 +02:00
if ( m_player -> isGameMaster ())
2009-08-16 14:30:40 +02:00
return ;
2009-10-17 16:20:24 -07:00
2010-04-07 19:14:10 +02:00
if ( achievement -> flags & ACHIEVEMENT_FLAG_COUNTER || HasAchieved ( achievement ))
2008-12-24 09:58:26 -06:00
return ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
SendAchievementEarned ( achievement );
CompletedAchievementData & ca = m_completedAchievements [ achievement -> ID ];
2009-12-24 10:20:15 +01:00
ca . date = time ( NULL );
2008-12-24 09:58:26 -06:00
ca . changed = true ;
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
// don't insert for ACHIEVEMENT_FLAG_REALM_FIRST_KILL since otherwise only the first group member would reach that achievement
// TODO: where do set this instead?
2010-04-07 19:14:10 +02:00
if ( ! ( achievement -> flags & ACHIEVEMENT_FLAG_REALM_FIRST_KILL ))
2010-12-22 21:25:23 +01:00
sAchievementMgr -> SetRealmCompleted ( achievement );
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_ACHIEVEMENT );
2010-08-06 14:56:41 +02:00
UpdateAchievementCriteria ( ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS , achievement -> points );
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// reward items and titles if any
2010-12-22 21:25:23 +01:00
AchievementReward const * reward = sAchievementMgr -> GetAchievementReward ( achievement );
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// no rewards
2010-04-07 19:14:10 +02:00
if ( ! reward )
2009-01-06 13:55:14 -06:00
return ;
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// titles
2010-05-26 11:03:45 +02:00
if ( uint32 titleId = reward -> titleId [ GetPlayer () -> GetTeam () == ALLIANCE ? 0 : 1 ])
2010-04-07 19:14:10 +02:00
if ( CharTitlesEntry const * titleEntry = sCharTitlesStore . LookupEntry ( titleId ))
2008-12-24 09:58:26 -06:00
GetPlayer () -> SetTitle ( titleEntry );
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// mail
2010-04-07 19:14:10 +02:00
if ( reward -> sender )
2009-01-06 13:55:14 -06:00
{
2011-04-29 20:47:02 +02:00
Item * item = reward -> itemId ? Item :: CreateItem ( reward -> itemId , 1 , GetPlayer ()) : NULL ;
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
int loc_idx = GetPlayer () -> GetSession () -> GetSessionDbLocaleIndex ();
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// subject and text
std :: string subject = reward -> subject ;
std :: string text = reward -> text ;
2010-04-07 22:59:46 +02:00
if ( loc_idx >= 0 )
2009-01-06 13:55:14 -06:00
{
2010-12-22 21:25:23 +01:00
if ( AchievementRewardLocale const * loc = sAchievementMgr -> GetAchievementRewardLocale ( achievement ))
2008-12-24 09:58:26 -06:00
{
2011-08-04 15:14:15 +02:00
ObjectMgr :: GetLocaleString ( loc -> subject , loc_idx , subject );
ObjectMgr :: GetLocaleString ( loc -> text , loc_idx , text );
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2010-04-11 11:16:42 +04:00
MailDraft draft ( subject , text );
2009-12-17 13:07:38 +01:00
2010-08-21 03:19:25 +02:00
SQLTransaction trans = CharacterDatabase . BeginTransaction ();
2010-04-07 19:14:10 +02:00
if ( item )
2009-12-17 13:07:38 +01:00
{
// save new item before send
2010-08-21 03:19:25 +02:00
item -> SaveToDB ( trans ); // save for prevent lost at next mail load, if send fail then item will deleted
2009-12-17 13:07:38 +01:00
// item
draft . AddItem ( item );
}
2010-08-21 03:19:25 +02:00
draft . SendMailTo ( trans , GetPlayer (), MailSender ( MAIL_CREATURE , reward -> sender ));
CharacterDatabase . CommitTransaction ( trans );
2008-12-24 09:58:26 -06:00
}
}
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
void AchievementMgr :: SendAllAchievementData () const
2008-12-24 09:58:26 -06:00
{
2010-04-24 15:08:18 +02:00
WorldPacket data ( SMSG_ALL_ACHIEVEMENT_DATA , m_completedAchievements . size () * 8 + 4 + m_criteriaProgress . size () * 38 + 4 );
BuildAllDataPacket ( & data );
GetPlayer () -> GetSession () -> SendPacket ( & data );
2008-12-24 09:58:26 -06:00
}
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
void AchievementMgr :: SendRespondInspectAchievements ( Player * player ) const
2008-12-24 09:58:26 -06:00
{
2010-04-24 15:08:18 +02:00
WorldPacket data ( SMSG_RESPOND_INSPECT_ACHIEVEMENTS , 9 + m_completedAchievements . size () * 8 + 4 + m_criteriaProgress . size () * 38 + 4 );
2008-12-24 09:58:26 -06:00
data . append ( GetPlayer () -> GetPackGUID ());
BuildAllDataPacket ( & data );
player -> GetSession () -> SendPacket ( & data );
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
/**
2010-04-24 15:08:18 +02:00
* used by SMSG_RESPOND_INSPECT_ACHIEVEMENT and SMSG_ALL_ACHIEVEMENT_DATA
2008-12-24 09:58:26 -06:00
*/
2011-03-04 12:11:20 +01:00
void AchievementMgr :: BuildAllDataPacket ( WorldPacket * data ) const
2008-12-24 09:58:26 -06:00
{
2011-03-04 12:11:20 +01:00
AchievementEntry const * achievement = NULL ;
2010-04-08 08:20:08 +02:00
for ( CompletedAchievementMap :: const_iterator iter = m_completedAchievements . begin (); iter != m_completedAchievements . end (); ++ iter )
2008-12-24 09:58:26 -06:00
{
2011-03-04 12:11:20 +01:00
// Skip hidden achievements
2010-04-27 22:22:13 +02:00
achievement = sAchievementStore . LookupEntry ( iter -> first );
2011-03-04 12:11:20 +01:00
if ( achievement -> flags & ACHIEVEMENT_FLAG_HIDDEN )
2010-04-27 22:22:13 +02:00
continue ;
2008-12-24 09:58:26 -06:00
* data << uint32 ( iter -> first );
* data << uint32 ( secsToTimeBitFields ( iter -> second . date ));
}
* data << int32 ( - 1 );
2009-10-17 15:51:44 -07:00
2010-04-08 08:20:08 +02:00
for ( CriteriaProgressMap :: const_iterator iter = m_criteriaProgress . begin (); iter != m_criteriaProgress . end (); ++ iter )
2008-12-24 09:58:26 -06:00
{
* data << uint32 ( iter -> first );
data -> appendPackGUID ( iter -> second . counter );
data -> append ( GetPlayer () -> GetPackGUID ());
* data << uint32 ( 0 );
* data << uint32 ( secsToTimeBitFields ( iter -> second . date ));
* data << uint32 ( 0 );
* data << uint32 ( 0 );
}
2009-10-17 15:51:44 -07:00
2008-12-24 09:58:26 -06:00
* data << int32 ( - 1 );
}
2009-10-17 15:51:44 -07:00
2010-03-15 04:37:28 +01:00
bool AchievementMgr :: HasAchieved ( AchievementEntry const * achievement ) const
{
return m_completedAchievements . find ( achievement -> ID ) != m_completedAchievements . end ();
}
2011-03-04 12:11:20 +01:00
bool AchievementMgr :: CanUpdateCriteria ( AchievementCriteriaEntry const * criteria , AchievementEntry const * achievement )
2009-01-06 13:55:14 -06:00
{
2011-03-04 12:11:20 +01:00
if ( sDisableMgr -> IsDisabledFor ( DISABLE_TYPE_ACHIEVEMENT_CRITERIA , criteria -> ID , NULL ))
return false ;
2009-10-17 15:51:44 -07:00
2011-04-03 14:44:09 +02:00
if ( achievement -> mapID != - 1 && GetPlayer () -> GetMapId () != uint32 ( achievement -> mapID ))
return false ;
2011-03-04 12:11:20 +01:00
if (( achievement -> requiredFaction == ACHIEVEMENT_FACTION_HORDE && GetPlayer () -> GetTeam () != HORDE ) ||
( achievement -> requiredFaction == ACHIEVEMENT_FACTION_ALLIANCE && GetPlayer () -> GetTeam () != ALLIANCE ))
return false ;
for ( uint32 i = 0 ; i < MAX_CRITERIA_REQUIREMENTS ; ++ i )
{
2011-03-26 05:33:46 +02:00
if ( ! criteria -> additionalRequirements [ i ]. additionalRequirement_type )
2011-03-04 12:11:20 +01:00
continue ;
2011-03-26 05:33:46 +02:00
switch ( criteria -> additionalRequirements [ i ]. additionalRequirement_type )
2011-03-04 12:11:20 +01:00
{
2011-04-21 21:14:49 +02:00
case ACHIEVEMENT_CRITERIA_CONDITION_BG_MAP :
2011-03-26 05:33:46 +02:00
if ( GetPlayer () -> GetMapId () != criteria -> additionalRequirements [ i ]. additionalRequirement_value )
2011-03-04 12:11:20 +01:00
return false ;
break ;
case ACHIEVEMENT_CRITERIA_CONDITION_NOT_IN_GROUP :
if ( GetPlayer () -> GetGroup ())
return false ;
break ;
default :
break ;
}
}
// don't update already completed criteria
if ( IsCompletedCriteria ( criteria , achievement ))
return false ;
return true ;
2010-04-27 22:22:13 +02:00
}
2011-03-04 12:11:20 +01:00
//==========================================================
2009-01-06 13:55:14 -06:00
void AchievementGlobalMgr :: LoadAchievementCriteriaList ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2010-04-07 23:25:02 +02:00
if ( sAchievementCriteriaStore . GetNumRows () == 0 )
2009-01-22 22:44:27 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( ">> Loaded 0 achievement criteria." );
sLog -> outString ();
2009-01-22 22:44:27 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
for ( uint32 entryId = 0 ; entryId < sAchievementCriteriaStore . GetNumRows (); ++ entryId )
2009-01-06 13:55:14 -06:00
{
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
AchievementCriteriaEntry const * criteria = sAchievementCriteriaStore . LookupEntry ( entryId );
2010-04-07 19:14:10 +02:00
if ( ! criteria )
2009-01-06 13:55:14 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
m_AchievementCriteriasByType [ criteria -> requiredType ]. push_back ( criteria );
2009-04-03 16:36:20 -06:00
m_AchievementCriteriaListByAchievement [ criteria -> referredAchievement ]. push_back ( criteria );
2010-04-27 22:22:13 +02:00
2010-04-29 23:12:16 +02:00
if ( criteria -> timeLimit )
2010-04-27 22:22:13 +02:00
m_AchievementCriteriasByTimedType [ criteria -> timedType ]. push_back ( criteria );
2009-01-06 13:55:14 -06:00
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
sLog -> outString ( ">> Loaded %lu achievement criteria in %u ms" , ( unsigned long ) m_AchievementCriteriasByType -> size (), GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-01-06 13:55:14 -06:00
}
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
void AchievementGlobalMgr :: LoadAchievementReferenceList ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2010-04-07 23:25:02 +02:00
if ( sAchievementStore . GetNumRows () == 0 )
2009-04-03 16:36:20 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded 0 achievement references." );
sLog -> outString ();
2009-04-03 16:36:20 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-12-19 17:06:33 +01:00
uint32 count = 0 ;
2009-04-03 16:36:20 -06:00
for ( uint32 entryId = 0 ; entryId < sAchievementStore . GetNumRows (); ++ entryId )
{
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( entryId );
2010-04-07 19:14:10 +02:00
if ( ! achievement || ! achievement -> refAchievement )
2009-04-03 16:36:20 -06:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-03 16:36:20 -06:00
m_AchievementListByReferencedId [ achievement -> refAchievement ]. push_back ( achievement );
++ count ;
}
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
sLog -> outString ( ">> Loaded %u achievement references in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-04-08 16:24:34 -05:00
}
2009-10-17 15:51:44 -07:00
2009-04-08 16:24:34 -05:00
void AchievementGlobalMgr :: LoadAchievementCriteriaData ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2009-04-08 16:27:00 -05:00
m_criteriaDataMap . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2010-09-11 21:10:54 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT criteria_id, type, value1, value2, ScriptName FROM achievement_criteria_data" );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! result )
2009-04-08 16:24:34 -05:00
{
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty." );
sLog -> outString ();
2009-04-08 16:24:34 -05:00
return ;
}
2009-10-17 15:51:44 -07:00
2010-12-19 17:06:33 +01:00
uint32 count = 0 ;
2009-04-08 16:24:34 -05:00
do
{
Field * fields = result -> Fetch ();
uint32 criteria_id = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2009-04-08 16:24:34 -05:00
AchievementCriteriaEntry const * criteria = sAchievementCriteriaStore . LookupEntry ( criteria_id );
2009-10-17 15:51:44 -07:00
2009-04-08 16:24:34 -05:00
if ( ! criteria )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` has data for non-existing criteria (Entry: %u), ignore." , criteria_id );
2009-04-08 16:24:34 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2010-08-07 16:48:34 +02:00
uint32 dataType = fields [ 1 ]. GetUInt32 ();
2010-09-24 22:16:21 +02:00
const char * scriptName = fields [ 4 ]. GetCString ();
2010-08-07 16:48:34 +02:00
uint32 scriptId = 0 ;
2010-08-09 10:56:59 +02:00
if ( strcmp ( scriptName , "" )) // not empty
2010-08-07 16:48:34 +02:00
{
if ( dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_SCRIPT )
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` has ScriptName set for non-scripted data type (Entry: %u, type %u), useless data." , criteria_id , dataType );
2010-08-07 16:48:34 +02:00
else
2010-12-22 21:25:23 +01:00
scriptId = sObjectMgr -> GetScriptId ( scriptName );
2010-08-07 16:48:34 +02:00
}
AchievementCriteriaData data ( dataType , fields [ 2 ]. GetUInt32 (), fields [ 3 ]. GetUInt32 (), scriptId );
2009-10-17 15:51:44 -07:00
2009-06-07 20:54:23 -05:00
if ( ! data . IsValid ( criteria ))
2009-04-08 16:24:34 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-04-08 16:34:38 -05:00
// this will allocate empty data set storage
AchievementCriteriaDataSet & dataSet = m_criteriaDataMap [ criteria_id ];
2010-01-16 19:41:04 +03:00
dataSet . SetCriteriaId ( criteria_id );
2009-10-17 15:51:44 -07:00
2009-04-08 16:34:38 -05:00
// add real data only for not NONE data types
2009-06-07 20:54:23 -05:00
if ( data . dataType != ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE )
2009-04-08 16:34:38 -05:00
dataSet . Add ( data );
2009-10-17 15:51:44 -07:00
2009-04-08 16:34:38 -05:00
// counting data by and data types
2009-04-08 16:24:34 -05:00
++ count ;
2010-12-19 17:06:33 +01:00
}
while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2009-04-08 16:24:34 -05:00
// post loading checks
for ( uint32 entryId = 0 ; entryId < sAchievementCriteriaStore . GetNumRows (); ++ entryId )
{
AchievementCriteriaEntry const * criteria = sAchievementCriteriaStore . LookupEntry ( entryId );
2010-04-07 19:14:10 +02:00
if ( ! criteria )
2009-04-08 16:24:34 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2010-12-17 18:12:46 +01:00
switch ( criteria -> requiredType )
2009-04-08 16:24:34 -05:00
{
2010-08-13 13:48:59 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_BG : // any cases
2009-07-31 11:36:02 +08:00
break ;
2009-06-07 20:54:23 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE :
break ; // any cases
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST :
{
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( criteria -> referredAchievement );
2010-04-07 19:14:10 +02:00
if ( ! achievement )
2009-06-14 10:00:45 -05:00
continue ;
2009-10-17 15:51:44 -07:00
2009-06-14 10:00:45 -05:00
// exist many achievements with this criteria, use at this moment hardcoded check to skil simple case
2011-06-19 14:07:07 +02:00
if ( achievement -> ID == 1282 )
break ;
continue ;
2009-06-14 10:00:45 -05:00
}
case ACHIEVEMENT_CRITERIA_TYPE_FALL_WITHOUT_DYING :
break ; // any cases
2010-04-27 22:22:13 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET : // any cases
break ;
2009-06-14 10:00:45 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL : // any cases
break ;
2009-06-01 21:51:34 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_RATED_ARENA : // need skip generic cases
2011-03-26 05:33:46 +02:00
if ( criteria -> additionalRequirements [ 0 ]. additionalRequirement_type != ACHIEVEMENT_CRITERIA_CONDITION_NO_LOSE )
2009-06-01 21:51:34 -05:00
continue ;
break ;
2010-03-22 18:32:38 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_EQUIP_EPIC_ITEM : // any cases
break ;
2010-04-27 22:22:13 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_NEED_ON_LOOT :
break ; // any cases
case ACHIEVEMENT_CRITERIA_TYPE_ROLL_GREED_ON_LOOT :
break ; // any cases
2009-04-08 16:34:38 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE : // need skip generic cases
2010-04-07 23:25:02 +02:00
if ( criteria -> do_emote . count == 0 )
2009-04-29 18:42:53 -05:00
continue ;
2009-04-08 16:24:34 -05:00
break ;
2010-04-27 22:22:13 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BE_SPELL_TARGET2 :
break ; // any cases
2009-08-02 10:12:40 +08:00
case ACHIEVEMENT_CRITERIA_TYPE_WIN_DUEL : // skip statistics
2010-04-07 23:25:02 +02:00
if ( criteria -> win_duel . duelCount == 0 )
2009-08-02 10:12:40 +08:00
continue ;
break ;
2009-04-29 18:42:53 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2 : // any cases
2009-04-08 16:24:34 -05:00
break ;
2009-04-29 18:42:53 -05:00
case ACHIEVEMENT_CRITERIA_TYPE_LOOT_TYPE : // need skip generic cases
2010-04-08 08:20:08 +02:00
if ( criteria -> loot_type . lootTypeCount != 1 )
2009-04-29 18:42:53 -05:00
continue ;
break ;
2010-08-07 18:31:06 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_BG_OBJECTIVE_CAPTURE :
break ; // any cases
2010-08-13 13:48:59 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_SPECIAL_PVP_KILL :
break ; // any cases
2010-12-17 18:12:46 +01:00
case ACHIEVEMENT_CRITERIA_TYPE_HONORABLE_KILL : // any cases
break ;
2011-04-30 12:41:14 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_DAILY_QUEST :
case ACHIEVEMENT_CRITERIA_TYPE_USE_ITEM : // only Children's Week achievements
{
AchievementEntry const * achievement = sAchievementStore . LookupEntry ( criteria -> referredAchievement );
if ( ! achievement )
continue ;
if ( achievement -> categoryId != CATEGORY_CHILDRENS_WEEK )
continue ;
break ;
}
2011-05-14 12:26:49 +02:00
case ACHIEVEMENT_CRITERIA_TYPE_GET_KILLING_BLOWS :
break ;
2009-04-29 18:42:53 -05:00
default : // type not use DB data, ignore
continue ;
2009-04-08 16:24:34 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-22 21:25:23 +01:00
if ( ! GetCriteriaDataSet ( criteria ) && ! sDisableMgr -> IsDisabledFor ( DISABLE_TYPE_ACHIEVEMENT_CRITERIA , entryId , NULL ))
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_criteria_data` does not have expected data for criteria (Entry: %u Type: %u) for achievement %u." , criteria -> ID , criteria -> requiredType , criteria -> referredAchievement );
2009-04-08 16:24:34 -05:00
}
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded %u additional achievement criteria data in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-04-03 16:36:20 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
void AchievementGlobalMgr :: LoadCompletedAchievements ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2010-09-11 21:10:54 +02:00
QueryResult result = CharacterDatabase . Query ( "SELECT achievement FROM character_achievement GROUP BY achievement" );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! result )
2009-01-22 22:44:27 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded 0 completed achievements. DB table `character_achievement` is empty." );
sLog -> outString ();
2009-01-06 13:55:14 -06:00
return ;
2009-01-22 22:44:27 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
do
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-05-08 19:22:17 -05:00
uint32 achievement_id = fields [ 0 ]. GetUInt32 ();
2010-04-07 19:14:10 +02:00
if ( ! sAchievementStore . LookupEntry ( achievement_id ))
2009-05-08 19:22:17 -05:00
{
// we will remove not existed achievement for all characters
2011-04-29 20:47:02 +02:00
sLog -> outError ( "Non-existing achievement %u data removed from table `character_achievement`." , achievement_id );
CharacterDatabase . PExecute ( "DELETE FROM character_achievement WHERE achievement = %u" , achievement_id );
2009-05-08 19:22:17 -05:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-05-08 19:22:17 -05:00
m_allCompletedAchievements . insert ( achievement_id );
2010-04-07 19:13:19 +02:00
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
sLog -> outString ( ">> Loaded %lu completed achievements in %u ms" , ( unsigned long ) m_allCompletedAchievements . size (), GetMSTimeDiffToNow ( oldMSTime ));
2010-12-23 23:25:44 +01:00
sLog -> outString ();
2009-01-06 13:55:14 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
void AchievementGlobalMgr :: LoadRewards ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2009-04-08 16:27:00 -05:00
m_achievementRewards . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// 0 1 2 3 4 5 6
2010-09-11 21:10:54 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT entry, title_A, title_H, item, sender, subject, text FROM achievement_reward" );
2009-10-17 15:51:44 -07:00
2010-04-07 19:14:10 +02:00
if ( ! result )
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( ">> Loaded 0 achievement rewards. DB table `achievement_reward` is empty." );
sLog -> outString ();
2009-01-06 13:55:14 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-04-08 16:27:00 -05:00
uint32 count = 0 ;
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
do
{
2009-01-22 22:44:27 -06:00
Field * fields = result -> Fetch ();
2009-01-06 13:55:14 -06:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
2010-03-11 23:25:04 +01:00
const AchievementEntry * pAchievement = sAchievementStore . LookupEntry ( entry );
if ( ! pAchievement )
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` has wrong achievement (Entry: %u), ignore" , entry );
2009-01-06 13:55:14 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
AchievementReward reward ;
reward . titleId [ 0 ] = fields [ 1 ]. GetUInt32 ();
reward . titleId [ 1 ] = fields [ 2 ]. GetUInt32 ();
reward . itemId = fields [ 3 ]. GetUInt32 ();
reward . sender = fields [ 4 ]. GetUInt32 ();
2010-09-24 22:16:21 +02:00
reward . subject = fields [ 5 ]. GetString ();
reward . text = fields [ 6 ]. GetString ();
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
// must be title or mail at least
if ( ! reward . titleId [ 0 ] && ! reward . titleId [ 1 ] && ! reward . sender )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) not have title or item reward data, ignore." , entry );
2009-01-06 13:55:14 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2011-03-04 12:11:20 +01:00
if ( pAchievement -> requiredFaction == ACHIEVEMENT_FACTION_ANY && (( reward . titleId [ 0 ] == 0 ) != ( reward . titleId [ 1 ] == 0 )))
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) has title (A: %u H: %u) for only one team." , entry , reward . titleId [ 0 ], reward . titleId [ 1 ]);
2010-03-11 23:25:04 +01:00
2009-01-06 13:55:14 -06:00
if ( reward . titleId [ 0 ])
{
CharTitlesEntry const * titleEntry = sCharTitlesStore . LookupEntry ( reward . titleId [ 0 ]);
if ( ! titleEntry )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_A`, set to 0" , entry , reward . titleId [ 0 ]);
2009-01-06 13:55:14 -06:00
reward . titleId [ 0 ] = 0 ;
}
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
if ( reward . titleId [ 1 ])
{
CharTitlesEntry const * titleEntry = sCharTitlesStore . LookupEntry ( reward . titleId [ 1 ]);
if ( ! titleEntry )
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) has invalid title id (%u) in `title_H`, set to 0" , entry , reward . titleId [ 1 ]);
2009-01-06 13:55:14 -06:00
reward . titleId [ 1 ] = 0 ;
}
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
//check mail data before item for report including wrong item case
if ( reward . sender )
{
2011-04-28 22:57:08 +02:00
if ( ! sObjectMgr -> GetCreatureTemplate ( reward . sender ))
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) has invalid creature entry %u as sender, mail reward skipped." , entry , reward . sender );
2009-01-06 13:55:14 -06:00
reward . sender = 0 ;
}
}
else
{
if ( reward . itemId )
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) does not have sender data but has item reward, item will not be rewarded." , entry );
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
if ( ! reward . subject . empty ())
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) does not have sender data but has mail subject." , entry );
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
if ( ! reward . text . empty ())
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) does not have sender data but has mail text." , entry );
2009-01-06 13:55:14 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
if ( reward . itemId )
{
2011-04-28 22:42:33 +02:00
if ( ! sObjectMgr -> GetItemTemplate ( reward . itemId ))
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `achievement_reward` (Entry: %u) has invalid item id %u, reward mail will not contain item." , entry , reward . itemId );
2009-01-06 13:55:14 -06:00
reward . itemId = 0 ;
}
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
m_achievementRewards [ entry ] = reward ;
2009-04-08 16:27:00 -05:00
++ count ;
2009-10-17 15:51:44 -07:00
2010-12-19 17:06:33 +01:00
}
while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded %u achievement rewards in %u ms" , count , GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-01-06 13:55:14 -06:00
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
void AchievementGlobalMgr :: LoadRewardLocales ()
{
2010-12-19 17:06:33 +01:00
uint32 oldMSTime = getMSTime ();
2009-01-06 13:55:14 -06:00
m_achievementRewardLocales . clear (); // need for reload case
2009-10-17 15:51:44 -07:00
2011-04-29 20:47:02 +02:00
QueryResult result = WorldDatabase . Query ( "SELECT entry, subject_loc1, text_loc1, subject_loc2, text_loc2, subject_loc3, text_loc3, subject_loc4, text_loc4, "
"subject_loc5, text_loc5, subject_loc6, text_loc6, subject_loc7, text_loc7, subject_loc8, text_loc8"
2010-12-19 17:06:33 +01:00
" FROM locales_achievement_reward" );
2009-10-17 15:51:44 -07:00
2010-01-01 14:19:29 -06:00
if ( ! result )
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded 0 achievement reward locale strings. DB table `locales_achievement_reward` is empty" );
sLog -> outString ();
2009-01-06 13:55:14 -06:00
return ;
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
do
{
Field * fields = result -> Fetch ();
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
uint32 entry = fields [ 0 ]. GetUInt32 ();
2009-10-17 15:51:44 -07:00
2010-04-07 23:25:02 +02:00
if ( m_achievementRewards . find ( entry ) == m_achievementRewards . end ())
2009-01-06 13:55:14 -06:00
{
2010-12-23 23:25:44 +01:00
sLog -> outErrorDb ( "Table `locales_achievement_reward` (Entry: %u) has locale strings for non-existing achievement reward." , entry );
2009-01-06 13:55:14 -06:00
continue ;
}
2009-10-17 15:51:44 -07:00
2009-01-06 13:55:14 -06:00
AchievementRewardLocale & data = m_achievementRewardLocales [ entry ];
2009-10-17 15:51:44 -07:00
2010-09-28 08:21:51 +03:00
for ( int i = 1 ; i < TOTAL_LOCALES ; ++ i )
2009-01-06 13:55:14 -06:00
{
2010-08-27 00:57:49 +06:00
LocaleConstant locale = ( LocaleConstant ) i ;
2011-08-04 15:14:15 +02:00
ObjectMgr :: AddLocaleString ( fields [ 1 + 2 * ( i - 1 )]. GetString (), locale , data . subject );
ObjectMgr :: AddLocaleString ( fields [ 1 + 2 * ( i - 1 ) + 1 ]. GetString (), locale , data . text );
2009-01-06 13:55:14 -06:00
}
} while ( result -> NextRow ());
2009-10-17 15:51:44 -07:00
2010-12-23 23:25:44 +01:00
sLog -> outString ( ">> Loaded %lu achievement reward locale strings in %u ms" , ( unsigned long ) m_achievementRewardLocales . size (), GetMSTimeDiffToNow ( oldMSTime ));
sLog -> outString ();
2009-01-06 13:55:14 -06:00
}