[7633] Implement support multiply basic requirements for crireria in achievement_criteria_data.

Also implement additional basic requirements for proper implementing checks for ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE
Req. DB support.
This commit is contained in:
VladimirMangos 2009-04-08 02:37:16 +04:00
parent 6b2fd22a9c
commit 863a747251
6 changed files with 144 additions and 62 deletions

View file

@ -22,7 +22,7 @@
DROP TABLE IF EXISTS `db_version`; DROP TABLE IF EXISTS `db_version`;
CREATE TABLE `db_version` ( CREATE TABLE `db_version` (
`version` varchar(120) default NULL, `version` varchar(120) default NULL,
`required_7627_01_mangos_achievement_criteria_data` bit(1) default NULL `required_7633_01_mangos_achievement_criteria_data` bit(1) default NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Used DB version notes';
-- --
@ -46,7 +46,7 @@ CREATE TABLE `achievement_criteria_data` (
`type` tinyint(3) unsigned NOT NULL DEFAULT '0', `type` tinyint(3) unsigned NOT NULL DEFAULT '0',
`value1` mediumint(8) unsigned NOT NULL DEFAULT '0', `value1` mediumint(8) unsigned NOT NULL DEFAULT '0',
`value2` mediumint(8) unsigned NOT NULL DEFAULT '0', `value2` mediumint(8) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`criteria_id`) PRIMARY KEY (`criteria_id`,`type`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Achievment system'; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 ROW_FORMAT=FIXED COMMENT='Achievment system';
-- --

View file

@ -0,0 +1,5 @@
ALTER TABLE db_version CHANGE COLUMN required_7627_01_mangos_achievement_criteria_data required_7633_01_mangos_achievement_criteria_data bit;
ALTER TABLE `achievement_criteria_data`
DROP PRIMARY KEY,
ADD PRIMARY KEY (`criteria_id`,`type`);

View file

@ -218,6 +218,7 @@ pkgdata_DATA = \
7622_02_mangos_creature_ai_summons.sql \ 7622_02_mangos_creature_ai_summons.sql \
7622_03_mangos_creature_ai_texts.sql \ 7622_03_mangos_creature_ai_texts.sql \
7627_01_mangos_achievement_criteria_data.sql \ 7627_01_mangos_achievement_criteria_data.sql \
7633_01_mangos_achievement_criteria_data.sql \
README README
## Additional files to include when running 'make dist' ## Additional files to include when running 'make dist'
@ -416,4 +417,5 @@ EXTRA_DIST = \
7622_02_mangos_creature_ai_summons.sql \ 7622_02_mangos_creature_ai_summons.sql \
7622_03_mangos_creature_ai_texts.sql \ 7622_03_mangos_creature_ai_texts.sql \
7627_01_mangos_achievement_criteria_data.sql \ 7627_01_mangos_achievement_criteria_data.sql \
7633_01_mangos_achievement_criteria_data.sql \
README README

View file

@ -79,17 +79,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
switch(criteria->requiredType) switch(criteria->requiredType)
{ {
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
switch(dataType) case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
{
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; break;
default: default:
sLog.outErrorDb( "Table `achievement_criteria_data` have data for not supported criteria type (Entry: %u Type: %u), ignore.", criteria->ID, criteria->requiredType); sLog.outErrorDb( "Table `achievement_criteria_data` have data for not supported criteria type (Entry: %u Type: %u), ignore.", criteria->ID, criteria->requiredType);
@ -100,7 +90,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
{ {
case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE:
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE:
if(!creature.id || !objmgr.GetCreatureTemplate(creature.id)) 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.", 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.",
@ -108,7 +98,7 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
return false; return false;
} }
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE:
if(!classRace.class_id && !classRace.race_id) 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.", 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.",
@ -128,14 +118,48 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
return false; return false;
} }
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH:
if(health.percent < 1 || health.percent > 100) 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.", sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH (%u) have wrong percent value in value1 (%u), ignore.",
criteria->ID, criteria->requiredType,dataType,health.percent); criteria->ID, criteria->requiredType,dataType,health.percent);
return false; return false;
} }
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD:
return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
{
SpellEntry const* spellEntry = sSpellStore.LookupEntry(aura.spell_id);
if(!spellEntry)
{
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell id in value1 (%u), ignore.",
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);
return false;
}
if(aura.effect_idx >= 3)
{
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have wrong spell effect index in value2 (%u), ignore.",
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);
return false;
}
if(!spellEntry->EffectApplyAuraName[aura.effect_idx])
{
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type %s (%u) have non-aura spell effect (ID: %u Effect: %u), ignore.",
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);
return false;
}
return true;
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
if(!GetAreaEntryByAreaID(area.id))
{
sLog.outErrorDb( "Table `achievement_criteria_data` (Entry: %u Type: %u) for data type ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA (%u) have wrong area id in value1 (%u), ignore.",
criteria->ID, criteria->requiredType,dataType,area.id);
return false;
}
return true;
default: 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); 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;
@ -143,38 +167,56 @@ bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria)
return false; return false;
} }
bool AchievementCriteriaData::Meets( Unit const* target ) const bool AchievementCriteriaData::Meets(Player const* source, Unit const* target) const
{ {
if (!target)
return false;
switch(dataType) switch(dataType)
{ {
case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE:
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE:
if (target->GetTypeId()!=TYPEID_UNIT) if (!target || target->GetTypeId()!=TYPEID_UNIT)
return false; return false;
if (target->GetEntry() != creature.id) if (target->GetEntry() != creature.id)
return false; return false;
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE:
if (target->GetTypeId()!=TYPEID_PLAYER) if (!target || target->GetTypeId()!=TYPEID_PLAYER)
return false; return false;
if(classRace.class_id && classRace.class_id != ((Player*)target)->getClass()) if(classRace.class_id && classRace.class_id != ((Player*)target)->getClass())
return false; return false;
if(classRace.race_id && classRace.race_id != ((Player*)target)->getRace()) if(classRace.race_id && classRace.race_id != ((Player*)target)->getRace())
return false; return false;
return true; return true;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH: case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH:
if (target->GetTypeId()!=TYPEID_PLAYER) if (!target || target->GetTypeId()!=TYPEID_PLAYER)
return false; return false;
return target->GetHealth()*100 <= health.percent*target->GetMaxHealth(); return target->GetHealth()*100 <= health.percent*target->GetMaxHealth();
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD:
return target && target->GetTypeId() == TYPEID_PLAYER && !target->isAlive() && ((Player*)target)->GetDeathTimer() != 0;
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA:
return source->HasAura(aura.spell_id,aura.effect_idx);
case ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA:
{
uint32 zone_id,area_id;
source->GetZoneAndAreaId(zone_id,area_id);
return area.id==zone_id || area.id==area_id;
}
case ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA:
return target && target->HasAura(aura.spell_id,aura.effect_idx);
} }
return false; return false;
} }
bool AchievementCriteriaDataSet::Meets(Player const* source, Unit const* target) const
{
for(Storage::const_iterator itr = storage.begin(); itr != storage.end(); ++itr)
if(!itr->Meets(source,target))
return false;
return true;
}
AchievementMgr::AchievementMgr(Player *player) AchievementMgr::AchievementMgr(Player *player)
{ {
m_player = player; m_player = player;
@ -863,22 +905,18 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE:
{ {
// miscvalue1 = emote // miscvalue1 = emote
// miscvalue2 = achievement->ID for special requirement
if(!miscvalue1) if(!miscvalue1)
continue; continue;
if(miscvalue1 != achievementCriteria->do_emote.emoteID) if(miscvalue1 != achievementCriteria->do_emote.emoteID)
continue; continue;
if(achievementCriteria->do_emote.count) if(achievementCriteria->do_emote.count)
{ {
// harcoded case // those requirements couldn't be found in the dbc
if(achievement->ID==247) AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
{ if(!data)
if (!unit || unit->GetTypeId() != TYPEID_PLAYER || continue;
unit->isAlive() || ((Player*)unit)->GetDeathTimer() == 0)
continue; if(!data->Meets(GetPlayer(),unit))
}
// expected as scripted case
else if(!miscvalue2 || !achievement->ID != miscvalue2)
continue; continue;
} }
@ -949,11 +987,11 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
continue; continue;
// those requirements couldn't be found in the dbc // those requirements couldn't be found in the dbc
AchievementCriteriaData const* data = achievementmgr.GetCriteriaData(achievementCriteria); AchievementCriteriaDataSet const* data = achievementmgr.GetCriteriaDataSet(achievementCriteria);
if(!data) if(!data)
continue; continue;
if(!data->Meets(unit)) if(!data->Meets(GetPlayer(),unit))
continue; continue;
SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE); SetCriteriaProgress(achievementCriteria, 1, PROGRESS_ACCUMULATE);
@ -1478,7 +1516,14 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
if(!data.IsValid(criteria)) if(!data.IsValid(criteria))
continue; continue;
m_criteriaDataMap[criteria_id] = data; // this will allocate empty data set storage
AchievementCriteriaDataSet& dataSet = m_criteriaDataMap[criteria_id];
// add real data only for not NONE data types
if(data.dataType!=ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE)
dataSet.Add(data);
// counting data by and data types
++count; ++count;
} while(result->NextRow()); } while(result->NextRow());
@ -1494,7 +1539,11 @@ void AchievementGlobalMgr::LoadAchievementCriteriaData()
switch(criteria->requiredType) switch(criteria->requiredType)
{ {
case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2: case ACHIEVEMENT_CRITERIA_TYPE_CAST_SPELL2:
if(!GetCriteriaData(criteria)) if(!GetCriteriaDataSet(criteria))
sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType);
break;
case ACHIEVEMENT_CRITERIA_TYPE_DO_EMOTE: // need skip generic cases
if(criteria->do_emote.count && !GetCriteriaDataSet(criteria))
sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType); sLog.outErrorDb( "Table `achievement_criteria_data` not have expected data for for criteria (Entry: %u Type: %u).", criteria->ID, criteria->requiredType);
break; break;
default: // unexpected case processed in IsValid check default: // unexpected case processed in IsValid check

View file

@ -41,15 +41,20 @@ struct CriteriaProgress
}; };
enum AchievementCriteriaDataType enum AchievementCriteriaDataType
{ // value1 value2 for the Condition enumed { // value1 value2 comment
ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0 ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE = 0, // 0 0
ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE = 1, // creature_id ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE = 1, // creature_id 0
ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE = 2, // class_id race_id ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE = 2, // class_id race_id
ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH = 3, // health_percent ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH= 3, // health_percent 0
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_DEAD = 4, // 0 0 not corpse (not released body)
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA = 5, // spell_id effect_idx
ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA = 6, // area id 0
ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA = 7, // spell_id effect_idx
}; };
#define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 4 // maximum value in AchievementCriteriaDataType enum #define MAX_ACHIEVEMENT_CRITERIA_DATA_TYPE 8 // maximum value in AchievementCriteriaDataType enum
class Player;
class Unit; class Unit;
struct AchievementCriteriaData struct AchievementCriteriaData
@ -57,27 +62,39 @@ struct AchievementCriteriaData
AchievementCriteriaDataType dataType; AchievementCriteriaDataType dataType;
union union
{ {
// ACHIEVEMENT_CRITERIA_DATA_TYPE_CREATURE // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_CREATURE
struct struct
{ {
uint32 id; uint32 id;
} creature; } creature;
// ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_CLASS_RACE // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_CLASS_RACE
struct struct
{ {
uint32 class_id; uint32 class_id;
uint32 race_id; uint32 race_id;
} classRace; } classRace;
// ACHIEVEMENT_CRITERIA_DATA_TYPE_PLAYER_LESS_HEALTH // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_PLAYER_LESS_HEALTH
struct struct
{ {
uint32 percent; uint32 percent;
} health; } health;
// ACHIEVEMENT_CRITERIA_DATA_TYPE_NONE // ACHIEVEMENT_CRITERIA_DATA_TYPE_T_AURA
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AURA
struct struct
{ {
uint32 value1; uint32 spell_id;
uint32 value2; uint32 effect_idx;
} aura;
// ACHIEVEMENT_CRITERIA_DATA_TYPE_S_AREA
struct
{
uint32 id;
} area;
// ...
struct
{
uint32 value1;
uint32 value2;
} raw; } raw;
}; };
@ -94,11 +111,20 @@ struct AchievementCriteriaData
} }
bool IsValid(AchievementCriteriaEntry const* criteria); bool IsValid(AchievementCriteriaEntry const* criteria);
// Checks correctness of values bool Meets(Player const* source, Unit const* target) const;
bool Meets(Unit const* target) const;// Checks if the target meets the requirement
}; };
typedef std::map<uint32,AchievementCriteriaData> AchievementCriteriaDataMap; struct AchievementCriteriaDataSet
{
typedef std::vector<AchievementCriteriaData> Storage;
void Add(AchievementCriteriaData const& data) { storage.push_back(data); }
bool Meets(Player const* source, Unit const* target) const;
private:
Storage storage;
};
typedef std::map<uint32,AchievementCriteriaDataSet> AchievementCriteriaDataMap;
struct AchievementReward struct AchievementReward
{ {
@ -194,7 +220,7 @@ class AchievementGlobalMgr
return iter!=m_achievementRewardLocales.end() ? &iter->second : NULL; return iter!=m_achievementRewardLocales.end() ? &iter->second : NULL;
} }
AchievementCriteriaData const* GetCriteriaData(AchievementCriteriaEntry const *achievementCriteria) AchievementCriteriaDataSet const* GetCriteriaDataSet(AchievementCriteriaEntry const *achievementCriteria)
{ {
AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID); AchievementCriteriaDataMap::const_iterator iter = m_criteriaDataMap.find(achievementCriteria->ID);
return iter!=m_criteriaDataMap.end() ? &iter->second : NULL; return iter!=m_criteriaDataMap.end() ? &iter->second : NULL;

View file

@ -1,4 +1,4 @@
#ifndef __REVISION_NR_H__ #ifndef __REVISION_NR_H__
#define __REVISION_NR_H__ #define __REVISION_NR_H__
#define REVISION_NR "7632" #define REVISION_NR "7633"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__