diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/game/AchievementMgr.cpp | 243 | ||||
-rw-r--r-- | src/game/AchievementMgr.h | 77 | ||||
-rw-r--r-- | src/game/World.cpp | 1 |
3 files changed, 243 insertions, 78 deletions
diff --git a/src/game/AchievementMgr.cpp b/src/game/AchievementMgr.cpp index da192844a70..c76a6b223c6 100644 --- a/src/game/AchievementMgr.cpp +++ b/src/game/AchievementMgr.cpp @@ -37,56 +37,6 @@ INSTANTIATE_SINGLETON_1(AchievementGlobalMgr); -const CriteriaCastSpellRequirement AchievementGlobalMgr::m_criteriaCastSpellRequirements[CRITERIA_CAST_SPELL_REQ_COUNT] = - { - {5272, 3057, 0, 0}, - {5273, 2784, 0, 0}, - {5752, 9099, 0, 0}, - {5753, 8403, 0, 0}, - {5772, 0, 0, RACE_GNOME}, - {5774, 0, 0, RACE_BLOODELF}, - {5775, 0, 0, RACE_DRAENEI}, - {5776, 0, 0, RACE_DWARF}, - {5777, 0, 0, RACE_HUMAN}, - {5778, 0, 0, RACE_NIGHTELF}, - {5779, 0, 0, RACE_ORC}, - {5780, 0, 0, RACE_TAUREN}, - {5781, 0, 0, RACE_TROLL}, - {5782, 0, 0, RACE_UNDEAD_PLAYER}, - {6225, 5661, 0, 0}, - {6226, 26044, 0, 0}, - {6228, 739, 0, 0}, - {6229, 927, 0, 0}, - {6230, 1444, 0, 0}, - {6231, 8140, 0, 0}, - {6232, 5489, 0, 0}, - {6233,12336, 0, 0}, - {6234, 1351, 0, 0}, - {6235, 5484, 0, 0}, - {6236, 1182, 0, 0}, - {6237, 0, CLASS_DEATH_KNIGHT, RACE_ORC}, - {6238, 0, CLASS_WARRIOR, RACE_HUMAN}, - {6239, 0, CLASS_SHAMAN, RACE_TAUREN}, - {6240, 0, CLASS_DRUID, RACE_NIGHTELF}, - {6241, 0, CLASS_ROGUE, RACE_UNDEAD_PLAYER}, - {6242, 0, CLASS_HUNTER, RACE_TROLL}, - {6243, 0, CLASS_MAGE, RACE_GNOME}, - {6244, 0, CLASS_PALADIN, RACE_DWARF}, - {6245, 0, CLASS_WARLOCK, RACE_BLOODELF}, - {6246, 0, CLASS_PRIEST, RACE_DRAENEI}, - {6312, 0, CLASS_WARLOCK, RACE_GNOME}, - {6313, 0, CLASS_DEATH_KNIGHT, RACE_HUMAN}, - {6314, 0, CLASS_PRIEST, RACE_NIGHTELF}, - {6315, 0, CLASS_SHAMAN, RACE_ORC}, - {6316, 0, CLASS_DRUID, RACE_TAUREN}, - {6317, 0, CLASS_ROGUE, RACE_TROLL}, - {6318, 0, CLASS_WARRIOR, RACE_UNDEAD_PLAYER}, - {6319, 0, CLASS_MAGE, RACE_BLOODELF}, - {6320, 0, CLASS_PALADIN, RACE_DRAENEI}, - {6321, 0, CLASS_HUNTER, RACE_DWARF}, - {6662, 31261, 0, 0} - }; - namespace MaNGOS { class AchievementChatBuilder @@ -117,6 +67,114 @@ namespace MaNGOS }; } // namespace MaNGOS + +bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) +{ + if(dataType >= MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE) + { + sLog.outErrorDb( "Table `achievement_criteria_data` for criteria (Entry: %u) have wrong data type (%u), ignore.", criteria->ID,dataType); + return false; + } + + switch(criteria->requiredType) + { + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + switch(dataType) + { + case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE: + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH: + break; + default: + sLog.outErrorDb( "Table `achievement_criteria_data` for criteria (Entry: %u Type: %u) have wrong data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType); + return false; + } + break; + default: + sLog.outErrorDb( "Table `achievement_criteria_data` have data for not supported criteria type (Entry: %u Type: %u), ignore.", criteria->ID, criteria->requiredType); + return false; + } + + switch(dataType) + { + case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE: + if(!creature.id || !objmgr.GetCreatureTemplate(creature.id)) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) have not existed creature id in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,creature.id); + return false; + } + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE: + if(!classRace.class_id && !classRace.race_id) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE (%u) must have not 0 in one from value fields, ignore.", + criteria->ID, criteria->requiredType,dataType); + return false; + } + if(classRace.class_id && ((1 << (classRace.class_id-1)) & CLASSMASK_ALL_PLAYABLE)==0) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) have not existed class in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,classRace.class_id); + return false; + } + if(classRace.race_id && ((1 << (classRace.race_id-1)) & RACEMASK_ALL_PLAYABLE)==0) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE (%u) have not existed race in value2 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,classRace.race_id); + return false; + } + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH: + if(health.percent < 1 || health.percent > 100) + { + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) have prong percent value in value1 (%u), ignore.", + criteria->ID, criteria->requiredType,dataType,health.percent); + return false; + } + return true; + default: + sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) have data for not supported data type (%u), ignore.", criteria->ID, criteria->requiredType,dataType); + return false; + } + return false; +} + +bool AchievementCriteriaData::Meets( Unit const* target ) const +{ + if (!target) + return false; + + switch(dataType) + { + case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE: + if (target->GetTypeId()!=TYPEID_UNIT) + return false; + if (target->GetEntry() != creature.id) + return false; + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE: + if (target->GetTypeId()!=TYPEID_PLAYER) + return false; + if(classRace.class_id && classRace.class_id != ((Player*)target)->getClass()) + return false; + if(classRace.race_id && classRace.race_id != ((Player*)target)->getRace()) + return false; + return true; + case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH: + if (target->GetTypeId()!=TYPEID_PLAYER) + return false; + return target->GetHealth()*100 <= health.percent*target->GetMaxHealth(); + } + + return false; +} + AchievementMgr::AchievementMgr(Player *player) { m_player = player; @@ -884,24 +942,19 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui break; case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: { + if (!miscvalue1) + continue; + if (!miscvalue1 || miscvalue1 != achievementCriteria->cast_spell.spellID) continue; // those requirements couldn't be found in the dbc - if (CriteriaCastSpellRequirement const* requirement = AchievementGlobalMgr::GetCriteriaCastSpellRequirement(achievementCriteria)) - { - if (!unit) - continue; - - if (requirement->creatureEntry && unit->GetEntry() != requirement->creatureEntry) - continue; - - if (requirement->playerRace && (unit->GetTypeId() != TYPEID_PLAYER || unit->getRace()!=requirement->playerRace)) - continue; + AchievementCriteriaData const* data = achievementmgr.GetCriteriaData(achievementCriteria); + if(!data) + continue; - if (requirement->playerClass && (unit->GetTypeId() != TYPEID_PLAYER || unit->getClass()!=requirement->playerClass)) - continue; - } + if(!data->Meets(unit)) + continue; SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); break; @@ -1388,6 +1441,70 @@ void AchievementGlobalMgr::LoadAchievementReferenceList() sLog.outString(">> Loaded %u achievement references.",count); } +void AchievementGlobalMgr::LoadAchievementCriteriaData() +{ + QueryResult *result = WorldDatabase.Query("SELECT criteria_id, type, value1, value2 FROM achievement_criteria_data"); + + if(!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outString(">> Loaded 0 additional achievement criteria data. DB table `achievement_criteria_data` is empty."); + return; + } + + uint32 count = 0; + barGoLink bar(result->GetRowCount()); + do + { + bar.step(); + Field *fields = result->Fetch(); + uint32 criteria_id = fields[0].GetUInt32(); + + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(criteria_id); + + if (!criteria) + { + sLog.outErrorDb( "Table `achievement_criteria_data` have data for not existed criteria (Entry: %u), ignore.", criteria_id); + continue; + } + + AchievementCriteriaData data(fields[1].GetUInt32(),fields[2].GetUInt32(),fields[3].GetUInt32()); + + if(!data.IsValid(criteria)) + continue; + + m_criteriaDataMap[criteria_id] = data; + ++count; + } while(result->NextRow()); + + delete result; + + // post loading checks + for (uint32 entryId = 0; entryId < sAchievementCriteriaStore.GetNumRows(); ++entryId) + { + AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(entryId); + if(!criteria) + continue; + + switch(criteria->requiredType) + { + case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: + if(!GetCriteriaData(criteria)) + sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType); + break; + default: // unexpected case processed in IsValid check + break; + } + + } + + sLog.outString(); + sLog.outString(">> Loaded %u additional achievement criteria data.",count); +} + void AchievementGlobalMgr::LoadCompletedAchievements() { QueryResult *result = CharacterDatabase.Query("SELECT achievement FROM character_achievement GROUP BY achievement"); diff --git a/src/game/AchievementMgr.h b/src/game/AchievementMgr.h index b45c63f7301..faabaf011ef 100644 --- a/src/game/AchievementMgr.h +++ b/src/game/AchievementMgr.h @@ -27,9 +27,6 @@ #include <map> #include <string> -#define CRITERIA_CAST_SPELL_REQ_COUNT 46 -#define ACHIEVEMENT_REWARD_COUNT 57 - typedef std::list<AchievementCriteriaEntry const*> AchievementCriteriaEntryList; typedef std::list<AchievementEntry const*> AchievementEntryList; @@ -43,14 +40,66 @@ struct CriteriaProgress bool changed; }; -struct CriteriaCastSpellRequirement +enum AchievementCriteriaDataType +{ // value1 value2 for the Condition enumed + ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 + ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE = 1, // creature_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE = 2, // class_id race_id + ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH = 3, // health_percent +}; + +#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 4 // maximum value in AchievementCriteriaDataType enum + +class Unit; + +struct AchievementCriteriaData { - uint32 achievementCriteriaId; - uint32 creatureEntry; - uint8 playerClass; - uint8 playerRace; + AchievementCriteriaDataType dataType; + union + { + // ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE + struct + { + uint32 id; + } creature; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE + struct + { + uint32 class_id; + uint32 race_id; + } classRace; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH + struct + { + uint32 percent; + } health; + // ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE + struct + { + uint32 value1; + uint32 value2; + } raw; + }; + + AchievementCriteriaData() : dataType(ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE) + { + raw.value1 = 0; + raw.value2 = 0; + } + + AchievementCriteriaData(uint32 _dataType, uint32 _value1, uint32 _value2) : dataType(AchievementCriteriaDataType(_dataType)) + { + raw.value1 = _value1; + raw.value2 = _value2; + } + + bool IsValid(AchievementCriteriaEntry const* criteria); + // Checks correctness of values + bool Meets(Unit const* target) const;// Checks if the target meets the requirement }; +typedef std::map<uint32,AchievementCriteriaData> AchievementCriteriaDataMap; + struct AchievementReward { uint32 titleId[2]; @@ -145,13 +194,10 @@ class AchievementGlobalMgr return iter!=m_achievementRewardLocales.end() ? &iter->second : NULL; } - static CriteriaCastSpellRequirement const * GetCriteriaCastSpellRequirement(AchievementCriteriaEntry const *achievementCriteria) + AchievementCriteriaData const* GetCriteriaData(AchievementCriteriaEntry const *achievementCriteria) { - for (uint32 i=0; i < CRITERIA_CAST_SPELL_REQ_COUNT; ++i) - if (m_criteriaCastSpellRequirements[i].achievementCriteriaId == achievementCriteria->ID) - return &m_criteriaCastSpellRequirements[i]; - - return NULL; + AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID); + return iter!=m_criteriaDataMap.end() ? &iter->second : NULL; } bool IsRealmCompleted(AchievementEntry const* achievement) const @@ -165,12 +211,13 @@ class AchievementGlobalMgr } void LoadAchievementCriteriaList(); + void LoadAchievementCriteriaData(); void LoadAchievementReferenceList(); void LoadCompletedAchievements(); void LoadRewards(); void LoadRewardLocales(); private: - static const CriteriaCastSpellRequirement m_criteriaCastSpellRequirements[]; + AchievementCriteriaDataMap m_criteriaDataMap; // store achievement criterias by type to speed up lookup AchievementCriteriaEntryList m_AchievementCriteriasByType[ACHIEVEMENT_CRITERIA_TYPE_TOTAL]; diff --git a/src/game/World.cpp b/src/game/World.cpp index 4bf272a21c8..a8dbff76114 100644 --- a/src/game/World.cpp +++ b/src/game/World.cpp @@ -1372,6 +1372,7 @@ void World::SetInitialWorldSettings() sLog.outString(); achievementmgr.LoadAchievementReferenceList(); achievementmgr.LoadAchievementCriteriaList(); + achievementmgr.LoadAchievementCriteriaData(); achievementmgr.LoadRewards(); achievementmgr.LoadRewardLocales(); achievementmgr.LoadCompletedAchievements(); |