From d9b12217c4b82e2d8dfeba1440c655207fb04eac Mon Sep 17 00:00:00 2001 From: Ovahlord Date: Wed, 18 Apr 2018 15:09:49 +0200 Subject: [PATCH] Core/LFG: implement weekly reward counter to limit the first dungeon rewards * all default random rewards can be rewarded 7 times per week * raid finder first reward can be rewarded once per week * if completionsPerWeek = 0 the currency caps will limit the first rewards otherwise first rewards can be always rewarded * random Cataclysm normal dungeons will now reward 140 Justice points instead of 150 * second reward for random Cataclysm normal dungeons will now reward gold only (need to verify this) --- .../4.3.4/custom_2018_04_18_00_characters.sql | 7 + .../4.3.4/custom_2018_04_18_00_world.sql | 8 + .../Implementation/CharacterDatabase.cpp | 5 + .../Implementation/CharacterDatabase.h | 5 + src/server/game/DungeonFinding/LFGMgr.cpp | 32 ++-- src/server/game/DungeonFinding/LFGMgr.h | 6 +- src/server/game/Entities/Player/Player.cpp | 149 ++++++++++++------ src/server/game/Entities/Player/Player.h | 14 +- src/server/game/Handlers/CharacterHandler.cpp | 4 + src/server/game/Handlers/LFGHandler.cpp | 21 ++- src/server/game/World/World.cpp | 16 +- src/server/game/World/World.h | 2 +- 12 files changed, 195 insertions(+), 74 deletions(-) create mode 100644 sql/updates/characters/4.3.4/custom_2018_04_18_00_characters.sql create mode 100644 sql/updates/world/4.3.4/custom_2018_04_18_00_world.sql diff --git a/sql/updates/characters/4.3.4/custom_2018_04_18_00_characters.sql b/sql/updates/characters/4.3.4/custom_2018_04_18_00_characters.sql new file mode 100644 index 00000000000..bf4cf0cbca4 --- /dev/null +++ b/sql/updates/characters/4.3.4/custom_2018_04_18_00_characters.sql @@ -0,0 +1,7 @@ +DROP TABLE IF EXISTS `character_rewardstatus_lfg`; +CREATE TABLE `character_rewardstatus_lfg`( + `guid` INT(10) NOT NULL DEFAULT 0 COMMENT 'Global Unique Identifier', + `dungeonId` SMALLINT(3) NOT NULL DEFAULT 0 COMMENT 'Dungeon ID Identifier', + `rewardCount` TINYINT(3) UNSIGNED DEFAULT 0 COMMENT 'Dungeon First Reward Count Identifier', + PRIMARY KEY (`dungeonId`) +); diff --git a/sql/updates/world/4.3.4/custom_2018_04_18_00_world.sql b/sql/updates/world/4.3.4/custom_2018_04_18_00_world.sql new file mode 100644 index 00000000000..e9307152b8c --- /dev/null +++ b/sql/updates/world/4.3.4/custom_2018_04_18_00_world.sql @@ -0,0 +1,8 @@ +ALTER TABLE `lfg_dungeon_rewards` ADD COLUMN `completionsPerWeek` TINYINT(3) UNSIGNED DEFAULT 0 NULL COMMENT 'Maximum amount that the first quest may be rewarded' AFTER `otherQuestId`; + +UPDATE `quest_template` SET `RewardCurrencyId1`= 0, `RewardCurrencyCount1`= 0 WHERE `ID` = 28908; +UPDATE `quest_template` SET `RewardCurrencyCount1`= 14000 WHERE `ID` = 28907; +UPDATE `quest_template` SET `Flags`= 0 WHERE `ID`= 30110; + +UPDATE `lfg_dungeon_rewards` SET `completionsPerWeek`= 7 WHERE `dungeonId` NOT IN (417, 416, 434, 301); +UPDATE `lfg_dungeon_rewards` SET `completionsPerWeek`= 1 WHERE `dungeonId` IN (417, 416); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.cpp b/src/server/database/Database/Implementation/CharacterDatabase.cpp index 1a072922a7f..161cdd83441 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.cpp +++ b/src/server/database/Database/Implementation/CharacterDatabase.cpp @@ -93,6 +93,11 @@ void CharacterDatabaseConnection::DoPrepareStatements() PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, "DELETE FROM character_queststatus_monthly", CONNECTION_ASYNC); PrepareStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, "DELETE FROM character_queststatus_seasonal WHERE event = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_REWARDSTATUS_LFG, "SELECT dungeonId, rewardCount FROM character_rewardstatus_lfg WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_CHARACTER_REWARDSTATUS_LFG, "DELETE FROM character_rewardstatus_lfg WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(CHAR_INS_CHARACTER_REWARDSTATUS_LFG, "INSERT INTO character_rewardstatus_lfg (guid, dungeonId, rewardCount) VALUES (?, ?, ?)", CONNECTION_ASYNC); + PrepareStatement(CHAR_DEL_RESET_CHARACTER_REWARDSTATUS_LFG, "DELETE FROM character_rewardstatus_lfg", CONNECTION_ASYNC); + PrepareStatement(CHAR_SEL_CHARACTER_REPUTATION, "SELECT faction, standing, flags FROM character_reputation WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(CHAR_SEL_CHARACTER_INVENTORY, "SELECT creatorGuid, giftCreatorGuid, count, duration, charges, flags, enchantments, randomPropertyId, durability, playedTime, text, bag, slot, " "item, itemEntry FROM character_inventory ci JOIN item_instance ii ON ci.item = ii.guid WHERE ci.guid = ? ORDER BY bag, slot", CONNECTION_ASYNC); diff --git a/src/server/database/Database/Implementation/CharacterDatabase.h b/src/server/database/Database/Implementation/CharacterDatabase.h index 384b8c3a3de..aae0d92dff8 100644 --- a/src/server/database/Database/Implementation/CharacterDatabase.h +++ b/src/server/database/Database/Implementation/CharacterDatabase.h @@ -82,6 +82,11 @@ enum CharacterDatabaseStatements : uint32 CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_MONTHLY, CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_SEASONAL_BY_EVENT, + CHAR_SEL_CHARACTER_REWARDSTATUS_LFG, + CHAR_DEL_CHARACTER_REWARDSTATUS_LFG, + CHAR_INS_CHARACTER_REWARDSTATUS_LFG, + CHAR_DEL_RESET_CHARACTER_REWARDSTATUS_LFG, + CHAR_SEL_CHARACTER_REPUTATION, CHAR_SEL_CHARACTER_INVENTORY, CHAR_SEL_CHARACTER_ACTIONS, diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 3625e94eef7..def400d91f0 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -124,7 +124,7 @@ void LFGMgr::LoadRewards() RewardMapStore.clear(); // ORDER BY is very important for GetRandomDungeonReward! - QueryResult result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, otherQuestId FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC"); + QueryResult result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, otherQuestId, completionsPerWeek FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC"); if (!result) { @@ -142,6 +142,7 @@ void LFGMgr::LoadRewards() uint32 maxLevel = fields[1].GetUInt8(); uint32 firstQuestId = fields[2].GetUInt32(); uint32 otherQuestId = fields[3].GetUInt32(); + uint32 completionsPerWeek = fields[4].GetUInt8(); if (!GetLFGDungeonEntry(dungeonId)) { @@ -167,7 +168,7 @@ void LFGMgr::LoadRewards() otherQuestId = 0; } - RewardMapStore.insert(LfgRewardContainer::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, otherQuestId))); + RewardMapStore.insert(LfgRewardContainer::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, otherQuestId, completionsPerWeek))); ++count; } while (result->NextRow()); @@ -1492,17 +1493,22 @@ void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId, Map const* if (!reward) continue; - bool done = false; + bool firstReward = true; Quest const* quest = sObjectMgr->GetQuestTemplate(reward->firstQuest); if (!quest) continue; - // if we can take the quest, means that we haven't done this kind of "run", IE: First Heroic Random of Day. - if (player->CanRewardQuest(quest, false)) + // CanRewardQuest to check currency caps, SatisfyFirstLFGReward to check weekly reward caps for first quest + if (player->CanRewardQuest(quest, false) && player->SatisfyFirstLFGReward(rDungeonId, reward->completionsPerWeek)) + { + if (reward->completionsPerWeek) + player->SetLFGRewardStatus(rDungeonId); + player->RewardQuest(quest, 0, nullptr, false); + } else { - done = true; + firstReward = false; quest = sObjectMgr->GetQuestTemplate(reward->otherQuest); if (!quest) continue; @@ -1514,20 +1520,16 @@ void LFGMgr::FinishDungeon(ObjectGuid gguid, const uint32 dungeonId, Map const* if (Group *group = player->GetGroup()) tmpRole = group->GetLfgRoles(player->GetGUID()); - if (IsCallToArmsEligible(player->getLevel(), rDungeonId & 0x00FFFFFF)) - { + if (IsCallToArmsEligible(player->getLevel(), rDungeonId)) if (player->GetCallToArmsTempRoles() & tmpRole) - { - const Quest* q = sObjectMgr->GetQuestTemplate(LFG_CALL_TO_ARMS_QUEST); - player->RewardQuest(q, 0, nullptr, false); - } - } + if (Quest const* callToArmsQuest = sObjectMgr->GetQuestTemplate(LFG_CALL_TO_ARMS_QUEST)) + player->RewardQuest(callToArmsQuest, 0, nullptr, false); player->SetTempCallToArmsRoles(0); // Give rewards - TC_LOG_DEBUG("lfg.dungeon.finish", "Group: %s, Player: %s done dungeon %u, %s previously done.", gguid.ToString().c_str(), guid.ToString().c_str(), GetDungeon(gguid), done ? " " : " not"); - LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), done, quest); + TC_LOG_DEBUG("lfg.dungeon.finish", "Group: %s, Player: %s done dungeon %u, %s previously done.", gguid.ToString().c_str(), guid.ToString().c_str(), GetDungeon(gguid), !firstReward ? " " : " not"); + LfgPlayerRewardData data = LfgPlayerRewardData(dungeon->Entry(), GetDungeon(gguid, false), !firstReward, quest); player->GetSession()->SendLfgPlayerReward(data); } } diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 485d8bd4c02..cfcb0d7ea6c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -210,6 +210,7 @@ struct LfgPlayerRewardData { LfgPlayerRewardData(uint32 random, uint32 current, bool _done, Quest const* _quest): rdungeonEntry(random), sdungeonEntry(current), done(_done), quest(_quest) { } + uint32 rdungeonEntry; uint32 sdungeonEntry; bool done; @@ -219,12 +220,13 @@ struct LfgPlayerRewardData /// Reward info struct LfgReward { - LfgReward(uint32 _maxLevel = 0, uint32 _firstQuest = 0, uint32 _otherQuest = 0): - maxLevel(_maxLevel), firstQuest(_firstQuest), otherQuest(_otherQuest) { } + LfgReward(uint32 _maxLevel = 0, uint32 _firstQuest = 0, uint32 _otherQuest = 0, uint8 _completionsPerWeek = 0): + maxLevel(_maxLevel), firstQuest(_firstQuest), otherQuest(_otherQuest), completionsPerWeek(_completionsPerWeek) { } uint32 maxLevel; uint32 firstQuest; uint32 otherQuest; + uint8 completionsPerWeek; }; /// Stores player data related to proposal to join diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 395c5a7fe6d..c213023a276 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -395,6 +395,8 @@ Player::Player(WorldSession* session): Unit(true) m_SeasonalQuestChanged = false; + m_LFGRewardStatusChanged = false; + SetPendingBind(0, 0); _activeCheats = CHEAT_NONE; @@ -4498,6 +4500,10 @@ void Player::DeleteFromDB(ObjectGuid playerguid, uint32 accountId, bool updateRe stmt->setUInt32(0, guid); trans->Append(stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_REWARDSTATUS_LFG); + stmt->setUInt32(0, guid); + trans->Append(stmt); + Corpse::DeleteFromDB(playerguid, trans); break; } @@ -15311,7 +15317,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, CharacterDatabase.CommitTransaction(trans); } - if ((quest->IsDaily() || (quest->IsDFQuest()) && !quest->IsRepeatable()) && !quest->IsWeekly()) + if (quest->IsDaily() && !quest->IsDFQuest()) { SetDailyQuestStatus(quest_id); if (quest->IsDaily()) @@ -15866,14 +15872,6 @@ bool Player::SatisfyQuestDay(Quest const* qInfo, bool msg) const if (!qInfo->IsDaily() && !qInfo->IsDFQuest()) return true; - if (qInfo->IsDFQuest() && !qInfo->IsRepeatable()) - { - if (m_DFQuests.find(qInfo->GetQuestId()) != m_DFQuests.end()) - return false; - - return true; - } - bool have_slot = false; for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) { @@ -16105,6 +16103,24 @@ void Player::SendQuestUpdate(uint32 questId) PhasingHandler::OnConditionChange(this); } +bool Player::SatisfyFirstLFGReward(uint32 dungeonId, uint8 maxRewCount) const +{ + LFGRewardStatusMap::const_iterator lfgdungeon = m_lfgrewardstatus.find(dungeonId); + if (lfgdungeon != m_lfgrewardstatus.end()) + return lfgdungeon->second && lfgdungeon->second < maxRewCount; + + return true; +} + +uint8 Player::GetFirstRewardCountForDungeonId(uint32 dungeonId) +{ + LFGRewardStatusMap::const_iterator lfgdungeon = m_lfgrewardstatus.find(dungeonId); + if (lfgdungeon != m_lfgrewardstatus.end()) + return lfgdungeon->second; + + return 0; +} + QuestGiverStatus Player::GetQuestDialogStatus(Object* questgiver) { QuestRelationBounds qr; @@ -17804,6 +17820,7 @@ bool Player::LoadFromDB(ObjectGuid guid, SQLQueryHolder* holder) _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)); + _LoadLFGRewardStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_LFG_REWARD_STATUS)); _LoadRandomBGStatus(holder->GetPreparedResult(PLAYER_LOGIN_QUERY_LOAD_RANDOM_BG)); // after spell and quest load @@ -18895,8 +18912,6 @@ void Player::_LoadDailyQuestStatus(PreparedQueryResult result) for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx, 0); - m_DFQuests.clear(); - //QueryResult* result = CharacterDatabase.PQuery("SELECT quest, time FROM character_queststatus_daily WHERE guid = '%u'", GetGUID().GetCounter()); if (result) @@ -18906,15 +18921,6 @@ void Player::_LoadDailyQuestStatus(PreparedQueryResult result) do { Field* fields = result->Fetch(); - if (Quest const* qQuest = sObjectMgr->GetQuestTemplate(fields[0].GetUInt32())) - { - if (qQuest->IsDFQuest()) - { - m_DFQuests.insert(qQuest->GetQuestId()); - m_lastDailyQuestTime = time_t(fields[1].GetUInt32()); - continue; - } - } if (quest_daily_idx >= PLAYER_MAX_DAILY_QUESTS) // max amount with exist data in query { @@ -19017,6 +19023,27 @@ void Player::_LoadMonthlyQuestStatus(PreparedQueryResult result) m_MonthlyQuestChanged = false; } +void Player::_LoadLFGRewardStatus(PreparedQueryResult result) +{ + m_lfgrewardstatus.clear(); + + if (result) + { + do + { + Field* fields = result->Fetch(); + uint32 dungeon_id = fields[0].GetUInt16(); + uint8 reward_count = fields[1].GetUInt8(); + + m_lfgrewardstatus[dungeon_id] = reward_count; + TC_LOG_DEBUG("entities.player.loading", "Player::_LFGQuestStatus: Loaded LFG quest first reward cooldown (DungeonID: %u) for player '%s' (%s)", + dungeon_id, GetName().c_str(), GetGUID().ToString().c_str()); + } while (result->NextRow()); + } + + m_LFGRewardStatusChanged = false; +} + void Player::_LoadSpells(PreparedQueryResult result) { //QueryResult* result = CharacterDatabase.PQuery("SELECT spell, active, disabled FROM character_spell WHERE guid = '%u'", GetGUID().GetCounter()); @@ -19906,6 +19933,7 @@ void Player::SaveToDB(bool create /*=false*/) _SaveWeeklyQuestStatus(trans); _SaveSeasonalQuestStatus(trans); _SaveMonthlyQuestStatus(trans); + _SaveLFGRewardStatus(trans); _SaveTalents(trans); _SaveSpells(trans); GetSpellHistory()->SaveToDB(trans); @@ -20436,18 +20464,6 @@ void Player::_SaveDailyQuestStatus(SQLTransaction& trans) trans->Append(stmt); } } - - if (!m_DFQuests.empty()) - { - for (DFQuestsDoneList::iterator itr = m_DFQuests.begin(); itr != m_DFQuests.end(); ++itr) - { - stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_QUESTSTATUS_DAILY); - stmt->setUInt32(0, GetGUID().GetCounter()); - stmt->setUInt32(1, (*itr)); - stmt->setUInt64(2, uint64(m_lastDailyQuestTime)); - trans->Append(stmt); - } - } } void Player::_SaveWeeklyQuestStatus(SQLTransaction& trans) @@ -20525,6 +20541,31 @@ void Player::_SaveMonthlyQuestStatus(SQLTransaction& trans) m_MonthlyQuestChanged = false; } +void Player::_SaveLFGRewardStatus(SQLTransaction& trans) +{ + if (!m_LFGRewardStatusChanged || m_lfgrewardstatus.empty()) + return; + + // we don't need transactions here. + PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_CHARACTER_REWARDSTATUS_LFG); + stmt->setUInt32(0, GetGUID().GetCounter()); + trans->Append(stmt); + + for (LFGRewardStatusMap::const_iterator itr = m_lfgrewardstatus.begin(); itr != m_lfgrewardstatus.end(); ++itr) + { + uint32 dungeonId = itr->first; + uint8 rewardCount = itr->second; + + stmt = CharacterDatabase.GetPreparedStatement(CHAR_INS_CHARACTER_REWARDSTATUS_LFG); + stmt->setUInt32(0, GetGUID().GetCounter()); + stmt->setUInt32(1, dungeonId); + stmt->setUInt32(2, rewardCount); + trans->Append(stmt); + } + + m_LFGRewardStatusChanged = false; +} + void Player::_SaveSkills(SQLTransaction& trans) { PreparedStatement* stmt; @@ -24061,23 +24102,15 @@ void Player::SetDailyQuestStatus(uint32 quest_id) { if (Quest const* qQuest = sObjectMgr->GetQuestTemplate(quest_id)) { - if (!qQuest->IsDFQuest()) + for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) { - for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) + if (!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx)) { - if (!GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) - { - SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx, quest_id); - m_lastDailyQuestTime = time(nullptr); // last daily quest time - m_DailyQuestChanged = true; - break; - } + SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1 + quest_daily_idx, quest_id); + m_lastDailyQuestTime = time(nullptr); // last daily quest time + m_DailyQuestChanged = true; + break; } - } else - { - m_DFQuests.insert(quest_id); - m_lastDailyQuestTime = time(nullptr); - m_DailyQuestChanged = true; } } } @@ -24122,13 +24155,23 @@ void Player::SetMonthlyQuestStatus(uint32 quest_id) m_MonthlyQuestChanged = true; } +void Player::SetLFGRewardStatus(uint32 dungeon_id) +{ + LFGRewardStatusMap::iterator lfgdungeon = m_lfgrewardstatus.find(dungeon_id); + + if (lfgdungeon != m_lfgrewardstatus.end()) + lfgdungeon->second++; + else + m_lfgrewardstatus[dungeon_id] = 1; + + m_LFGRewardStatusChanged = true; +} + void Player::ResetDailyQuestStatus() { for (uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) SetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx, 0); - m_DFQuests.clear(); // Dungeon Finder Quests. - // DB data deleted in caller m_DailyQuestChanged = false; m_lastDailyQuestTime = 0; @@ -24165,6 +24208,16 @@ void Player::ResetMonthlyQuestStatus() m_MonthlyQuestChanged = false; } +void Player::ResetLFGRewardStatus() +{ + if (!m_lfgrewardstatus.empty()) + return; + + m_lfgrewardstatus.clear(); + // DB data deleted in caller + m_LFGRewardStatusChanged = 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 84e1780de0b..4f8bbca5b52 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -784,6 +784,7 @@ enum PlayerLoginQueryIndex PLAYER_LOGIN_QUERY_LOAD_CUF_PROFILES = 35, PLAYER_LOGIN_QUERY_LOAD_CORPSE_LOCATION = 36, PLAYER_LOGIN_QUERY_LOAD_ALL_PETS = 37, + PLAYER_LOGIN_QUERY_LOAD_LFG_REWARD_STATUS = 38, MAX_PLAYER_LOGIN_QUERY }; @@ -1385,16 +1386,20 @@ class TC_GAME_API Player : public Unit, public GridObject void RemoveRewardedQuest(uint32 questId, bool update = true); void SendQuestUpdate(uint32 questId); QuestGiverStatus GetQuestDialogStatus(Object* questGiver); + bool SatisfyFirstLFGReward(uint32 dungeonId, uint8 maxRewCount) const; + uint8 GetFirstRewardCountForDungeonId(uint32 dungeon); void SetDailyQuestStatus(uint32 quest_id); bool IsDailyQuestDone(uint32 quest_id); void SetWeeklyQuestStatus(uint32 quest_id); void SetMonthlyQuestStatus(uint32 quest_id); void SetSeasonalQuestStatus(uint32 quest_id); + void SetLFGRewardStatus(uint32 dungeon_id); void ResetDailyQuestStatus(); void ResetWeeklyQuestStatus(); void ResetMonthlyQuestStatus(); void ResetSeasonalQuestStatus(uint16 event_id); + void ResetLFGRewardStatus(); uint16 FindQuestSlot(uint32 quest_id) const; uint32 GetQuestSlotQuestId(uint16 slot) const; @@ -2186,9 +2191,6 @@ class TC_GAME_API Player : public Unit, public GridObject bool HasValidLFGLeavePoint(uint32 mapid); void SetLFGLeavePoint(); - typedef std::set DFQuestsDoneList; - DFQuestsDoneList m_DFQuests; - // Temporarily removed pet cache uint32 GetTemporaryUnsummonedPetNumber() const { return m_temporaryUnsummonedPetNumber; } void SetTemporaryUnsummonedPetNumber(uint32 petnumber) { m_temporaryUnsummonedPetNumber = petnumber; } @@ -2400,10 +2402,13 @@ class TC_GAME_API Player : public Unit, public GridObject typedef std::set QuestSet; typedef std::set SeasonalQuestSet; typedef std::unordered_map SeasonalEventQuestMap; + typedef std::unordered_map LFGRewardStatusMap; + QuestSet m_timedquests; QuestSet m_weeklyquests; QuestSet m_monthlyquests; SeasonalEventQuestMap m_seasonalquests; + LFGRewardStatusMap m_lfgrewardstatus; ObjectGuid m_playerSharingQuest; uint32 m_sharedQuestId; @@ -2442,6 +2447,7 @@ class TC_GAME_API Player : public Unit, public GridObject void _LoadInstanceTimeRestrictions(PreparedQueryResult result); void _LoadCurrency(PreparedQueryResult result); void _LoadCUFProfiles(PreparedQueryResult result); + void _LoadLFGRewardStatus(PreparedQueryResult result); /*********************************************************/ /*** SAVE SYSTEM ***/ @@ -2467,6 +2473,7 @@ class TC_GAME_API Player : public Unit, public GridObject void _SaveInstanceTimeRestrictions(SQLTransaction& trans); void _SaveCurrency(SQLTransaction& trans); void _SaveCUFProfiles(SQLTransaction& trans); + void _SaveLFGRewardStatus(SQLTransaction& trans); /*********************************************************/ /*** ENVIRONMENTAL SYSTEM ***/ @@ -2577,6 +2584,7 @@ class TC_GAME_API Player : public Unit, public GridObject bool m_WeeklyQuestChanged; bool m_MonthlyQuestChanged; bool m_SeasonalQuestChanged; + bool m_LFGRewardStatusChanged; time_t m_lastDailyQuestTime; uint32 m_hostileReferenceCheckTimer; diff --git a/src/server/game/Handlers/CharacterHandler.cpp b/src/server/game/Handlers/CharacterHandler.cpp index b9ed8bbcdf1..505104d545e 100644 --- a/src/server/game/Handlers/CharacterHandler.cpp +++ b/src/server/game/Handlers/CharacterHandler.cpp @@ -230,6 +230,10 @@ bool LoginQueryHolder::Initialize() stmt->setUInt64(0, lowGuid); res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_ALL_PETS, stmt); + stmt = CharacterDatabase.GetPreparedStatement(CHAR_SEL_CHARACTER_REWARDSTATUS_LFG); + stmt->setUInt32(0, lowGuid); + res &= SetPreparedQuery(PLAYER_LOGIN_QUERY_LOAD_LFG_REWARD_STATUS, stmt); + return res; } diff --git a/src/server/game/Handlers/LFGHandler.cpp b/src/server/game/Handlers/LFGHandler.cpp index 3ac358f0cf3..e820a8bb956 100644 --- a/src/server/game/Handlers/LFGHandler.cpp +++ b/src/server/game/Handlers/LFGHandler.cpp @@ -323,6 +323,9 @@ void WorldSession::SendLfgPlayerLockInfo() if (quest) { firstCompletion = player->CanRewardQuest(quest, false); + if (reward->completionsPerWeek) + firstCompletion = player->SatisfyFirstLFGReward(dungeonId & 0x00FFFFFF, reward->completionsPerWeek); + if (!firstCompletion) quest = sObjectMgr->GetQuestTemplate(reward->otherQuest); } @@ -337,7 +340,7 @@ void WorldSession::SendLfgPlayerLockInfo() CurrencyTypesEntry const* currency = sCurrencyTypesStore.LookupEntry(CURRENCY_TYPE_VALOR_POINTS); - if (currency && rewValorPoints && !quest->IsWeekly()) + if (currency && rewValorPoints && !reward->completionsPerWeek) { data << uint32(rewValorPoints); // currencyQuantity (valor points from selected dungeon) data << uint32(player->GetCurrencyWeekCap(currency)); // some sort of overall cap/weekly cap @@ -352,6 +355,21 @@ void WorldSession::SendLfgPlayerLockInfo() data << uint32(0); // purseLimit data << uint32(rewValorPoints); // some sort of reward for completion } + else if (firstCompletion && reward && reward->completionsPerWeek) + { + data << uint32(1); // currencyQuantity + data << uint32(reward->completionsPerWeek); // some sort of overall cap/weekly cap + data << uint32(0); // currencyID + data << uint32(0); // tier1Quantity + data << uint32(reward->completionsPerWeek); // tier1Limit + data << uint32(player->GetFirstRewardCountForDungeonId(dungeonId & 0x00FFFFFF)); // overallQuantity + data << uint32(reward->completionsPerWeek); // overallLimit + data << uint32(0); // periodPurseQuantity + data << uint32(0); // periodPurseLimit + data << uint32(0); // purseQuantity + data << uint32(0); // purseLimit + data << uint32(1); // some sort of reward for completion + } else { data << uint32(0); // currencyQuantity @@ -762,7 +780,6 @@ void WorldSession::SendLfgPlayerReward(lfg::LfgPlayerRewardData const& rewardDat GetPlayerInfo().c_str(), rewardData.rdungeonEntry, rewardData.sdungeonEntry, rewardData.done); uint8 itemNum = rewardData.quest->GetRewItemsCount() + rewardData.quest->GetRewCurrencyCount(); - WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); data << uint32(rewardData.rdungeonEntry); // Random Dungeon Finished data << uint32(rewardData.sdungeonEntry); // Dungeon Finished diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index b595167b84f..ab9d30a91bb 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -2200,7 +2200,7 @@ void World::Update(uint32 diff) /// Handle weekly quests reset time if (currentGameTime > m_NextWeeklyQuestReset) - ResetWeeklyQuests(); + ResetWeeklyQuestsAndRewards(); /// Handle monthly quests reset time if (currentGameTime > m_NextMonthlyQuestReset) @@ -3204,16 +3204,26 @@ void World::SetPlayerSecurityLimit(AccountTypes _sec) KickAllLess(m_allowedSecurityLevel); } -void World::ResetWeeklyQuests() +void World::ResetWeeklyQuestsAndRewards() { - TC_LOG_INFO("misc", "Weekly quests reset for all characters."); + TC_LOG_INFO("misc", "Weekly quests and rewards reset for all characters."); + // Reset Weekly quests PreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_QUESTSTATUS_WEEKLY); CharacterDatabase.Execute(stmt); + // Reset Weekly lfg rewards + stmt = CharacterDatabase.GetPreparedStatement(CHAR_DEL_RESET_CHARACTER_REWARDSTATUS_LFG); + CharacterDatabase.Execute(stmt); + for (SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr) + { if (itr->second->GetPlayer()) + { itr->second->GetPlayer()->ResetWeeklyQuestStatus(); + itr->second->GetPlayer()->ResetLFGRewardStatus(); + } + } m_NextWeeklyQuestReset = time_t(m_NextWeeklyQuestReset + WEEK); sWorld->setWorldState(WS_WEEKLY_QUEST_RESET_TIME, uint64(m_NextWeeklyQuestReset)); diff --git a/src/server/game/World/World.h b/src/server/game/World/World.h index 2038f09a43a..764388d9fdd 100644 --- a/src/server/game/World/World.h +++ b/src/server/game/World/World.h @@ -822,7 +822,7 @@ class TC_GAME_API World void InitGuildResetTime(); void InitCurrencyResetTime(); void ResetDailyQuests(); - void ResetWeeklyQuests(); + void ResetWeeklyQuestsAndRewards(); void ResetMonthlyQuests(); void ResetRandomBG(); void ResetGuildCap();