diff options
-rw-r--r-- | sql/updates/characters/2012_12_03_00_character_character_queststatus_monthly.sql | 8 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 144 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 72 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 9 | ||||
-rw-r--r-- | src/server/game/Handlers/CharacterHandler.cpp | 72 | ||||
-rw-r--r-- | src/server/game/Quests/QuestDef.h | 6 | ||||
-rw-r--r-- | src/server/game/World/World.cpp | 68 | ||||
-rw-r--r-- | src/server/game/World/World.h | 10 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.cpp | 4 | ||||
-rw-r--r-- | src/server/shared/Database/Implementation/CharacterDatabase.h | 4 |
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, |