aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sql/updates/characters/2012_12_03_00_character_character_queststatus_monthly.sql8
-rw-r--r--src/server/game/Entities/Player/Player.cpp144
-rw-r--r--src/server/game/Entities/Player/Player.h72
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp9
-rw-r--r--src/server/game/Handlers/CharacterHandler.cpp72
-rw-r--r--src/server/game/Quests/QuestDef.h6
-rw-r--r--src/server/game/World/World.cpp68
-rw-r--r--src/server/game/World/World.h10
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.cpp4
-rw-r--r--src/server/shared/Database/Implementation/CharacterDatabase.h4
10 files changed, 289 insertions, 108 deletions
diff --git a/sql/updates/characters/2012_12_03_00_character_character_queststatus_monthly.sql b/sql/updates/characters/2012_12_03_00_character_character_queststatus_monthly.sql
new file mode 100644
index 00000000000..256bb1f7ad6
--- /dev/null
+++ b/sql/updates/characters/2012_12_03_00_character_character_queststatus_monthly.sql
@@ -0,0 +1,8 @@
+DROP TABLE IF EXISTS `character_queststatus_monthly`;
+
+CREATE TABLE IF NOT EXISTS `character_queststatus_monthly` (
+ `guid` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Global Unique Identifier',
+ `quest` INT(10) UNSIGNED NOT NULL DEFAULT '0' COMMENT 'Quest Identifier',
+ PRIMARY KEY (`guid`,`quest`),
+ KEY `idx_guid` (`guid`)
+) ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='Player System';
diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp
index 3a562ca09b1..6c3434df14f 100644
--- a/src/server/game/Entities/Player/Player.cpp
+++ b/src/server/game/Entities/Player/Player.cpp
@@ -14705,11 +14705,11 @@ Quest const* Player::GetNextQuest(uint64 guid, Quest const* quest)
bool Player::CanSeeStartQuest(Quest const* quest)
{
- if (SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) && SatisfyQuestSkill(quest, false) &&
- SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
+ if (!DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this) && SatisfyQuestClass(quest, false) && SatisfyQuestRace(quest, false) &&
+ SatisfyQuestSkill(quest, false) && SatisfyQuestExclusiveGroup(quest, false) && SatisfyQuestReputation(quest, false) &&
SatisfyQuestPreviousQuest(quest, false) && SatisfyQuestNextChain(quest, false) &&
SatisfyQuestPrevChain(quest, false) && SatisfyQuestDay(quest, false) && SatisfyQuestWeek(quest, false) &&
- SatisfyQuestSeasonal(quest, false) && !DisableMgr::IsDisabledFor(DISABLE_TYPE_QUEST, quest->GetQuestId(), this))
+ SatisfyQuestMonth(quest, false) && SatisfyQuestSeasonal(quest, false))
{
return getLevel() + sWorld->getIntConfig(CONFIG_QUEST_HIGH_LEVEL_HIDE_DIFF) >= quest->GetMinLevel();
}
@@ -14726,7 +14726,7 @@ bool Player::CanTakeQuest(Quest const* quest, bool msg)
&& SatisfyQuestPreviousQuest(quest, msg) && SatisfyQuestTimed(quest, msg)
&& SatisfyQuestNextChain(quest, msg) && SatisfyQuestPrevChain(quest, msg)
&& SatisfyQuestDay(quest, msg) && SatisfyQuestWeek(quest, msg)
- && SatisfyQuestSeasonal(quest,msg)
+ && SatisfyQuestMonth(quest, msg) && SatisfyQuestSeasonal(quest, msg)
&& SatisfyQuestConditions(quest, msg);
}
@@ -14850,7 +14850,7 @@ bool Player::CanRewardQuest(Quest const* quest, bool msg)
return false;
// daily quest can't be rewarded (25 daily quest already completed)
- if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true) || !SatisfyQuestSeasonal(quest,true))
+ if (!SatisfyQuestDay(quest, true) || !SatisfyQuestWeek(quest, true) || !SatisfyQuestMonth(quest, true) || !SatisfyQuestSeasonal(quest, true))
return false;
// rewarded and not repeatable quest (only cheating case, then ignore without message)
@@ -15148,6 +15148,8 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver,
}
else if (quest->IsWeekly())
SetWeeklyQuestStatus(quest_id);
+ else if (quest->IsMonthly())
+ SetMonthlyQuestStatus(quest_id);
else if (quest->IsSeasonal())
SetSeasonalQuestStatus(quest_id);
@@ -15601,6 +15603,15 @@ bool Player::SatisfyQuestSeasonal(Quest const* qInfo, bool /*msg*/)
return m_seasonalquests[eventId].find(qInfo->GetQuestId()) == m_seasonalquests[eventId].end();
}
+bool Player::SatisfyQuestMonth(Quest const* qInfo, bool /*msg*/)
+{
+ if (!qInfo->IsMonthly() || m_monthlyquests.empty())
+ return true;
+
+ // if not found in cooldown list
+ return m_monthlyquests.find(qInfo->GetQuestId()) == m_monthlyquests.end();
+}
+
bool Player::GiveQuestSourceItem(Quest const* quest)
{
uint32 srcitem = quest->GetSrcItemId();
@@ -16664,8 +16675,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
//"arenaPoints, totalHonorPoints, todayHonorPoints, yesterdayHonorPoints, totalKills, todayKills, yesterdayKills, chosenTitle, knownCurrencies, watchedFaction, drunk, "
// 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
//"health, power1, power2, power3, power4, power5, power6, power7, instance_id, speccount, activespec, exploredZones, equipmentCache, ammoId, knownTitles, actionBars, grantableLevels FROM characters WHERE guid = '%u'", guid);
- PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADFROM);
-
+ PreparedQueryResult result = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_FROM);
if (!result)
{
sLog->outError(LOG_FILTER_PLAYER, "Player (GUID: %u) not found in table `characters`, can't load. ", guid);
@@ -16684,7 +16694,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
return false;
}
- if (holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADBANNED))
+ if (holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BANNED))
{
sLog->outError(LOG_FILTER_PLAYER, "Player (GUID: %u) is banned, can't load.", guid);
return false;
@@ -16699,12 +16709,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
(AccountMgr::IsPlayerAccount(GetSession()->GetSecurity()) && sObjectMgr->IsReservedName(m_name)))
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_UPD_ADD_AT_LOGIN_FLAG);
-
stmt->setUInt16(0, uint16(AT_LOGIN_RENAME));
stmt->setUInt32(1, guid);
-
CharacterDatabase.Execute(stmt);
-
return false;
}
@@ -16736,7 +16743,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
SetFloatValue(UNIT_FIELD_HOVERHEIGHT, 1.0f);
// load achievements before anything else to prevent multiple gains for the same achievement/criteria on every loading (as loading does call UpdateAchievementCriteria)
- m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS));
+ m_achievementMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS));
uint32 money = fields[8].GetUInt32();
if (money > MAX_MONEY_AMOUNT)
@@ -16777,7 +16784,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
setFactionForRace(getRace());
// load home bind and check in same time class/race pair, it used later for restore broken positions
- if (!_LoadHomeBind(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADHOMEBIND)))
+ if (!_LoadHomeBind(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND)))
return false;
InitPrimaryProfessions(); // to max set before any spell loaded
@@ -16801,9 +16808,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
#define RelocateToHomebind(){ mapId = m_homebindMapId; instanceId = 0; Relocate(m_homebindX, m_homebindY, m_homebindZ); }
- _LoadGroup(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADGROUP));
+ _LoadGroup(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GROUP));
- _LoadArenaTeamInfo(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADARENAINFO));
+ _LoadArenaTeamInfo(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO));
SetArenaPoints(fields[39].GetUInt32());
@@ -16830,9 +16837,9 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
SetUInt16Value(PLAYER_FIELD_KILLS, 0, fields[44].GetUInt16());
SetUInt16Value(PLAYER_FIELD_KILLS, 1, fields[45].GetUInt16());
- _LoadBoundInstances(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES));
- _LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES));
- _LoadBGData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADBGDATA));
+ _LoadBoundInstances(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES));
+ _LoadInstanceTimeRestrictions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES));
+ _LoadBGData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_BG_DATA));
GetSession()->SetPlayer(this);
MapEntry const* mapEntry = sMapStore.LookupEntry(mapId);
@@ -17141,7 +17148,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
}
// load skills after InitStatsForLevel because it triggering aura apply also
- _LoadSkills(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSKILLS));
+ _LoadSkills(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SKILLS));
UpdateSkillsForLevel(); //update skills after load, to make sure they are correctly update at player load
// apply original stats mods before spell loading or item equipment that call before equip _RemoveStatsMods()
@@ -17159,42 +17166,43 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
sLog->outError(LOG_FILTER_PLAYER, "Player %s(GUID: %u) has SpecCount = %u and ActiveSpec = %u.", GetName().c_str(), GetGUIDLow(), m_specsCount, m_activeSpec);
}
- _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADTALENTS));
- _LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSPELLS));
+ _LoadTalents(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_TALENTS));
+ _LoadSpells(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELLS));
- _LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADGLYPHS));
- _LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADAURAS), time_diff);
+ _LoadGlyphs(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GLYPHS));
+ _LoadAuras(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_AURAS), time_diff);
_LoadGlyphAuras();
// add ghost flag (must be after aura load: PLAYER_FLAGS_GHOST set in aura)
if (HasFlag(PLAYER_FLAGS, PLAYER_FLAGS_GHOST))
m_deathState = DEAD;
// after spell load, learn rewarded spell if need also
- _LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS));
- _LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW));
- _LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS));
- _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS));
- _LoadSeasonalQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS));
- _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADRANDOMBG));
+ _LoadQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS));
+ _LoadQuestStatusRewarded(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW));
+ _LoadDailyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS));
+ _LoadWeeklyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS));
+ _LoadSeasonalQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS));
+ _LoadMonthlyQuestStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS));
+ _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG));
// after spell and quest load
InitTalentForLevel();
learnDefaultSpells();
// must be before inventory (some items required reputation check)
- m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADREPUTATION));
+ m_reputationMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_REPUTATION));
- _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADINVENTORY), time_diff);
+ _LoadInventory(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_INVENTORY), time_diff);
// update items with duration and realtime
UpdateItemDuration(time_diff, true);
- _LoadActions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADACTIONS));
+ _LoadActions(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACTIONS));
// unread mails and next delivery time, actual mails not loaded
- _LoadMailInit(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADMAILCOUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADMAILDATE));
+ _LoadMailInit(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT), holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE));
- m_social = sSocialMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSOCIALLIST), GetGUIDLow());
+ m_social = sSocialMgr->LoadFromDB(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST), GetGUIDLow());
// check PLAYER_CHOSEN_TITLE compatibility with PLAYER__FIELD_KNOWN_TITLES
// note: PLAYER__FIELD_KNOWN_TITLES updated at quest status loaded
@@ -17207,7 +17215,7 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
// has to be called after last Relocate() in Player::LoadFromDB
SetFallInformation(0, GetPositionZ());
- _LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS));
+ _LoadSpellCooldowns(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS));
// Spell code allow apply any auras to dead character in load time in aura/spell/item loading
// Do now before stats re-calculation cleanup for ghost state unexpected auras
@@ -17288,11 +17296,11 @@ bool Player::LoadFromDB(uint32 guid, SQLQueryHolder *holder)
if (m_grantableLevels > 0)
SetByteValue(PLAYER_FIELD_BYTES, 1, 0x01);
- _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES));
+ _LoadDeclinedNames(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES));
m_achievementMgr->CheckAllAchievementCriteria();
- _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS));
+ _LoadEquipmentSets(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS));
return true;
}
@@ -18102,6 +18110,29 @@ void Player::_LoadSeasonalQuestStatus(PreparedQueryResult result)
m_SeasonalQuestChanged = false;
}
+void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result)
+{
+ m_monthlyquests.clear();
+
+ if (result)
+ {
+ do
+ {
+ Field* fields = result->Fetch();
+ uint32 quest_id = fields[0].GetUInt32();
+ Quest const* quest = sObjectMgr->GetQuestTemplate(quest_id);
+ if (!quest)
+ continue;
+
+ m_monthlyquests.insert(quest_id);
+ sLog->outDebug(LOG_FILTER_PLAYER_LOADING, "Monthly quest {%u} cooldown for player (GUID: %u)", quest_id, GetGUIDLow());
+ }
+ while (result->NextRow());
+ }
+
+ m_MonthlyQuestChanged = false;
+}
+
void Player::_LoadSpells(PreparedQueryResult result)
{
//QueryResult* result = CharacterDatabase.PQuery("SELECT spell, active, disabled FROM character_spell WHERE guid = '%u'", GetGUIDLow());
@@ -18842,6 +18873,7 @@ void Player::SaveToDB(bool create /*=false*/)
_SaveDailyQuestStatus(trans);
_SaveWeeklyQuestStatus(trans);
_SaveSeasonalQuestStatus(trans);
+ _SaveMonthlyQuestStatus(trans);
_SaveTalents(trans);
_SaveSpells(trans);
_SaveSpellCooldowns(trans);
@@ -19344,6 +19376,28 @@ void Player::_SaveSeasonalQuestStatus(SQLTransaction& trans)
m_SeasonalQuestChanged = false;
}
+void Player::_SaveMonthlyQuestStatus(SQLTransaction& trans)
+{
+ if (!m_MonthlyQuestChanged || m_monthlyquests.empty())
+ return;
+
+ // we don't need transactions here.
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR);
+ stmt->setUInt32(0, GetGUIDLow());
+ trans->Append(stmt);
+
+ for (QuestSet::const_iterator iter = m_monthlyquests.begin(); iter != m_monthlyquests.end(); ++iter)
+ {
+ uint32 quest_id = *iter;
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS);
+ stmt->setUInt32(0, GetGUIDLow());
+ stmt->setUInt32(1, quest_id);
+ trans->Append(stmt);
+ }
+
+ m_MonthlyQuestChanged = false;
+}
+
void Player::_SaveSkills(SQLTransaction& trans)
{
PreparedStatement* stmt = NULL;
@@ -22526,6 +22580,12 @@ void Player::SetSeasonalQuestStatus(uint32 quest_id)
m_SeasonalQuestChanged = true;
}
+void Player::SetMonthlyQuestStatus(uint32 quest_id)
+{
+ m_monthlyquests.insert(quest_id);
+ m_MonthlyQuestChanged = true;
+}
+
void Player::ResetDailyQuestStatus()
{
for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx)
@@ -22558,6 +22618,16 @@ void Player::ResetSeasonalQuestStatus(uint16 event_id)
m_SeasonalQuestChanged = false;
}
+void Player::ResetMonthlyQuestStatus()
+{
+ if (m_monthlyquests.empty())
+ return;
+
+ m_monthlyquests.clear();
+ // DB data deleted in caller
+ m_MonthlyQuestChanged = false;
+}
+
Battleground* Player::GetBattleground() const
{
if (GetBattlegroundId() == 0)
diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h
index 4cd90f27875..c4b7deca4dd 100644
--- a/src/server/game/Entities/Player/Player.h
+++ b/src/server/game/Entities/Player/Player.h
@@ -763,38 +763,39 @@ enum PlayedTimeIndex
// used at player loading query list preparing, and later result selection
enum PlayerLoginQueryIndex
{
- PLAYER_LOGIN_QUERY_LOADFROM = 0,
- PLAYER_LOGIN_QUERY_LOADGROUP = 1,
- PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES = 2,
- PLAYER_LOGIN_QUERY_LOADAURAS = 3,
- PLAYER_LOGIN_QUERY_LOADSPELLS = 4,
- PLAYER_LOGIN_QUERY_LOADQUESTSTATUS = 5,
- PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS = 6,
- PLAYER_LOGIN_QUERY_LOADREPUTATION = 7,
- PLAYER_LOGIN_QUERY_LOADINVENTORY = 8,
- PLAYER_LOGIN_QUERY_LOADACTIONS = 9,
- PLAYER_LOGIN_QUERY_LOADMAILCOUNT = 10,
- PLAYER_LOGIN_QUERY_LOADMAILDATE = 11,
- PLAYER_LOGIN_QUERY_LOADSOCIALLIST = 12,
- PLAYER_LOGIN_QUERY_LOADHOMEBIND = 13,
- PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS = 14,
- PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES = 15,
- PLAYER_LOGIN_QUERY_LOADGUILD = 16,
- PLAYER_LOGIN_QUERY_LOADARENAINFO = 17,
- PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS = 18,
- PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS = 19,
- PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS = 20,
- PLAYER_LOGIN_QUERY_LOADBGDATA = 21,
- PLAYER_LOGIN_QUERY_LOADGLYPHS = 22,
- PLAYER_LOGIN_QUERY_LOADTALENTS = 23,
- PLAYER_LOGIN_QUERY_LOADACCOUNTDATA = 24,
- PLAYER_LOGIN_QUERY_LOADSKILLS = 25,
- PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS = 26,
- PLAYER_LOGIN_QUERY_LOADRANDOMBG = 27,
- PLAYER_LOGIN_QUERY_LOADBANNED = 28,
- PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW = 29,
- PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES = 30,
- PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS = 31,
+ PLAYER_LOGIN_QUERY_LOAD_FROM = 0,
+ PLAYER_LOGIN_QUERY_LOAD_GROUP = 1,
+ PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES = 2,
+ PLAYER_LOGIN_QUERY_LOAD_AURAS = 3,
+ PLAYER_LOGIN_QUERY_LOAD_SPELLS = 4,
+ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS = 5,
+ PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS = 6,
+ PLAYER_LOGIN_QUERY_LOAD_REPUTATION = 7,
+ PLAYER_LOGIN_QUERY_LOAD_INVENTORY = 8,
+ PLAYER_LOGIN_QUERY_LOAD_ACTIONS = 9,
+ PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT = 10,
+ PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE = 11,
+ PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST = 12,
+ PLAYER_LOGIN_QUERY_LOAD_HOME_BIND = 13,
+ PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS = 14,
+ PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES = 15,
+ PLAYER_LOGIN_QUERY_LOAD_GUILD = 16,
+ PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO = 17,
+ PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS = 18,
+ PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS = 19,
+ PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS = 20,
+ PLAYER_LOGIN_QUERY_LOAD_BG_DATA = 21,
+ PLAYER_LOGIN_QUERY_LOAD_GLYPHS = 22,
+ PLAYER_LOGIN_QUERY_LOAD_TALENTS = 23,
+ PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA = 24,
+ PLAYER_LOGIN_QUERY_LOAD_SKILLS = 25,
+ PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS = 26,
+ PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG = 27,
+ PLAYER_LOGIN_QUERY_LOAD_BANNED = 28,
+ PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW = 29,
+ PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES = 30,
+ PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS = 31,
+ PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS = 32,
MAX_PLAYER_LOGIN_QUERY
};
@@ -1397,6 +1398,7 @@ class Player : public Unit, public GridObject<Player>
bool SatisfyQuestPrevChain(Quest const* qInfo, bool msg);
bool SatisfyQuestDay(Quest const* qInfo, bool msg);
bool SatisfyQuestWeek(Quest const* qInfo, bool msg);
+ bool SatisfyQuestMonth(Quest const* qInfo, bool msg);
bool SatisfyQuestSeasonal(Quest const* qInfo, bool msg);
bool GiveQuestSourceItem(Quest const* quest);
bool TakeQuestSourceItem(uint32 questId, bool msg);
@@ -1408,9 +1410,11 @@ class Player : public Unit, public GridObject<Player>
void SetDailyQuestStatus(uint32 quest_id);
void SetWeeklyQuestStatus(uint32 quest_id);
+ void SetMonthlyQuestStatus(uint32 quest_id);
void SetSeasonalQuestStatus(uint32 quest_id);
void ResetDailyQuestStatus();
void ResetWeeklyQuestStatus();
+ void ResetMonthlyQuestStatus();
void ResetSeasonalQuestStatus(uint16 event_id);
uint16 FindQuestSlot(uint32 quest_id) const;
@@ -2552,6 +2556,7 @@ class Player : public Unit, public GridObject<Player>
typedef UNORDERED_MAP<uint32,SeasonalQuestSet> SeasonalEventQuestMap;
QuestSet m_timedquests;
QuestSet m_weeklyquests;
+ QuestSet m_monthlyquests;
SeasonalEventQuestMap m_seasonalquests;
uint64 m_divider;
@@ -2573,6 +2578,7 @@ class Player : public Unit, public GridObject<Player>
void _LoadQuestStatusRewarded(PreparedQueryResult result);
void _LoadDailyQuestStatus(PreparedQueryResult result);
void _LoadWeeklyQuestStatus(PreparedQueryResult result);
+ void _LoadMonthlyQuestStatus(PreparedQueryResult result);
void _LoadSeasonalQuestStatus(PreparedQueryResult result);
void _LoadRandomBGStatus(PreparedQueryResult result);
void _LoadGroup(PreparedQueryResult result);
@@ -2599,6 +2605,7 @@ class Player : public Unit, public GridObject<Player>
void _SaveQuestStatus(SQLTransaction& trans);
void _SaveDailyQuestStatus(SQLTransaction& trans);
void _SaveWeeklyQuestStatus(SQLTransaction& trans);
+ void _SaveMonthlyQuestStatus(SQLTransaction& trans);
void _SaveSeasonalQuestStatus(SQLTransaction& trans);
void _SaveSkills(SQLTransaction& trans);
void _SaveSpells(SQLTransaction& trans);
@@ -2708,6 +2715,7 @@ class Player : public Unit, public GridObject<Player>
bool m_DailyQuestChanged;
bool m_WeeklyQuestChanged;
+ bool m_MonthlyQuestChanged;
bool m_SeasonalQuestChanged;
time_t m_lastDailyQuestTime;
diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp
index 64ce078bfef..b91207c9413 100644
--- a/src/server/game/Globals/ObjectMgr.cpp
+++ b/src/server/game/Globals/ObjectMgr.cpp
@@ -3730,6 +3730,15 @@ void ObjectMgr::LoadQuests()
}
}
+ if (qinfo->Flags & QUEST_TRINITY_FLAGS_MONTHLY)
+ {
+ if (!(qinfo->Flags & QUEST_TRINITY_FLAGS_REPEATABLE))
+ {
+ sLog->outError(LOG_FILTER_SQL, "Monthly quest %u not marked as repeatable in `SpecialFlags`, added.", qinfo->GetQuestId());
+ qinfo->Flags |= QUEST_TRINITY_FLAGS_REPEATABLE;
+ }
+ }
+
if (qinfo->Flags & QUEST_FLAGS_AUTO_REWARDED)
{
// at auto-reward can be rewarded only RewardChoiceItemId[0]
diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp
index 005e7679a4e..0e9ad902d8f 100644
--- a/src/server/game/Handlers/CharacterHandler.cpp
+++ b/src/server/game/Handlers/CharacterHandler.cpp
@@ -71,135 +71,139 @@ bool LoginQueryHolder::Initialize()
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADFROM, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_FROM, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GROUP_MEMBER);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGROUP, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GROUP, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INSTANCE);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBOUNDINSTANCES, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BOUND_INSTANCES, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_AURAS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADAURAS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_AURAS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELL);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELLS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDAILYQUESTSTATUS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DAILY_QUEST_STATUS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADWEEKLYQUESTSTATUS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_WEEKLY_QUEST_STATUS, stmt);
+
+ stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS);
+ stmt->setUInt32(0, lowGuid);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MONTHLY_QUEST_STATUS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSEASONALQUESTSTATUS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SEASONAL_QUEST_STATUS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REPUTATION);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADREPUTATION, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_REPUTATION, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_INVENTORY);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINVENTORY, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INVENTORY, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACTIONS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACTIONS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACTIONS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILCOUNT);
stmt->setUInt32(0, lowGuid);
stmt->setUInt64(1, uint64(time(NULL)));
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILCOUNT, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_COUNT, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_MAILDATE);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADMAILDATE, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_MAIL_DATE, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SOCIALLIST);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSOCIALLIST, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SOCIAL_LIST, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_HOMEBIND);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADHOMEBIND, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_HOME_BIND, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SPELLCOOLDOWNS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSPELLCOOLDOWNS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SPELL_COOLDOWNS, stmt);
if (sWorld->getBoolConfig(CONFIG_DECLINED_NAMES_USED))
{
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_DECLINEDNAMES);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADDECLINEDNAMES, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_DECLINED_NAMES, stmt);
}
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_GUILD_MEMBER);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGUILD, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GUILD, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ARENAINFO);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADARENAINFO, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ARENA_INFO, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_ACHIEVEMENTS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACHIEVEMENTS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACHIEVEMENTS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_CRITERIAPROGRESS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADCRITERIAPROGRESS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_CRITERIA_PROGRESS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_EQUIPMENTSETS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADEQUIPMENTSETS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_EQUIPMENT_SETS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BGDATA);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBGDATA, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BG_DATA, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_GLYPHS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADGLYPHS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_GLYPHS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_TALENTS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADTALENTS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_TALENTS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_PLAYER_ACCOUNT_DATA);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_SKILLS);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADSKILLS, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_SKILLS, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_RANDOMBG);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADRANDOMBG, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_BANNED);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADBANNED, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_BANNED, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_QUESTSTATUSREW);
stmt->setUInt32(0, lowGuid);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADQUESTSTATUSREW, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_QUEST_STATUS_REW, stmt);
stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_ACCOUNT_INSTANCELOCKTIMES);
stmt->setUInt32(0, m_accountId);
- res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOADINSTANCELOCKTIMES, stmt);
+ res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_INSTANCE_LOCK_TIMES, stmt);
return res;
}
@@ -803,7 +807,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
SendPacket(&data);
// load player specific part before send times
- LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADACCOUNTDATA), PER_CHARACTER_CACHE_MASK);
+ LoadAccountData(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_ACCOUNT_DATA), PER_CHARACTER_CACHE_MASK);
SendAccountDataTimes(PER_CHARACTER_CACHE_MASK);
data.Initialize(SMSG_FEATURE_SYSTEM_STATUS, 2); // added in 2.2.0
@@ -850,7 +854,7 @@ void WorldSession::HandlePlayerLogin(LoginQueryHolder* holder)
}
//QueryResult* result = CharacterDatabase.PQuery("SELECT guildid, rank FROM guild_member WHERE guid = '%u'", pCurrChar->GetGUIDLow());
- if (PreparedQueryResult resultGuild = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOADGUILD))
+ if (PreparedQueryResult resultGuild = holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_GUILD))
{
Field* fields = resultGuild->Fetch();
pCurrChar->SetInGuild(fields[0].GetUInt32());
diff --git a/src/server/game/Quests/QuestDef.h b/src/server/game/Quests/QuestDef.h
index 58734751cea..ffb0cf02a0a 100644
--- a/src/server/game/Quests/QuestDef.h
+++ b/src/server/game/Quests/QuestDef.h
@@ -120,7 +120,7 @@ enum __QuestGiverStatus
DIALOG_STATUS_REWARD = 10 // yellow dot on minimap
};
-enum __QuestFlags
+enum QuestFlags
{
// Flags used at server and sent to client
QUEST_FLAGS_NONE = 0x00000000,
@@ -150,8 +150,9 @@ enum __QuestFlags
QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT = 0x00200000, // Set by 2 in SpecialFlags from DB (if reequired area explore, spell SPELL_EFFECT_QUEST_COMPLETE casting, table `*_script` command SCRIPT_COMMAND_QUEST_EXPLORED use, set from script)
QUEST_TRINITY_FLAGS_AUTO_ACCEPT = 0x00400000, // Set by 4 in SpecialFlags in DB if the quest is to be auto-accepted.
QUEST_TRINITY_FLAGS_DF_QUEST = 0x00800000, // Set by 8 in SpecialFlags in DB if the quest is used by Dungeon Finder.
+ QUEST_TRINITY_FLAGS_MONTHLY = 0x01000000, // Set by 16 in SpecialFlags in DB if the quest is reset at the begining of the month
- QUEST_TRINITY_FLAGS_DB_ALLOWED = 0xFFFFF | QUEST_TRINITY_FLAGS_REPEATABLE | QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT | QUEST_TRINITY_FLAGS_AUTO_ACCEPT | QUEST_TRINITY_FLAGS_DF_QUEST,
+ QUEST_TRINITY_FLAGS_DB_ALLOWED = 0xFFFFF | QUEST_TRINITY_FLAGS_REPEATABLE | QUEST_TRINITY_FLAGS_EXPLORATION_OR_EVENT | QUEST_TRINITY_FLAGS_AUTO_ACCEPT | QUEST_TRINITY_FLAGS_DF_QUEST | QUEST_TRINITY_FLAGS_MONTHLY,
// Trinity flags for internal use only
QUEST_TRINITY_FLAGS_DELIVER = 0x04000000, // Internal flag computed only
@@ -251,6 +252,7 @@ class Quest
uint32 GetFlags() const { return Flags; }
bool IsDaily() const { return Flags & QUEST_FLAGS_DAILY; }
bool IsWeekly() const { return Flags & QUEST_FLAGS_WEEKLY; }
+ bool IsMonthly() const { return Flags & QUEST_TRINITY_FLAGS_MONTHLY; }
bool IsSeasonal() const { return (ZoneOrSort == -QUEST_SORT_SEASONAL || ZoneOrSort == -QUEST_SORT_SPECIAL || ZoneOrSort == -QUEST_SORT_LUNAR_FESTIVAL || ZoneOrSort == -QUEST_SORT_MIDSUMMER || ZoneOrSort == -QUEST_SORT_BREWFEST || ZoneOrSort == -QUEST_SORT_LOVE_IS_IN_THE_AIR || ZoneOrSort == -QUEST_SORT_NOBLEGARDEN) && !IsRepeatable(); }
bool IsDailyOrWeekly() const { return Flags & (QUEST_FLAGS_DAILY | QUEST_FLAGS_WEEKLY); }
bool IsRaidQuest() const { return Type == QUEST_TYPE_RAID || Type == QUEST_TYPE_RAID_10 || Type == QUEST_TYPE_RAID_25; }
diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp
index 5a776126d33..7f5c6b3fead 100644
--- a/src/server/game/World/World.cpp
+++ b/src/server/game/World/World.cpp
@@ -1772,6 +1772,9 @@ void World::SetInitialWorldSettings()
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Calculate next weekly quest reset time...");
InitWeeklyQuestResetTime();
+ sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Calculate next monthly quest reset time...");
+ InitMonthlyQuestResetTime();
+
sLog->outInfo(LOG_FILTER_SERVER_LOADING, "Calculate random battleground reset time...");
InitRandomBGResetTime();
@@ -1927,9 +1930,14 @@ void World::Update(uint32 diff)
m_NextDailyQuestReset += DAY;
}
+ /// Handle weekly quests reset time
if (m_gameTime > m_NextWeeklyQuestReset)
ResetWeeklyQuests();
+ /// Handle monthly quests reset time
+ if (m_gameTime > m_NextMonthlyQuestReset)
+ ResetMonthlyQuests();
+
if (m_gameTime > m_NextRandomBGReset)
ResetRandomBG();
@@ -2719,6 +2727,13 @@ void World::InitDailyQuestResetTime()
m_NextDailyQuestReset = (curTime >= curDayResetTime) ? curDayResetTime + DAY : curDayResetTime;
}
+void World::InitMonthlyQuestResetTime()
+{
+ time_t wstime = uint64(sWorld->getWorldState(WS_MONTHLY_QUEST_RESET_TIME));
+ time_t curtime = time(NULL);
+ m_NextMonthlyQuestReset = wstime < curtime ? curtime : time_t(wstime);
+}
+
void World::InitRandomBGResetTime()
{
time_t bgtime = uint64(sWorld->getWorldState(WS_BG_DAILY_RESET_TIME));
@@ -2809,6 +2824,8 @@ void World::SetPlayerSecurityLimit(AccountTypes _sec)
void World::ResetWeeklyQuests()
{
+ sLog->outInfo(LOG_FILTER_GENERAL, "Weekly quests reset for all characters.");
+
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_WEEKLY);
CharacterDatabase.Execute(stmt);
@@ -2823,6 +2840,57 @@ void World::ResetWeeklyQuests()
sPoolMgr->ChangeWeeklyQuests();
}
+void World::ResetMonthlyQuests()
+{
+ sLog->outInfo(LOG_FILTER_GENERAL, "Monthly quests reset for all characters.");
+
+ PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_MONTHLY);
+ CharacterDatabase.Execute(stmt);
+
+ for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
+ if (itr->second->GetPlayer())
+ itr->second->GetPlayer()->ResetMonthlyQuestStatus();
+
+ time_t mostRecentQuestTime = 0;
+
+ // generate time
+ time_t curTime = time(NULL);
+ tm localTm = *localtime(&curTime);
+
+ int month = localTm.tm_mon;
+ int year = localTm.tm_year;
+
+ ++month;
+
+ // month 11 is december, next is january (0)
+ if (month > 11)
+ {
+ month = 0;
+ year += 1;
+ }
+
+ // reset time for next month
+ localTm.tm_year = year;
+ localTm.tm_mon = month;
+ localTm.tm_mday = 1; // don't know if we really need config option for day / hour
+ localTm.tm_hour = 0;
+ localTm.tm_min = 0;
+ localTm.tm_sec = 0;
+
+ time_t nextMonthResetTime = mktime(&localTm);
+
+ // last reset time before current moment
+ time_t resetTime = (curTime < nextMonthResetTime) ? nextMonthResetTime - MONTH : nextMonthResetTime;
+
+ // need reset (if we have quest time before last reset time (not processed by some reason)
+ if (mostRecentQuestTime && mostRecentQuestTime <= resetTime)
+ m_NextMonthlyQuestReset = mostRecentQuestTime;
+ else // plan next reset time
+ m_NextMonthlyQuestReset = (curTime >= nextMonthResetTime) ? nextMonthResetTime + MONTH : nextMonthResetTime;
+
+ sWorld->setWorldState(WS_MONTHLY_QUEST_RESET_TIME, uint64(m_NextMonthlyQuestReset));
+}
+
void World::ResetEventSeasonalQuests(uint16 event_id)
{
PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_QUEST_STATUS_SEASONAL);
diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h
index 40ef0d7a8e5..1ac9b153dfd 100644
--- a/src/server/game/World/World.h
+++ b/src/server/game/World/World.h
@@ -469,9 +469,10 @@ enum RealmZone
enum WorldStates
{
- WS_WEEKLY_QUEST_RESET_TIME = 20002, // Next weekly reset time
- WS_BG_DAILY_RESET_TIME = 20003, // Next daily BG reset time
- WS_GUILD_DAILY_RESET_TIME = 20006, // Next guild cap reset time
+ WS_WEEKLY_QUEST_RESET_TIME = 20002, // Next weekly reset time
+ WS_BG_DAILY_RESET_TIME = 20003, // Next daily BG reset time
+ WS_MONTHLY_QUEST_RESET_TIME = 20004, // Next monthly reset time
+ WS_GUILD_DAILY_RESET_TIME = 20006, // Next guild cap reset time
};
/// Storage class for commands issued for delayed execution
@@ -742,10 +743,12 @@ class World
void InitDailyQuestResetTime();
void InitWeeklyQuestResetTime();
+ void InitMonthlyQuestResetTime();
void InitRandomBGResetTime();
void InitGuildResetTime();
void ResetDailyQuests();
void ResetWeeklyQuests();
+ void ResetMonthlyQuests();
void ResetRandomBG();
void ResetGuildCap();
private:
@@ -807,6 +810,7 @@ class World
// next daily quests and random bg reset time
time_t m_NextDailyQuestReset;
time_t m_NextWeeklyQuestReset;
+ time_t m_NextMonthlyQuestReset;
time_t m_NextRandomBGReset;
time_t m_NextGuildReset;
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.cpp b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
index 9c5db00ad49..33f0cab5170 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.cpp
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.cpp
@@ -54,9 +54,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
PREPARE_STATEMENT(CHAR_SEL_CHAR_POSITION, "SELECT position_x, position_y, position_z, orientation, map, taxi_path FROM characters WHERE guid = ?", CONNECTION_SYNCH);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY, "DELETE FROM character_queststatus_daily", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_WEEKLY, "DELETE FROM character_queststatus_weekly", CONNECTION_ASYNC);
+ PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_SEASONAL, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_DAILY_CHAR, "DELETE FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR, "DELETE FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC);
+ PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR, "DELETE FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR, "DELETE FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_DEL_BATTLEGROUND_RANDOM, "DELETE FROM character_battleground_random", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_INS_BATTLEGROUND_RANDOM, "INSERT INTO character_battleground_random (guid) VALUES (?)", CONNECTION_ASYNC);
@@ -76,9 +78,11 @@ void CharacterDatabaseConnection::DoPrepareStatements()
"itemcount1, itemcount2, itemcount3, itemcount4, playercount FROM character_queststatus WHERE guid = ? AND status <> 0", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_SEL_CHARACTER_DAILYQUESTSTATUS, "SELECT quest, time FROM character_queststatus_daily WHERE guid = ?", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS, "SELECT quest FROM character_queststatus_weekly WHERE guid = ?", CONNECTION_ASYNC)
+ PREPARE_STATEMENT(CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS, "SELECT quest FROM character_queststatus_monthly WHERE guid = ?", CONNECTION_ASYNC);
PREPARE_STATEMENT(CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS, "SELECT quest, event FROM character_queststatus_seasonal WHERE guid = ?", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_INS_CHARACTER_DAILYQUESTSTATUS, "INSERT INTO character_queststatus_daily (guid, quest, time) VALUES (?, ?, ?)", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS, "INSERT INTO character_queststatus_weekly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC)
+ PREPARE_STATEMENT(CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS, "INSERT INTO character_queststatus_monthly (guid, quest) VALUES (?, ?)", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_INS_CHARACTER_SEASONALQUESTSTATUS, "INSERT INTO character_queststatus_seasonal (guid, quest, event) VALUES (?, ?, ?)", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC)
PREPARE_STATEMENT(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, "
diff --git a/src/server/shared/Database/Implementation/CharacterDatabase.h b/src/server/shared/Database/Implementation/CharacterDatabase.h
index 5ce0639e59b..181161978df 100644
--- a/src/server/shared/Database/Implementation/CharacterDatabase.h
+++ b/src/server/shared/Database/Implementation/CharacterDatabase.h
@@ -74,9 +74,11 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHAR_POSITION,
CHAR_DEL_QUEST_STATUS_DAILY,
CHAR_DEL_QUEST_STATUS_WEEKLY,
+ CHAR_DEL_QUEST_STATUS_MONTHLY,
CHAR_DEL_QUEST_STATUS_SEASONAL,
CHAR_DEL_QUEST_STATUS_DAILY_CHAR,
CHAR_DEL_QUEST_STATUS_WEEKLY_CHAR,
+ CHAR_DEL_QUEST_STATUS_MONTHLY_CHAR,
CHAR_DEL_QUEST_STATUS_SEASONAL_CHAR,
CHAR_DEL_BATTLEGROUND_RANDOM,
CHAR_INS_BATTLEGROUND_RANDOM,
@@ -89,9 +91,11 @@ enum CharacterDatabaseStatements
CHAR_SEL_CHARACTER_QUESTSTATUS,
CHAR_SEL_CHARACTER_DAILYQUESTSTATUS,
CHAR_SEL_CHARACTER_WEEKLYQUESTSTATUS,
+ CHAR_SEL_CHARACTER_MONTHLYQUESTSTATUS,
CHAR_SEL_CHARACTER_SEASONALQUESTSTATUS,
CHAR_INS_CHARACTER_DAILYQUESTSTATUS,
CHAR_INS_CHARACTER_WEEKLYQUESTSTATUS,
+ CHAR_INS_CHARACTER_MONTHLYQUESTSTATUS,
CHAR_INS_CHARACTER_SEASONALQUESTSTATUS,
CHAR_SEL_CHARACTER_REPUTATION,
CHAR_SEL_CHARACTER_INVENTORY,