[10667] Timed Achievements, Fail-Support and Opcodes

Signed-off-by: VladimirMangos <vladimir@getmangos.com>
This commit is contained in:
Schmoozerd 2010-11-01 05:44:32 +03:00 committed by VladimirMangos
parent e78887e964
commit ef5ea6f24f
4 changed files with 104 additions and 37 deletions

View file

@ -523,8 +523,15 @@ void AchievementMgr::SaveToDB()
ssdel << iter->first; ssdel << iter->first;
} }
// store data only for real progress // store data only for real progress, exceptions are timedCriterias, they are also stored for counter == 0
if(iter->second.counter != 0) bool needSave = iter->second.counter != 0;
if (!needSave)
{
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(iter->first);
needSave = criteria && criteria->timeLimit > 0;
}
if (needSave)
{ {
/// first new/changed record prefix /// first new/changed record prefix
if(!need_execute_ins) if(!need_execute_ins)
@ -597,13 +604,27 @@ void AchievementMgr::LoadFromDB(QueryResult *achievementResult, QueryResult *cri
continue; continue;
} }
if (criteria->timeLimit && time_t(date + criteria->timeLimit) < time(NULL))
continue;
CriteriaProgress& progress = m_criteriaProgress[id]; CriteriaProgress& progress = m_criteriaProgress[id];
progress.counter = counter; progress.counter = counter;
progress.date = date; progress.date = date;
progress.changed = false; progress.changed = false;
progress.timedCriteriaFailed = false;
// A failed achievement will be removed on next tick - TODO: Possible that timer 2 is reseted
if (criteria->timeLimit)
{
AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->referredAchievement);
// Add not-completed achievements to time map
if (!IsCompletedCriteria(criteria, achievement))
{
time_t failTime = time_t(progress.date + criteria->timeLimit);
m_criteriaFailTimes[criteria->ID] = failTime;
// A failed Achievement - will be removed by DoFailedTimedAchievementCriterias on next tick for player
if (failTime <= time(NULL))
progress.timedCriteriaFailed = true;
}
}
// check intergiry with max allowed counter value // check intergiry with max allowed counter value
if (uint32 maxcounter = GetCriteriaProgressMaxCounter(criteria)) if (uint32 maxcounter = GetCriteriaProgressMaxCounter(criteria))
@ -667,14 +688,15 @@ void AchievementMgr::SendCriteriaUpdate(uint32 id, CriteriaProgress const* progr
WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8); WorldPacket data(SMSG_CRITERIA_UPDATE, 8+4+8);
data << uint32(id); data << uint32(id);
time_t now = time(NULL);
// the counter is packed like a packed Guid // the counter is packed like a packed Guid
data.appendPackGUID(progress->counter); data.appendPackGUID(progress->counter);
data << GetPlayer()->GetPackGUID(); data << GetPlayer()->GetPackGUID();
data << uint32(0); data << uint32(progress->timedCriteriaFailed ? 1 : 0);
data << uint32(secsToTimeBitFields(progress->date)); data << uint32(secsToTimeBitFields(now));
data << uint32(0); // timer 1 data << uint32(now - progress->date); // timer 1
data << uint32(0); // timer 2 data << uint32(now - progress->date); // timer 2
GetPlayer()->SendDirectMessage(&data); GetPlayer()->SendDirectMessage(&data);
} }
@ -758,11 +780,58 @@ void AchievementMgr::StartTimedAchievementCriteria(AchievementCriteriaTypes type
// Start with given startTime or now // Start with given startTime or now
progress->date = startTime ? startTime : time(NULL); progress->date = startTime ? startTime : time(NULL);
progress->timedCriteriaFailed = false;
// Add to timer map
m_criteriaFailTimes[achievementCriteria->ID] = time_t(progress->date + achievementCriteria->timeLimit);
SendCriteriaUpdate(achievementCriteria->ID, progress); SendCriteriaUpdate(achievementCriteria->ID, progress);
} }
} }
/**
* this function will be called whenever there could be a timed achievement criteria failed because of ellapsed time
*/
void AchievementMgr::DoFailedTimedAchievementCriterias()
{
if (m_criteriaFailTimes.empty())
return;
time_t now = time(NULL);
for (AchievementCriteriaFailTimeMap::iterator iter = m_criteriaFailTimes.begin(); iter != m_criteriaFailTimes.end();)
{
if (iter->second > now)
{
++iter;
continue;
}
// Possible failed achievement criteria found
AchievementCriteriaEntry const* criteria = sAchievementCriteriaStore.LookupEntry(iter->first);
AchievementEntry const* achievement = sAchievementStore.LookupEntry(criteria->referredAchievement);
// Send Fail for failed criterias
if (!IsCompletedCriteria(criteria, achievement))
{
DETAIL_FILTER_LOG(LOG_FILTER_ACHIEVEMENT_UPDATES, "AchievementMgr::DoFailedTimedAchievementCriterias for criteria %u", criteria->ID);
CriteriaProgressMap::iterator pro_iter = m_criteriaProgress.find(criteria->ID);
MANGOS_ASSERT(pro_iter != m_criteriaProgress.end());
CriteriaProgress* progress = &pro_iter->second;
// Set to failed, and send to client
progress->timedCriteriaFailed = true;
SendCriteriaUpdate(criteria->ID, progress);
// Remove failed progress
m_criteriaProgress.erase(pro_iter);
}
iter = m_criteriaFailTimes.erase(iter);
}
}
/** /**
* 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
*/ */
@ -1902,13 +1971,24 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
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) // not start manually started timed achievements
if (criteria->IsExplicitlyStartedTimedCriteria()) if (criteria->IsExplicitlyStartedTimedCriteria())
return; return;
progress = &m_criteriaProgress[criteria->ID]; progress = &m_criteriaProgress[criteria->ID];
newValue = changeValue;
progress->date = time(NULL); progress->date = time(NULL);
progress->timedCriteriaFailed = false;
// timed criterias are added to fail-timer map, and send the starting with counter=0
if (criteria->timeLimit)
{
m_criteriaFailTimes[criteria->ID] = time_t(progress->date + criteria->timeLimit);
progress->counter = 0;
SendCriteriaUpdate(criteria->ID, progress);
}
newValue = changeValue;
} }
else else
{ {
@ -1936,27 +2016,6 @@ void AchievementMgr::SetCriteriaProgress(AchievementCriteriaEntry const* criteri
return; return;
} }
progress->changed = true;
if(criteria->timeLimit)
{
time_t now = time(NULL);
// 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->counter = newValue;
progress->changed = true; progress->changed = true;
@ -2144,15 +2203,16 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket *data)
} }
*data << int32(-1); *data << int32(-1);
time_t now = time(NULL);
for(CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter) for(CriteriaProgressMap::const_iterator iter = m_criteriaProgress.begin(); iter!=m_criteriaProgress.end(); ++iter)
{ {
*data << uint32(iter->first); *data << uint32(iter->first);
data->appendPackGUID(iter->second.counter); data->appendPackGUID(iter->second.counter);
*data << GetPlayer()->GetPackGUID(); *data << GetPlayer()->GetPackGUID();
*data << uint32(0); *data << uint32(iter->second.timedCriteriaFailed ? 1 : 0);
*data << uint32(secsToTimeBitFields(iter->second.date)); *data << uint32(secsToTimeBitFields(now));
*data << uint32(0); *data << uint32(now - iter->second.date);
*data << uint32(0); *data << uint32(now - iter->second.date);
} }
*data << int32(-1); *data << int32(-1);

