mirror of
https://github.com/mangosfour/server.git
synced 2025-12-20 16:37:04 +00:00
[10352] Implement support explcitly started timed achievements.
* Player::StartTimedAchievementCriteria can be used for activate timer for specific explicitly starting timed achievement by timedRequirementId in script. * for ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST this done in core. Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
parent
64fe2cf3ed
commit
12aa1bc606
8 changed files with 113 additions and 19 deletions
|
|
@ -703,6 +703,70 @@ static const uint32 achievIdForDangeon[][4] =
|
||||||
static const uint32 achievIdByClass[MAX_CLASSES] = { 0, 459, 465 , 462, 458, 464, 461, 467, 460, 463, 0, 466 };
|
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 };
|
static const uint32 achievIdByRace[MAX_RACES] = { 0, 1408, 1410, 1407, 1409, 1413, 1411, 1404, 1412, 0, 1405, 1406 };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this function will be called whenever the user might have done a timed-criteria relevant action, or by scripting side?
|
||||||
|
*/
|
||||||
|
void AchievementMgr::StartTimedAchievementCriteria(AchievementCriteriaTypes type, uint32 timedRequirementId, time_t startTime /*= 0*/)
|
||||||
|
{
|
||||||
|
DETAIL_FILTER_LOG(LOG_FILTER_ACHIEVEMENT_UPDATES, "AchievementMgr::StartTimedAchievementCriteria(%u, %u)", type, timedRequirementId);
|
||||||
|
|
||||||
|
if (!sWorld.getConfig(CONFIG_BOOL_GM_ALLOW_ACHIEVEMENT_GAINS) && m_player->GetSession()->GetSecurity() > SEC_PLAYER)
|
||||||
|
return;
|
||||||
|
|
||||||
|
AchievementCriteriaEntryList const& achievementCriteriaList = sAchievementMgr.GetAchievementCriteriaByType(type);
|
||||||
|
for(AchievementCriteriaEntryList::const_iterator i = achievementCriteriaList.begin(); i!=achievementCriteriaList.end(); ++i)
|
||||||
|
{
|
||||||
|
AchievementCriteriaEntry const *achievementCriteria = (*i);
|
||||||
|
|
||||||
|
// only apply to specific timedRequirementId related criteria
|
||||||
|
if (achievementCriteria->timedCriteriaMiscId != timedRequirementId)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!achievementCriteria->IsExplicitlyStartedTimedCriteria())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (achievementCriteria->groupFlag & ACHIEVEMENT_CRITERIA_GROUP_NOT_IN_GROUP && GetPlayer()->GetGroup())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AchievementEntry const *achievement = sAchievementStore.LookupEntry(achievementCriteria->referredAchievement);
|
||||||
|
if (!achievement)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_HORDE && GetPlayer()->GetTeam() != HORDE) ||
|
||||||
|
(achievement->factionFlag == ACHIEVEMENT_FACTION_FLAG_ALLIANCE && GetPlayer()->GetTeam() != ALLIANCE))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// don't update already completed criteria
|
||||||
|
if (IsCompletedCriteria(achievementCriteria,achievement))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// if we have additional DB criteria, they must be met to start the criteria
|
||||||
|
AchievementCriteriaRequirementSet const* data = sAchievementMgr.GetCriteriaRequirementSet(achievementCriteria);
|
||||||
|
if (data && !data->Meets(GetPlayer(), NULL)) // TODO this might need more research, if this could be the player, or we also need to pass an unit
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// do not start already failed timers
|
||||||
|
if (startTime && time_t(startTime + achievementCriteria->timeLimit) < time(NULL))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CriteriaProgress* progress = NULL;
|
||||||
|
|
||||||
|
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(achievementCriteria->ID);
|
||||||
|
if (iter == m_criteriaProgress.end())
|
||||||
|
progress = &m_criteriaProgress[achievementCriteria->ID];
|
||||||
|
else
|
||||||
|
progress = &iter->second;
|
||||||
|
|
||||||
|
progress->changed = true;
|
||||||
|
progress->counter = 0;
|
||||||
|
|
||||||
|
// Start with given startTime or now
|
||||||
|
progress->date = startTime ? startTime : time(NULL);
|
||||||
|
|
||||||
|
SendCriteriaUpdate(achievementCriteria->ID, progress);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* this function will be called whenever the user might have done a criteria relevant action
|
* this function will be called whenever the user might have done a criteria relevant action
|
||||||
*/
|
*/
|
||||||
|
|
@ -1102,9 +1166,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
||||||
switch(achievement->ID)
|
switch(achievement->ID)
|
||||||
{
|
{
|
||||||
case 31:
|
case 31:
|
||||||
case 1275:
|
//case 1275: // these timed achievements have to be "started" on Quest Accecpt
|
||||||
case 1276:
|
//case 1276:
|
||||||
case 1277:
|
//case 1277:
|
||||||
case 1282:
|
case 1282:
|
||||||
case 1789:
|
case 1789:
|
||||||
{
|
{
|
||||||
|
|
@ -1812,17 +1876,21 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
||||||
|
|
||||||
CriteriaProgress *progress = NULL;
|
CriteriaProgress *progress = NULL;
|
||||||
uint32 old_value = 0;
|
uint32 old_value = 0;
|
||||||
|
uint32 newValue = 0;
|
||||||
|
|
||||||
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(criteria->ID);
|
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(criteria->ID);
|
||||||
|
|
||||||
if(iter == m_criteriaProgress.end())
|
if(iter == m_criteriaProgress.end())
|
||||||
{
|
{
|
||||||
// not create record for 0 counter
|
// not create record for 0 counter
|
||||||
if(changeValue == 0)
|
if(changeValue == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// not start manually started timed achievements - must be same check as below (ie possible on player logout between start and finish)
|
||||||
|
if (criteria->IsExplicitlyStartedTimedCriteria())
|
||||||
|
return;
|
||||||
|
|
||||||
progress = &m_criteriaProgress[criteria->ID];
|
progress = &m_criteriaProgress[criteria->ID];
|
||||||
progress->counter = changeValue;
|
newValue = changeValue;
|
||||||
progress->date = time(NULL);
|
progress->date = time(NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
@ -1830,8 +1898,6 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
||||||
progress = &iter->second;
|
progress = &iter->second;
|
||||||
|
|
||||||
old_value = progress->counter;
|
old_value = progress->counter;
|
||||||
|
|
||||||
uint32 newValue = 0;
|
|
||||||
switch(ptype)
|
switch(ptype)
|
||||||
{
|
{
|
||||||
case PROGRESS_SET:
|
case PROGRESS_SET:
|
||||||
|
|
@ -1851,8 +1917,6 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
||||||
// not update (not mark as changed) if counter will have same value
|
// not update (not mark as changed) if counter will have same value
|
||||||
if(progress->counter == newValue)
|
if(progress->counter == newValue)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
progress->counter = newValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
progress->changed = true;
|
progress->changed = true;
|
||||||
|
|
@ -1860,12 +1924,24 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
||||||
if(criteria->timeLimit)
|
if(criteria->timeLimit)
|
||||||
{
|
{
|
||||||
time_t now = time(NULL);
|
time_t now = time(NULL);
|
||||||
if(time_t(progress->date + criteria->timeLimit) < now)
|
|
||||||
progress->counter = 1;
|
|
||||||
|
|
||||||
// also it seems illogical, the timeframe will be extended at every criteria update
|
// too later, need restart from 1 auto-started or just fail explcit started
|
||||||
|
if (time_t(progress->date + criteria->timeLimit) < now)
|
||||||
|
{
|
||||||
|
// Do not reset timer for requirements that are started manually, also reset their counter, same check as above
|
||||||
|
if (criteria->IsExplicitlyStartedTimedCriteria())
|
||||||
|
newValue = 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
newValue = 1;
|
||||||
|
// This is used as start time of the achievement, and hence only updated on fail
|
||||||
progress->date = now;
|
progress->date = now;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
progress->counter = newValue;
|
||||||
|
progress->changed = true;
|
||||||
|
|
||||||
// update client side value
|
// update client side value
|
||||||
SendCriteriaUpdate(criteria->ID,progress);
|
SendCriteriaUpdate(criteria->ID,progress);
|
||||||
|
|
|
||||||
|
|
@ -248,6 +248,7 @@ class AchievementMgr
|
||||||
void LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult);
|
void LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult);
|
||||||
void SaveToDB();
|
void SaveToDB();
|
||||||
void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0);
|
void ResetAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0);
|
||||||
|
void StartTimedAchievementCriteria(AchievementCriteriaTypes type, uint32 timedRequirementId, time_t startTime = 0);
|
||||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
|
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
|
||||||
void CheckAllAchievementCriteria();
|
void CheckAllAchievementCriteria();
|
||||||
void SendAllAchievementData();
|
void SendAllAchievementData();
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,7 @@ struct AchievementCriteriaEntry
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
uint32 field3; // 3 main requirement
|
uint32 value; // 3 main requirement
|
||||||
uint32 count; // 4 main requirement count
|
uint32 count; // 4 main requirement count
|
||||||
uint32 additionalRequirement1_type; // 5 additional requirement 1 type
|
uint32 additionalRequirement1_type; // 5 additional requirement 1 type
|
||||||
uint32 additionalRequirement1_value; // 6 additional requirement 1 value
|
uint32 additionalRequirement1_value; // 6 additional requirement 1 value
|
||||||
|
|
@ -493,11 +493,19 @@ struct AchievementCriteriaEntry
|
||||||
//uint32 name_flags; // 25
|
//uint32 name_flags; // 25
|
||||||
uint32 completionFlag; // 26
|
uint32 completionFlag; // 26
|
||||||
uint32 groupFlag; // 27
|
uint32 groupFlag; // 27
|
||||||
//uint32 unk1; // 28 Alway appears with timed events
|
uint32 timedCriteriaMiscId; // 28 Alway appears with timed events, used internally to start the achievement, store
|
||||||
// for timed spells it is spell id for
|
|
||||||
// timed kills it is creature id
|
|
||||||
uint32 timeLimit; // 29 time limit in seconds
|
uint32 timeLimit; // 29 time limit in seconds
|
||||||
uint32 showOrder; // 30 show order, also used in achievement shift-links as index in state bitmask
|
uint32 showOrder; // 30 show order, also used in achievement shift-links as index in state bitmask
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
bool IsExplicitlyStartedTimedCriteria() const
|
||||||
|
{
|
||||||
|
if (!timeLimit)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// in case raw.value == timedCriteriaMiscId in timedCriteriaMiscId stored spellid/itemids for cast/use, so repeating aura start at first cast/use until fails
|
||||||
|
return requiredType == ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST || raw.value != timedCriteriaMiscId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AreaTableEntry
|
struct AreaTableEntry
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
#define MANGOS_DBCSFRM_H
|
#define MANGOS_DBCSFRM_H
|
||||||
|
|
||||||
const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
||||||
const char AchievementCriteriafmt[]="niiiiiiiissssssssssssssssxiixii";
|
const char AchievementCriteriafmt[]="niiiiiiiissssssssssssssssxiiiii";
|
||||||
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
|
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
|
||||||
const char AreaGroupEntryfmt[]="niiiiiii";
|
const char AreaGroupEntryfmt[]="niiiiiii";
|
||||||
const char AreaTriggerEntryfmt[]="niffffffff";
|
const char AreaTriggerEntryfmt[]="niffffffff";
|
||||||
|
|
|
||||||
|
|
@ -21331,6 +21331,11 @@ void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 mi
|
||||||
GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time);
|
GetAchievementMgr().UpdateAchievementCriteria(type, miscvalue1,miscvalue2,unit,time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::StartTimedAchievementCriteria(AchievementCriteriaTypes type, uint32 timedRequirementId, time_t startTime /*= 0*/)
|
||||||
|
{
|
||||||
|
GetAchievementMgr().StartTimedAchievementCriteria(type, timedRequirementId, startTime);
|
||||||
|
}
|
||||||
|
|
||||||
PlayerTalent const* Player::GetKnownTalentById(int32 talentId) const
|
PlayerTalent const* Player::GetKnownTalentById(int32 talentId) const
|
||||||
{
|
{
|
||||||
PlayerTalentMap::const_iterator itr = m_talents[m_activeSpec].find(talentId);
|
PlayerTalentMap::const_iterator itr = m_talents[m_activeSpec].find(talentId);
|
||||||
|
|
|
||||||
|
|
@ -2385,6 +2385,8 @@ class MANGOS_DLL_SPEC Player : public Unit
|
||||||
AchievementMgr const& GetAchievementMgr() const { return m_achievementMgr; }
|
AchievementMgr const& GetAchievementMgr() const { return m_achievementMgr; }
|
||||||
AchievementMgr& GetAchievementMgr() { return m_achievementMgr; }
|
AchievementMgr& GetAchievementMgr() { return m_achievementMgr; }
|
||||||
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
|
void UpdateAchievementCriteria(AchievementCriteriaTypes type, uint32 miscvalue1=0, uint32 miscvalue2=0, Unit *unit=NULL, uint32 time=0);
|
||||||
|
void StartTimedAchievementCriteria(AchievementCriteriaTypes type, uint32 timedRequirementId, time_t startTime = 0);
|
||||||
|
|
||||||
|
|
||||||
bool HasTitle(uint32 bitIndex);
|
bool HasTitle(uint32 bitIndex);
|
||||||
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
|
bool HasTitle(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
|
||||||
|
|
|
||||||
|
|
@ -189,6 +189,8 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket & recv_data )
|
||||||
if ( _player->CanCompleteQuest( quest ) )
|
if ( _player->CanCompleteQuest( quest ) )
|
||||||
_player->CompleteQuest( quest );
|
_player->CompleteQuest( quest );
|
||||||
|
|
||||||
|
_player->GetAchievementMgr().StartTimedAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest);
|
||||||
|
|
||||||
switch(pObject->GetTypeId())
|
switch(pObject->GetTypeId())
|
||||||
{
|
{
|
||||||
case TYPEID_UNIT:
|
case TYPEID_UNIT:
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#ifndef __REVISION_NR_H__
|
#ifndef __REVISION_NR_H__
|
||||||
#define __REVISION_NR_H__
|
#define __REVISION_NR_H__
|
||||||
#define REVISION_NR "10351"
|
#define REVISION_NR "10352"
|
||||||
#endif // __REVISION_NR_H__
|
#endif // __REVISION_NR_H__
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue