diff options
| -rw-r--r-- | sql/base/world_database.sql | 48 | ||||
| -rw-r--r-- | sql/updates/9743_world_command.sql | 4 | ||||
| -rw-r--r-- | sql/updates/9743_world_lfg_dungeon_encounters.sql | 6 | ||||
| -rw-r--r-- | sql/updates/9743_world_lfg_dungeon_rewards.sql | 12 | ||||
| -rw-r--r-- | src/server/game/Achievements/AchievementMgr.cpp | 9 | ||||
| -rw-r--r-- | src/server/game/Chat/Chat.cpp | 2 | ||||
| -rw-r--r-- | src/server/game/Chat/Chat.h | 2 | ||||
| -rw-r--r-- | src/server/game/Chat/Commands/Level3.cpp | 17 | ||||
| -rw-r--r-- | src/server/game/DataStores/DBCStructure.h | 6 | ||||
| -rw-r--r-- | src/server/game/DungeonFinding/LFGMgr.cpp | 380 | ||||
| -rw-r--r-- | src/server/game/DungeonFinding/LFGMgr.h | 104 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 16 | ||||
| -rw-r--r-- | src/server/game/Entities/Player/Player.h | 1 | ||||
| -rw-r--r-- | src/server/game/World/World.cpp | 6 |
14 files changed, 434 insertions, 179 deletions
diff --git a/sql/base/world_database.sql b/sql/base/world_database.sql index f74f8bbbcab..d5fe2a57039 100644 --- a/sql/base/world_database.sql +++ b/sql/base/world_database.sql @@ -592,6 +592,8 @@ INSERT INTO `command` VALUES ('reload item_enchantment_template',3,'Syntax: .reload item_enchantment_template\nReload item_enchantment_template table.'), ('reload item_loot_template',3,'Syntax: .reload item_loot_template\nReload item_loot_template table.'), ('reload item_set_names',3,'Syntax: .reload item_set_names\nReload item_set_names table.'), +('reload lfg_dungeon_encounters',3,'Syntax: .reload lfg_dungeon_encounters\nReload lfg_dungeon_encounters table.'), +('reload lfg_dungeon_rewards',3,'Syntax: .reload lfg_dungeon_rewards\nReload lfg_dungeon_rewards table.'), ('reload locales_creature',3,'Syntax: .reload locales_creature\nReload locales_creature table.'), ('reload locales_gameobject',3,'Syntax: .reload locales_gameobject\nReload locales_gameobject table.'), ('reload locales_gossip_menu_option',3, 'Syntax: .reload locales_gossip_menu_option\nReload locales_gossip_menu_option table.'), @@ -3091,6 +3093,52 @@ LOCK TABLES `item_template` WRITE; UNLOCK TABLES; -- +-- Table structure for table `lfg_dungeon_encounters` +-- + +DROP TABLE IF EXISTS `lfg_dungeon_encounters`; +CREATE TABLE `lfg_dungeon_encounters` ( + `achievementId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Achievement marking final boss completion', + `dungeonId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Dungeon entry from dbc', + PRIMARY KEY (`achievementId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `lfg_dungeon_encounters` +-- + +LOCK TABLES `lfg_dungeon_encounters` WRITE; +/*!40000 ALTER TABLE `lfg_dungeon_encounters` DISABLE KEYS */; +/*!40000 ALTER TABLE `lfg_dungeon_encounters` ENABLE KEYS */; +UNLOCK TABLES; + +-- +-- Table structure for table `lfg_dungeon_rewards` +-- + +DROP TABLE IF EXISTS `lfg_dungeon_rewards`; +CREATE TABLE `lfg_dungeon_rewards` ( + `dungeonId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Dungeon entry from dbc', + `maxLevel` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Max level at which this reward is rewarded', + `firstQuestId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest id with rewards for first dungeon this day', + `firstMoneyVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Money multiplier for completing the dungeon first time in a day with less players than max', + `firstXPVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Experience multiplier for completing the dungeon first time in a day with less players than max', + `otherQuestId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest id with rewards for Nth dungeon this day', + `otherMoneyVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Money multiplier for completing the dungeon Nth time in a day with less players than max', + `otherXPVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Experience multiplier for completing the dungeon Nth time in a day with less players than max', + PRIMARY KEY (`dungeonId`,`maxLevel`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Dumping data for table `lfg_dungeon_rewards` +-- + +LOCK TABLES `lfg_dungeon_rewards` WRITE; +/*!40000 ALTER TABLE `lfg_dungeon_rewards` DISABLE KEYS */; +/*!40000 ALTER TABLE `lfg_dungeon_rewards` ENABLE KEYS */; +UNLOCK TABLES; + +-- -- Table structure for table `locales_achievement_reward` -- diff --git a/sql/updates/9743_world_command.sql b/sql/updates/9743_world_command.sql new file mode 100644 index 00000000000..4309c51db98 --- /dev/null +++ b/sql/updates/9743_world_command.sql @@ -0,0 +1,4 @@ +DELETE FROM `command` WHERE `name` IN ('reload lfg_dungeon_encounters','reload lfg_dungeon_rewards'); +INSERT INTO `command` (`name`,`security`,`help`) VALUES +('reload lfg_dungeon_encounters',3,'Syntax: .reload lfg_dungeon_encounters\nReload lfg_dungeon_encounters table.'), +('reload lfg_dungeon_rewards',3,'Syntax: .reload lfg_dungeon_rewards\nReload lfg_dungeon_rewards table.'); diff --git a/sql/updates/9743_world_lfg_dungeon_encounters.sql b/sql/updates/9743_world_lfg_dungeon_encounters.sql new file mode 100644 index 00000000000..2e436b0edb2 --- /dev/null +++ b/sql/updates/9743_world_lfg_dungeon_encounters.sql @@ -0,0 +1,6 @@ +DROP TABLE IF EXISTS `lfg_dungeon_encounters`; +CREATE TABLE `lfg_dungeon_encounters` ( + `achievementId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Achievement marking final boss completion', + `dungeonId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Dungeon entry from dbc', + PRIMARY KEY (`achievementId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/9743_world_lfg_dungeon_rewards.sql b/sql/updates/9743_world_lfg_dungeon_rewards.sql new file mode 100644 index 00000000000..0b762b59aca --- /dev/null +++ b/sql/updates/9743_world_lfg_dungeon_rewards.sql @@ -0,0 +1,12 @@ +DROP TABLE IF EXISTS `lfg_dungeon_rewards`; +CREATE TABLE `lfg_dungeon_rewards` ( + `dungeonId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Dungeon entry from dbc', + `maxLevel` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT 'Max level at which this reward is rewarded', + `firstQuestId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest id with rewards for first dungeon this day', + `firstMoneyVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Money multiplier for completing the dungeon first time in a day with less players than max', + `firstXPVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Experience multiplier for completing the dungeon first time in a day with less players than max', + `otherQuestId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Quest id with rewards for Nth dungeon this day', + `otherMoneyVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Money multiplier for completing the dungeon Nth time in a day with less players than max', + `otherXPVar` int(10) unsigned NOT NULL DEFAULT '0' COMMENT 'Experience multiplier for completing the dungeon Nth time in a day with less players than max', + PRIMARY KEY (`dungeonId`,`maxLevel`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index d91ae2eec0c..ad1aef0b42a 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -39,6 +39,7 @@ #include "BattlegroundAB.h" #include "Map.h" #include "InstanceScript.h" +#include "LFGMgr.h" namespace Trinity { @@ -744,6 +745,7 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_QUEST_ABANDONED: case ACHIEVEMENT_CRITERIA_TYPE_FLIGHT_PATHS_TAKEN: case ACHIEVEMENT_CRITERIA_TYPE_ACCEPTED_SUMMONINGS: + case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: // AchievementMgr::UpdateAchievementCriteria might also be called on login - skip in this case if (!miscvalue1) continue; @@ -1476,9 +1478,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui case ACHIEVEMENT_CRITERIA_TYPE_EARNED_PVP_TITLE: case ACHIEVEMENT_CRITERIA_TYPE_KILL_CREATURE_TYPE: case ACHIEVEMENT_CRITERIA_TYPE_TOTAL: - case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: break; // Not implemented yet :( } + if (IsCompletedCriteria(achievementCriteria,achievement)) CompletedCriteriaFor(achievement); @@ -1496,6 +1498,9 @@ void AchievementMgr::UpdateAchievementCriteria(AchievementCriteriaTypes type, ui if (IsCompletedAchievement(*itr)) CompletedAchievement(*itr); } + + if (const uint32 dungeonId = sLFGMgr.GetDungeonIdForAchievement(achievement->ID)) + sLFGMgr.RewardDungeonDoneFor(dungeonId, GetPlayer()); } } @@ -1625,6 +1630,8 @@ bool AchievementMgr::IsCompletedCriteria(AchievementCriteriaEntry const* achieve return progress->counter >= achievementCriteria->honorable_kill.killCount; case ACHIEVEMENT_CRITERIA_TYPE_EARN_ACHIEVEMENT_POINTS: return progress->counter >= 9000; + case ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS: + return progress->counter >= achievementCriteria->use_lfg.dungeonsComplete; // handle all statistic-only criteria here case ACHIEVEMENT_CRITERIA_TYPE_COMPLETE_BATTLEGROUND: case ACHIEVEMENT_CRITERIA_TYPE_DEATH_AT_MAP: diff --git a/src/server/game/Chat/Chat.cpp b/src/server/game/Chat/Chat.cpp index 9ff18aba367..581145a1e5f 100644 --- a/src/server/game/Chat/Chat.cpp +++ b/src/server/game/Chat/Chat.cpp @@ -492,6 +492,8 @@ ChatCommand * ChatHandler::getCommandTable() { "item_enchantment_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemEnchantementsCommand, "", NULL }, { "item_loot_template", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLootTemplatesItemCommand, "", NULL }, { "item_set_names", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadItemSetNamesCommand, "", NULL }, + { "lfg_dungeon_encounters", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLfgEncountersCommand, "", NULL }, + { "lfg_dungeon_rewards", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLfgRewardsCommand, "", NULL }, { "locales_achievement_reward", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesAchievementRewardCommand,"", NULL }, { "locales_creature", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesCreatureCommand, "", NULL }, { "locales_gameobject", SEC_ADMINISTRATOR, true, &ChatHandler::HandleReloadLocalesGameobjectCommand, "", NULL }, diff --git a/src/server/game/Chat/Chat.h b/src/server/game/Chat/Chat.h index 6e84ae67511..b966a76c622 100644 --- a/src/server/game/Chat/Chat.h +++ b/src/server/game/Chat/Chat.h @@ -387,6 +387,8 @@ class ChatHandler bool HandleReloadGOQuestInvRelationsCommand(const char* args); bool HandleReloadItemEnchantementsCommand(const char* args); bool HandleReloadItemSetNamesCommand(const char* args); + bool HandleReloadLfgEncountersCommand(const char* args); + bool HandleReloadLfgRewardsCommand(const char* args); bool HandleReloadLocalesAchievementRewardCommand(const char* args); bool HandleReloadLocalesCreatureCommand(const char* args); bool HandleReloadLocalesGameobjectCommand(const char* args); diff --git a/src/server/game/Chat/Commands/Level3.cpp b/src/server/game/Chat/Commands/Level3.cpp index ee1dddc966a..de5c99e27ba 100644 --- a/src/server/game/Chat/Commands/Level3.cpp +++ b/src/server/game/Chat/Commands/Level3.cpp @@ -59,6 +59,7 @@ #include "Transport.h" #include "WeatherMgr.h" #include "ScriptMgr.h" +#include "LFGMgr.h" //reload commands bool ChatHandler::HandleReloadAllCommand(const char*) @@ -1055,6 +1056,22 @@ bool ChatHandler::HandleReloadLocalesAchievementRewardCommand(const char*) return true; } +bool ChatHandler::HandleReloadLfgEncountersCommand(const char*) +{ + sLog.outString("Re-Loading dungeon encounter lfg associations..."); + sLFGMgr.LoadDungeonEncounters(); + SendGlobalGMSysMessage("DB table `lfg_dungeon_encounters` reloaded."); + return true; +} + +bool ChatHandler::HandleReloadLfgRewardsCommand(const char*) +{ + sLog.outString("Re-Loading lfg dungeon rewards..."); + sLFGMgr.LoadRewards(); + SendGlobalGMSysMessage("DB table `lfg_dungeon_rewards` reloaded."); + return true; +} + bool ChatHandler::HandleReloadLocalesCreatureCommand(const char* /*arg*/) { sLog.outString("Re-Loading Locales Creature ..."); diff --git a/src/server/game/DataStores/DBCStructure.h b/src/server/game/DataStores/DBCStructure.h index 14876543a5c..e9297f29cfb 100644 --- a/src/server/game/DataStores/DBCStructure.h +++ b/src/server/game/DataStores/DBCStructure.h @@ -483,6 +483,12 @@ struct AchievementCriteriaEntry struct { + uint32 unused; + uint32 dungeonsComplete; + } use_lfg; + + struct + { uint32 field3; // 3 main requirement uint32 count; // 4 main requirement count } raw; diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 49bcaffdc5a..056ffed393c 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -25,6 +25,7 @@ #include "ObjectMgr.h" #include "DisableMgr.h" #include "WorldPacket.h" +#include "ProgressBar.h" LFGMgr::LFGMgr() { @@ -43,15 +44,11 @@ LFGMgr::LFGMgr() LFGMgr::~LFGMgr() { - // FIXME: RewardList to be removed -> query quest system - for (LfgRewardList::iterator it = m_RewardList.begin(); it != m_RewardList.end(); ++it) - delete *it; - m_RewardList.clear(); + for (LfgRewardMap::iterator itr = m_RewardMap.begin(); itr != m_RewardMap.end(); ++itr) + delete itr->second; + m_RewardMap.clear(); - // FIXME: RewardDoneList to be removed -> query quest system - for (LfgRewardList::iterator it = m_RewardDoneList.begin(); it != m_RewardDoneList.end(); ++it) - delete *it; - m_RewardDoneList.clear(); + m_EncountersByAchievement.clear(); for (LfgQueueInfoMap::iterator it = m_QueueInfoMap.begin(); it != m_QueueInfoMap.end(); ++it) delete it->second; @@ -363,40 +360,138 @@ void LFGMgr::Update(uint32 diff) /// </summary> void LFGMgr::InitLFG() { - // Fill reward data (to be removed -> query quest system) - LfgReward *reward; - for (uint8 i = 0; i <= LFG_REWARD_DATA_SIZE; ++i) - { - reward = new LfgReward(); - reward->strangers = 0; - reward->baseXP = RewardDungeonData[i][0]; - reward->baseMoney = RewardDungeonData[i][1]; - reward->variableMoney = 0; - reward->variableXP = 0; - reward->itemId = RewardDungeonData[i][2]; - reward->displayId = RewardDungeonData[i][3]; - reward->stackCount = RewardDungeonData[i][4]; - m_RewardList.push_back(reward); - } - - for (uint8 i = 0; i < LFG_REWARD_DATA_SIZE; ++i) - { - reward = new LfgReward(); - reward->strangers = 0; - reward->baseXP = RewardDungeonDoneData[i][0]; - reward->baseMoney = RewardDungeonDoneData[i][1]; - reward->variableMoney = 0; - reward->variableXP = 0; - reward->itemId = RewardDungeonDoneData[i][2]; - reward->displayId = RewardDungeonDoneData[i][3]; - reward->stackCount = RewardDungeonDoneData[i][4]; - m_RewardDoneList.push_back(reward); - } // Initialize dungeonMap GetAllDungeons(); } /// <summary> +/// Load achievement <-> encounter associations +/// </summary> +void LFGMgr::LoadDungeonEncounters() +{ + m_EncountersByAchievement.clear(); + + uint32 count = 0; + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT achievementId, dungeonId FROM lfg_dungeon_encounters"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 dungeon encounter lfg associations. DB table `lfg_dungeon_encounters` is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + Field* fields = NULL; + do + { + fields = result->Fetch(); + uint32 achievementId = fields[0].GetUInt32(); + uint32 dungeonId = fields[1].GetUInt32(); + + if (AchievementEntry const* achievement = sAchievementStore.LookupEntry(achievementId)) + { + if (!(achievement->flags & ACHIEVEMENT_FLAG_COUNTER)) + { + sLog.outErrorDb("Achievement %u specified in table `lfg_dungeon_encounters` is not a statistic!", achievementId); + continue; + } + } + else + { + sLog.outErrorDb("Achievement %u specified in table `lfg_dungeon_encounters` does not exist!", achievementId); + continue; + } + + if (!sLFGDungeonStore.LookupEntry(dungeonId)) + { + sLog.outErrorDb("Dungeon %u specified in table `lfg_dungeon_encounters` does not exist!", dungeonId); + continue; + } + + m_EncountersByAchievement[achievementId] = dungeonId; + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u dungeon encounter lfg associations.", count); +} + +/// <summary> +/// Load rewards for completing dungeons +/// </summary> +void LFGMgr::LoadRewards() +{ + for (LfgRewardMap::iterator itr = m_RewardMap.begin(); itr != m_RewardMap.end(); ++itr) + delete itr->second; + m_RewardMap.clear(); + + uint32 count = 0; + // ORDER BY is very important for GetRandomDungeonReward! + QueryResult_AutoPtr result = WorldDatabase.Query("SELECT dungeonId, maxLevel, firstQuestId, firstMoneyVar, firstXPVar, otherQuestId, otherMoneyVar, otherXPVar FROM lfg_dungeon_rewards ORDER BY dungeonId, maxLevel ASC"); + + if (!result) + { + barGoLink bar(1); + bar.step(); + + sLog.outString(); + sLog.outErrorDb(">> Loaded 0 lfg dungeon rewards. DB table `lfg_dungeon_rewards` is empty!"); + return; + } + + barGoLink bar(result->GetRowCount()); + + Field* fields = NULL; + do + { + fields = result->Fetch(); + uint32 dungeonId = fields[0].GetUInt32(); + uint32 maxLevel = fields[1].GetUInt8(); + uint32 firstQuestId = fields[2].GetUInt32(); + uint32 firstMoneyVar = fields[3].GetUInt32(); + uint32 firstXPVar = fields[4].GetUInt32(); + uint32 otherQuestId = fields[5].GetUInt32(); + uint32 otherMoneyVar = fields[6].GetUInt32(); + uint32 otherXPVar = fields[7].GetUInt32(); + + if (!sLFGDungeonStore.LookupEntry(dungeonId)) + { + sLog.outErrorDb("Dungeon %u specified in table `lfg_dungeon_rewards` does not exist!", dungeonId); + continue; + } + + if (!maxLevel || maxLevel > sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + { + sLog.outErrorDb("Level %u specified for dungeon %u in table `lfg_dungeon_rewards` can never be reached!", maxLevel, dungeonId); + maxLevel = sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL); + } + + if (firstQuestId && !sObjectMgr.GetQuestTemplate(firstQuestId)) + { + sLog.outErrorDb("First quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", firstQuestId, dungeonId); + firstQuestId = 0; + } + + if (otherQuestId && !sObjectMgr.GetQuestTemplate(otherQuestId)) + { + sLog.outErrorDb("Other quest %u specified for dungeon %u in table `lfg_dungeon_rewards` does not exist!", otherQuestId, dungeonId); + otherQuestId = 0; + } + + m_RewardMap.insert(LfgRewardMap::value_type(dungeonId, new LfgReward(maxLevel, firstQuestId, firstMoneyVar, firstXPVar, otherQuestId, otherMoneyVar, otherXPVar))); + ++count; + } while (result->NextRow()); + + sLog.outString(); + sLog.outString(">> Loaded %u lfg dungeon rewards.", count); +} + +/// <summary> /// Adds the player/group to lfg queue /// </summary> /// <param name="Player *">Player</param> @@ -1566,24 +1661,47 @@ void LFGMgr::SendLfgPlayerInfo(Player *plr) data << uint8(0); else { - LfgReward *reward; + LfgReward const* reward = NULL; + Quest const* qRew = NULL; + data << uint8(randomlist->size()); // Random Dungeon count for (LfgDungeonSet::iterator it = randomlist->begin(); it != randomlist->end(); ++it) { done = plr->isLfgDungeonDone(*it); - reward = GetRandomDungeonReward(*it, done, plr->getLevel()); + reward = GetRandomDungeonReward(*it, plr->getLevel()); data << uint32(*it); // Entry data << uint8(done); - data << uint32(reward->baseMoney); - data << uint32(reward->baseXP); - data << uint32(reward->variableMoney); - data << uint32(reward->variableXP); - data << uint8(reward->itemId != 0); - if (reward->itemId) + if (reward) { - data << uint32(reward->itemId); - data << uint32(reward->displayId); - data << uint32(reward->stackCount); + qRew = sObjectMgr.GetQuestTemplate(reward->reward[done].questId); + data << uint32(qRew ? qRew->GetRewOrReqMoney() : 0); + data << uint32(qRew ? qRew->XPValue(plr) : 0); + data << uint32(reward->reward[done].variableMoney); + data << uint32(reward->reward[done].variableXP); + data << uint8(qRew ? qRew->GetRewItemsCount() : 0); + if (qRew && qRew->GetRewItemsCount()) + { + ItemPrototype const* iProto = NULL; + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (!qRew->RewItemId[i]) + continue; + + iProto = ObjectMgr::GetItemPrototype(qRew->RewItemId[i]); + + data << uint32(qRew->RewItemId[i]); + data << uint32(iProto ? iProto->DisplayInfoID : 0); + data << uint32(qRew->RewItemCount[i]); + } + } + } + else + { + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint8(0); } } randomlist->clear(); @@ -1661,29 +1779,55 @@ void LFGMgr::SendLfgPlayerReward(Player *plr) if (plr->GetGroup()) sdungeonId = plr->GetGroup()->GetLfgDungeonEntry(false); bool done = plr->isLfgDungeonDone(rdungeonId); - LfgReward *reward = GetRandomDungeonReward(rdungeonId, done, plr->getLevel()); - if (!reward) - return; + LfgReward const* reward = GetRandomDungeonReward(rdungeonId, plr->getLevel()); - uint8 itemNum = uint8(reward->itemId != 0); + uint8 itemNum = 0; + Quest const* qRew = NULL; + if (reward) + { + qRew = sObjectMgr.GetQuestTemplate(reward->reward[done].questId); + if (qRew) + itemNum = qRew->GetRewItemsCount(); + } sLog.outDebug("SMSG_LFG_PLAYER_REWARD"); WorldPacket data(SMSG_LFG_PLAYER_REWARD, 4 + 4 + 1 + 4 + 4 + 4 + 4 + 4 + 1 + itemNum * (4 + 4 + 4)); data << uint32(rdungeonId); // Random Dungeon Finished data << uint32(sdungeonId); // Dungeon Finished data << uint8(done); - data << uint32(reward->strangers); - data << uint32(reward->baseMoney); - data << uint32(reward->baseXP); - data << uint32(reward->variableMoney); - data << uint32(reward->variableXP); - data << uint8(itemNum); - if (itemNum) - { - data << uint32(reward->itemId); - data << uint32(reward->displayId); - data << uint32(reward->stackCount); + data << uint32(reward ? 1 : 0); + if (reward) + { + data << uint32(qRew ? qRew->GetRewOrReqMoney() : 0); + data << uint32(qRew ? qRew->XPValue(plr) : 0); + data << uint32(reward->reward[done].variableMoney); + data << uint32(reward->reward[done].variableXP); + data << uint8(itemNum); + if (qRew && itemNum) + { + ItemPrototype const* iProto = NULL; + for (uint8 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (!qRew->RewItemId[i]) + continue; + + iProto = ObjectMgr::GetItemPrototype(qRew->RewItemId[i]); + + data << uint32(qRew->RewItemId[i]); + data << uint32(iProto ? iProto->DisplayInfoID : 0); + data << uint32(qRew->RewItemCount[i]); + } + } } + else + { + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint32(0); + data << uint8(0); + } + plr->GetSession()->SendPacket(&data); } @@ -1733,6 +1877,65 @@ void LFGMgr::BuildPlayerLockDungeonBlock(WorldPacket &data, LfgLockStatusSet *lo delete lockSet; } +/// <summary> +/// Give completion reward to player +/// </summary> +/// <param name="const uint32">dungeonId</param> +/// <param name="Player *">player</param> +void LFGMgr::RewardDungeonDoneFor(const uint32 dungeonId, Player *player) +{ + player->GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_USE_LFD_TO_GROUP_WITH_PLAYERS, 1); + + if (isRandomDungeon(dungeonId)) + player->SetLfgDungeonDone(dungeonId); + + LfgReward const* reward = GetRandomDungeonReward(dungeonId, player->getLevel()); + if (!reward) + return; + + uint8 index = player->isLfgDungeonDone(dungeonId) ? 1 : 0; + Quest const* qReward = sObjectMgr.GetQuestTemplate(reward->reward[index].questId); + if (!qReward) + return; + + if (qReward->GetRewItemsCount() > 0) + { + for (uint32 i = 0; i < QUEST_REWARDS_COUNT; ++i) + { + if (uint32 itemId = qReward->RewItemId[i]) + { + ItemPosCountVec dest; + if (player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, itemId, qReward->RewItemCount[i]) == EQUIP_ERR_OK) + { + Item* item = player->StoreNewItem(dest, itemId, true, Item::GenerateItemRandomPropertyId(itemId)); + player->SendNewItem(item, qReward->RewItemCount[i], true, false); + } + } + } + } + + // Not give XP in case already completed once repeatable quest + uint32 XP = qReward->XPValue(player) * sWorld.getRate(RATE_XP_QUEST); + + Group* group = player->GetGroup(); + if (group) + XP += (5 - group->GetMembersCount()) * reward->reward[index].variableXP; + + // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative + int32 moneyRew = qReward->GetRewOrReqMoney(); + + if (player->getLevel() < sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) + player->GiveXP(XP, NULL); + else + moneyRew += int32(qReward->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)); + + if (group) + moneyRew += (5 - group->GetMembersCount()) * reward->reward[index].variableMoney; + + if (moneyRew) + player->ModifyMoney(moneyRew); +} + // --------------------------------------------------------------------------// // Auxiliar Functions // --------------------------------------------------------------------------// @@ -1945,47 +2148,22 @@ LfgDungeonSet* LFGMgr::GetRandomDungeons(uint8 level, uint8 expansion) /// Get the reward of a given random dungeon at a certain level /// </summary> /// <param name="uint32">random dungeon id</param> -/// <param name="bool">Dungeon previously done</param> /// <param name="uint8">Player level</param> -/// <returns>LfgReward*</returns> -LfgReward* LFGMgr::GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level) +/// <returns>LfgReward const*</returns> +LfgReward const* LFGMgr::GetRandomDungeonReward(uint32 dungeon, uint8 level) { + LfgReward const* rew = NULL; + LfgRewardMapBounds bounds = m_RewardMap.equal_range(dungeon & 0x00FFFFFF); uint8 index = 0; - switch((dungeon & 0x00FFFFFF)) // Get dungeon id from dungeon entry - { - case LFG_RANDOM_CLASSIC: - if (level < 15) - index = LFG_REWARD_LEVEL0; - else if (level < 24) - index = LFG_REWARD_LEVEL1; - else if (level < 35) - index = LFG_REWARD_LEVEL2; - else if (level < 46) - index = LFG_REWARD_LEVEL3; - else if (level < 56) - index = LFG_REWARD_LEVEL4; - else - index = LFG_REWARD_LEVEL5; - break; - case LFG_RANDOM_BC_NORMAL: - index = LFG_REWARD_BC_NORMAL; - break; - case LFG_RANDOM_BC_HEROIC: - index = LFG_REWARD_BC_HEROIC; - break; - case LFG_RANDOM_LK_NORMAL: - index = level == 80 ? LFG_REWARD_LK_NORMAL80 : LFG_REWARD_LK_NORMAL; - break; - case LFG_RANDOM_LK_HEROIC: - index = LFG_REWARD_LK_HEROIC; - break; - default: // This should never happen! - done = false; - index = LFG_REWARD_LEVEL0; - sLog.outError("LFGMgr::GetRandomDungeonReward: Dungeon %u is not random dungeon!", dungeon); - break; - } - return done ? m_RewardDoneList.at(index) : m_RewardList.at(index); + for (LfgRewardMap::const_iterator itr = bounds.first; itr != bounds.second; ++itr) + { + rew = itr->second; + // ordered properly at loading + if (itr->second->maxLevel >= level) + break; + } + + return rew; } /// <summary> diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 25e7d431174..cc932c5817f 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -131,62 +131,6 @@ enum LfgRoleCheckResult LFG_ROLECHECK_NO_ROLE = 6, // Someone selected no role }; -// TODO: Remove me, will not be needed when Reward moved to quest system -enum LfgRandomDungeonEntries -{ - LFG_ALL_DUNGEONS = 0, - LFG_RANDOM_CLASSIC = 258, - LFG_RANDOM_BC_NORMAL = 259, - LFG_RANDOM_BC_HEROIC = 260, - LFG_RANDOM_LK_NORMAL = 261, - LFG_RANDOM_LK_HEROIC = 262, -}; - -enum LfgRewardEnums -{ - LFG_REWARD_LEVEL0 = 10, - LFG_REWARD_LEVEL1 = 0, - LFG_REWARD_LEVEL2 = 1, - LFG_REWARD_LEVEL3 = 2, - LFG_REWARD_LEVEL4 = 3, - LFG_REWARD_LEVEL5 = 4, - LFG_REWARD_BC_NORMAL = 5, - LFG_REWARD_BC_HEROIC = 6, - LFG_REWARD_LK_NORMAL = 7, - LFG_REWARD_LK_NORMAL80 = 7, - LFG_REWARD_LK_HEROIC = 8, - LFG_REWARD_DATA_SIZE = 10, -}; - -const uint32 RewardDungeonData[LFG_REWARD_DATA_SIZE+1][5] = -{ // XP, money, item, item display, count - {310, 3500, 51999, 56915, 1}, // Classic 15-23 - {470, 7000, 52000, 56915, 1}, // Classic 24-34 - {825, 13000, 52001, 56915, 1}, // Classic 35-45 - {12250, 16500, 52002, 56915, 1}, // Classic 46-55 - {14300, 18000, 52003, 56915, 1}, // Classic 56-60 - {1600, 62000, 52004, 56915, 1}, // BC Normal - {1900, 88000, 52005, 56915, 1}, // BC Heroic - {33100, 148000, 47241, 62232, 2}, // LK Normal - {0, 198600, 47241, 62232, 2}, // LK Normal - Level 80 - {0, 264600, 49426, 64062, 2}, // LK Heroic - {0, 0, 0, 0, 0}, // Classic - No level -}; - -const uint32 RewardDungeonDoneData[LFG_REWARD_DATA_SIZE][5] = -{ // XP, money, item, item display, count - {200, 1800, 51999, 56915, 1}, // Classic 15-23 - {310, 3500, 52000, 56915, 1}, // Classic 24-34 - {550, 6500, 52001, 56915, 1}, // Classic 35-45 - {8150, 8500, 52002, 56915, 1}, // Classic 46-55 - {9550, 9000, 52003, 56915, 1}, // Classic 56-60 - {1100, 31000, 52004, 56915, 1}, // BC Normal - {12650, 44000, 52005, 56915, 1}, // BC Heroic - {16550, 74000, 0, 0, 0}, // LK Normal - {0, 99300, 0, 0, 0}, // LK Normal - Level 80 - {0, 132300, 47241, 62232, 2}, // LK Heroic -}; - // Dungeon and reason why player can't join struct LfgLockStatus { @@ -197,14 +141,24 @@ struct LfgLockStatus // Reward info struct LfgReward { - uint32 strangers; - uint32 baseMoney; - uint32 baseXP; - uint32 variableMoney; - uint32 variableXP; - uint32 itemId; - uint32 displayId; - uint32 stackCount; + uint32 maxLevel; + struct + { + uint32 questId; + uint32 variableMoney; + uint32 variableXP; + } reward[2]; + + LfgReward(uint32 _maxLevel, uint32 firstQuest, uint32 firstVarMoney, uint32 firstVarXp, uint32 otherQuest, uint32 otherVarMoney, uint32 otherVarXp) + : maxLevel(_maxLevel) + { + reward[0].questId = firstQuest; + reward[0].variableMoney = firstVarMoney; + reward[0].variableXP = firstVarXp; + reward[1].questId = otherQuest; + reward[1].variableMoney = otherVarMoney; + reward[1].variableXP = otherVarXp; + } }; typedef std::map<uint32, uint8> LfgRolesMap; @@ -279,14 +233,14 @@ struct LfgPlayerBoot typedef std::set<Player*> PlayerSet; typedef std::set<LfgLockStatus*> LfgLockStatusSet; -typedef std::vector<LfgReward*> LfgRewardList; -typedef std::map<uint32, LfgReward*> LfgRewardMap; typedef std::vector<LfgProposal*> LfgProposalList; typedef std::map<uint32, LfgLockStatusSet*> LfgLockStatusMap; typedef std::map<uint64, LfgQueueInfo*> LfgQueueInfoMap; typedef std::map<uint32, LfgRoleCheck*> LfgRoleCheckMap; typedef std::map<uint32, LfgProposal*> LfgProposalMap; typedef std::map<uint32, LfgPlayerBoot*> LfgPlayerBootMap; +typedef std::multimap<uint32, LfgReward const*> LfgRewardMap; +typedef std::pair<LfgRewardMap::const_iterator, LfgRewardMap::const_iterator> LfgRewardMapBounds; typedef std::list<Player *> LfgPlayerList; class LFGMgr @@ -311,6 +265,18 @@ class LFGMgr bool isRandomDungeon(uint32 dungeonId); void InitBoot(Group *grp, uint32 plowGuid, uint32 vlowGuid, std::string reason); + void LoadDungeonEncounters(); + void LoadRewards(); + void RewardDungeonDoneFor(const uint32 dungeonId, Player* player); + const uint32 GetDungeonIdForAchievement(uint32 achievementId) + { + std::map<uint32, uint32>::iterator itr = m_EncountersByAchievement.find(achievementId); + if (itr != m_EncountersByAchievement.end()) + return itr->second; + + return 0; + } + private: void Cleaner(); void AddGuidToNewQueue(uint64 guid); @@ -337,11 +303,11 @@ class LFGMgr LfgDungeonSet* GetDungeonsByRandom(uint32 randomdungeon); LfgDungeonSet* GetRandomDungeons(uint8 level, uint8 expansion); LfgDungeonSet* GetAllDungeons(); - LfgReward* GetRandomDungeonReward(uint32 dungeon, bool done, uint8 level); + LfgReward const* GetRandomDungeonReward(uint32 dungeon, uint8 level); uint8 GetDungeonGroupType(uint32 dungeon); - LfgRewardList m_RewardList; // TODO: Change it to list of quests - LfgRewardList m_RewardDoneList; // TODO: Change it to list of quests + LfgRewardMap m_RewardMap; // Stores rewards for random dungeons + std::map<uint32, uint32> m_EncountersByAchievement; // Stores dungeon ids associated with achievements (for rewards) LfgDungeonMap m_CachedDungeonMap; // Stores all dungeons by groupType LfgQueueInfoMap m_QueueInfoMap; // Queued groups LfgGuidList m_currentQueue; // Ordered list. Used to find groups diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index ae636dcca5e..ceb6e0605b4 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -14373,22 +14373,22 @@ void Player::RewardQuest(Quest const *pQuest, uint32 reward, Object* questGiver, for (Unit::AuraEffectList::const_iterator i = ModXPPctAuras.begin(); i != ModXPPctAuras.end(); ++i) XP = uint32(XP*(1.0f + (*i)->GetAmount() / 100.0f)); + int32 moneyRew = 0; if (getLevel() < sWorld.getIntConfig(CONFIG_MAX_PLAYER_LEVEL)) GiveXP(XP, NULL); else - { - uint32 money = uint32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)); - ModifyMoney(money); - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, money); - } + moneyRew = int32(pQuest->GetRewMoneyMaxLevel() * sWorld.getRate(RATE_DROP_MONEY)); // Give player extra money if GetRewOrReqMoney > 0 and get ReqMoney if negative if (pQuest->GetRewOrReqMoney()) + moneyRew += pQuest->GetRewOrReqMoney(); + + if (moneyRew) { - ModifyMoney(pQuest->GetRewOrReqMoney()); + ModifyMoney(moneyRew); - if (pQuest->GetRewOrReqMoney() > 0) - GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, pQuest->GetRewOrReqMoney()); + if (moneyRew > 0) + GetAchievementMgr().UpdateAchievementCriteria(ACHIEVEMENT_CRITERIA_TYPE_MONEY_FROM_QUEST_REWARD, uint32(moneyRew)); } // honor reward diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 267abba9e9f..e82b6c823fd 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -2251,6 +2251,7 @@ class Player : public Unit, public GridObject<Player> bool isLfgDungeonDone(const uint32 entry) { return m_LookingForGroup.donerandomDungeons.find(entry) != m_LookingForGroup.donerandomDungeons.end(); } LfgDungeonSet *GetLfgDungeons() { return &m_LookingForGroup.applyDungeons; } LfgDungeonSet *GetLfgDungeonsDone() { return &m_LookingForGroup.donerandomDungeons; } + void SetLfgDungeonDone(const uint32 entry) { m_LookingForGroup.donerandomDungeons.insert(entry); } std::string GetLfgComment() { return m_LookingForGroup.comment; } void SetLfgComment(std::string _comment) { m_LookingForGroup.comment = _comment; } uint8 GetLfgRoles() { return m_LookingForGroup.roles; } diff --git a/src/server/game/World/World.cpp b/src/server/game/World/World.cpp index 65a631c71e3..9a12e2be60b 100644 --- a/src/server/game/World/World.cpp +++ b/src/server/game/World/World.cpp @@ -1431,6 +1431,12 @@ void World::SetInitialWorldSettings() sLog.outString("Loading Quests Relations..."); sObjectMgr.LoadQuestRelations(); // must be after quest load + sLog.outString("Loading Dungeon boss data..."); + sLFGMgr.LoadDungeonEncounters(); + + sLog.outString("Loading LFG rewards..."); + sLFGMgr.LoadRewards(); + sLog.outString("Loading UNIT_NPC_FLAG_SPELLCLICK Data..."); sObjectMgr.LoadNPCSpellClickSpells(); |