View file

@ -33,12 +33,14 @@ typedef std::list<AchievementEntry const*> AchievementEntryList;
typedef std::map<uint32,AchievementCriteriaEntryList> AchievementCriteriaListByAchievement; typedef std::map<uint32,AchievementCriteriaEntryList> AchievementCriteriaListByAchievement;
typedef std::map<uint32,AchievementEntryList> AchievementListByReferencedId; typedef std::map<uint32,AchievementEntryList> AchievementListByReferencedId;
typedef std::map<uint32,time_t> AchievementCriteriaFailTimeMap;
struct CriteriaProgress struct CriteriaProgress
{ {
uint32 counter; uint32 counter;
time_t date; time_t date;
bool changed; bool changed;
bool timedCriteriaFailed;
}; };
enum AchievementCriteriaRequirementType enum AchievementCriteriaRequirementType
@ -250,6 +252,7 @@ class AchievementMgr
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 StartTimedAchievementCriteria(AchievementCriteriaTypes type, uint32 timedRequirementId, time_t startTime = 0);
void DoFailedTimedAchievementCriterias();
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();
@ -292,6 +295,7 @@ class AchievementMgr
Player* m_player; Player* m_player;
CriteriaProgressMap m_criteriaProgress; CriteriaProgressMap m_criteriaProgress;
CompletedAchievementMap m_completedAchievements; CompletedAchievementMap m_completedAchievements;
AchievementCriteriaFailTimeMap m_criteriaFailTimes;
}; };
class AchievementGlobalMgr class AchievementGlobalMgr

View file

@ -1180,6 +1180,9 @@ void Player::Update( uint32 p_time )
if(!IsInWorld()) if(!IsInWorld())
return; return;
// remove failed timed Achievements
GetAchievementMgr().DoFailedTimedAchievementCriterias();
// undelivered mail // undelivered mail
if(m_nextMailDelivereTime && m_nextMailDelivereTime <= time(NULL)) if(m_nextMailDelivereTime && m_nextMailDelivereTime <= time(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 "10666" #define REVISION_NR "10667"
#endif // __REVISION_NR_H__ #endif // __REVISION_NR_H__