mirror of
https://github.com/mangosfour/server.git
synced 2025-12-20 07:37:02 +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 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
|
||||
*/
|
||||
|
|
@ -1102,9 +1166,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui
|
|||
switch(achievement->ID)
|
||||
{
|
||||
case 31:
|
||||
case 1275:
|
||||
case 1276:
|
||||
case 1277:
|
||||
//case 1275: // these timed achievements have to be "started" on Quest Accecpt
|
||||
//case 1276:
|
||||
//case 1277:
|
||||
case 1282:
|
||||
case 1789:
|
||||
{
|
||||
|
|
@ -1812,17 +1876,21 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
|||
|
||||
CriteriaProgress *progress = NULL;
|
||||
uint32 old_value = 0;
|
||||
uint32 newValue = 0;
|
||||
|
||||
CriteriaProgressMap::iterator iter = m_criteriaProgress.find(criteria->ID);
|
||||
|
||||
if(iter == m_criteriaProgress.end())
|
||||
{
|
||||
// not create record for 0 counter
|
||||
if(changeValue == 0)
|
||||
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->counter = changeValue;
|
||||
newValue = changeValue;
|
||||
progress->date = time(NULL);
|
||||
}
|
||||
else
|
||||
|
|
@ -1830,8 +1898,6 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
|||
progress = &iter->second;
|
||||
|
||||
old_value = progress->counter;
|
||||
|
||||
uint32 newValue = 0;
|
||||
switch(ptype)
|
||||
{
|
||||
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
|
||||
if(progress->counter == newValue)
|
||||
return;
|
||||
|
||||
progress->counter = newValue;
|
||||
}
|
||||
|
||||
progress->changed = true;
|
||||
|
|
@ -1860,12 +1924,24 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
|
|||
if(criteria->timeLimit)
|
||||
{
|
||||
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->counter = newValue;
|
||||
progress->changed = true;
|
||||
|
||||
// update client side value
|
||||
SendCriteriaUpdate(criteria->ID,progress);
|
||||
|
|
|
|||
|
|
@ -248,6 +248,7 @@ class AchievementMgr
|
|||
void LoadFromDB(QueryResult *achievementResult, QueryResult *criteriaResult);
|
||||
void SaveToDB();
|
||||
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 CheckAllAchievementCriteria();
|
||||
void SendAllAchievementData();
|
||||
|
|
|
|||
|
|
@ -481,7 +481,7 @@ struct AchievementCriteriaEntry
|
|||
|
||||
struct
|
||||
{
|
||||
uint32 field3; // 3 main requirement
|
||||
uint32 value; // 3 main requirement
|
||||
uint32 count; // 4 main requirement count
|
||||
uint32 additionalRequirement1_type; // 5 additional requirement 1 type
|
||||
uint32 additionalRequirement1_value; // 6 additional requirement 1 value
|
||||
|
|
@ -493,11 +493,19 @@ struct AchievementCriteriaEntry
|
|||
//uint32 name_flags; // 25
|
||||
uint32 completionFlag; // 26
|
||||
uint32 groupFlag; // 27
|
||||
//uint32 unk1; // 28 Alway appears with timed events
|
||||
// for timed spells it is spell id for
|
||||
// timed kills it is creature id
|
||||
uint32 timedCriteriaMiscId; // 28 Alway appears with timed events, used internally to start the achievement, store
|
||||
uint32 timeLimit; // 29 time limit in seconds
|
||||
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
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
#define MANGOS_DBCSFRM_H
|
||||
|
||||
const char Achievementfmt[]="niixssssssssssssssssxxxxxxxxxxxxxxxxxxiixixxxxxxxxxxxxxxxxxxii";
|
||||
const char AchievementCriteriafmt[]="niiiiiiiissssssssssssssssxiixii";
|
||||
const char AchievementCriteriafmt[]="niiiiiiiissssssssssssssssxiiiii";
|
||||
const char AreaTableEntryfmt[]="iiinixxxxxissssssssssssssssxixxxxxxx";
|
||||
const char AreaGroupEntryfmt[]="niiiiiii";
|
||||
const char AreaTriggerEntryfmt[]="niffffffff";
|
||||
|
|
|
|||
|
|
@ -21331,6 +21331,11 @@ void Player::UpdateAchievementCriteria( AchievementCriteriaTypes type, uint32 mi
|
|||
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
|
||||
{
|
||||
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& GetAchievementMgr() { return m_achievementMgr; }
|
||||
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(CharTitlesEntry const* title) { return HasTitle(title->bit_index); }
|
||||
|
|
|
|||
|
|
@ -189,6 +189,8 @@ void WorldSession::HandleQuestgiverAcceptQuestOpcode( WorldPacket & recv_data )
|
|||
if ( _player->CanCompleteQuest( quest ) )
|
||||
_player->CompleteQuest( quest );
|
||||
|
||||
_player->GetAchievementMgr().StartTimedAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_QUEST, quest);
|
||||
|
||||
switch(pObject->GetTypeId())
|
||||
{
|
||||
case TYPEID_UNIT:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __REVISION_NR_H__
|
||||
#define __REVISION_NR_H__
|
||||
#define REVISION_NR "10351"
|
||||
#define REVISION_NR "10352"
|
||||
#endif // __REVISION_NR_H__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue