diff options
-rw-r--r-- | sql/base/auth_database.sql | 7 | ||||
-rw-r--r-- | sql/updates/auth/master/2017_12_31_00_auth.sql | 7 | ||||
-rw-r--r-- | sql/updates/auth/master/9999_99_99_99_auth.sql | 5 | ||||
-rw-r--r-- | sql/updates/world/master/2017_12_31_00_world.sql | 121 | ||||
-rw-r--r-- | sql/updates/world/master/9999_99_99_99_playerchoice.sql | 83 | ||||
-rw-r--r-- | src/server/game/Entities/Creature/GossipDef.h | 2 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.cpp | 176 | ||||
-rw-r--r-- | src/server/game/Entities/Player/Player.h | 3 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.cpp | 341 | ||||
-rw-r--r-- | src/server/game/Globals/ObjectMgr.h | 99 | ||||
-rw-r--r-- | src/server/game/Handlers/QuestHandler.cpp | 61 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.cpp | 4 | ||||
-rw-r--r-- | src/server/game/Scripting/ScriptMgr.h | 4 | ||||
-rw-r--r-- | src/server/game/Server/Packets/QuestPackets.cpp | 97 | ||||
-rw-r--r-- | src/server/game/Server/Packets/QuestPackets.h | 54 | ||||
-rw-r--r-- | src/server/game/Server/WorldSession.h | 4 | ||||
-rw-r--r-- | src/server/game/Spells/SpellEffects.cpp | 4 |
17 files changed, 715 insertions, 357 deletions
diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 1fd7696bdc7..a5916565ddb 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -1105,6 +1105,7 @@ INSERT INTO `rbac_linked_permissions` VALUES (196,840), (196,842), (196,843), +(196,869), (197,232), (197,236), (197,237), @@ -2024,7 +2025,8 @@ INSERT INTO `rbac_permissions` VALUES (852,'Command: go offset'), (853,'Command: .reload conversation_template'), (854,'Command: .debug conversation'), -(868,'Command: modify power'); +(868,'Command: modify power'), +(869,'Command: debug send playerchoice'); /*!40000 ALTER TABLE `rbac_permissions` ENABLE KEYS */; UNLOCK TABLES; @@ -2225,7 +2227,8 @@ INSERT INTO `updates` VALUES ('2017_09_22_00_auth.sql','9313CCE80A18212E6F0C78D83316DE8582AE8084','RELEASED','2017-09-22 18:05:17',0), ('2017_11_11_01_auth.sql','0D6EDB6B2FC8B9FBDF11ECD79B4B8E943328B6A9','RELEASED','2017-11-11 18:49:45',0), ('2017_12_30_00_auth.sql','F360E9555AC68E28834E3FF807E4E37A090EF363','RELEASED','2017-12-30 00:23:32',0), -('2017_12_30_01_auth.sql','1E11C78BA6D1D8E8CED7423DF92D1D197D6061EE','RELEASED','2017-12-30 23:00:00',0); +('2017_12_30_01_auth.sql','1E11C78BA6D1D8E8CED7423DF92D1D197D6061EE','RELEASED','2017-12-30 23:00:00',0), +('2017_12_31_00_auth.sql','1721ACBD35EB95FAE33B9E95F8C4E4B1FB70A5E4','RELEASED','2017-12-31 20:15:23',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/master/2017_12_31_00_auth.sql b/sql/updates/auth/master/2017_12_31_00_auth.sql new file mode 100644 index 00000000000..7348c426b5f --- /dev/null +++ b/sql/updates/auth/master/2017_12_31_00_auth.sql @@ -0,0 +1,7 @@ +DELETE FROM `rbac_permissions` WHERE `id`=869; +INSERT INTO `rbac_permissions` (`id`,`name`) VALUES +(869,'Command: debug send playerchoice'); + +DELETE FROM `rbac_linked_permissions` WHERE `linkedId`=869; +INSERT INTO `rbac_linked_permissions` (`id`,`linkedId`) VALUES +(196,869); diff --git a/sql/updates/auth/master/9999_99_99_99_auth.sql b/sql/updates/auth/master/9999_99_99_99_auth.sql deleted file mode 100644 index f673ceae849..00000000000 --- a/sql/updates/auth/master/9999_99_99_99_auth.sql +++ /dev/null @@ -1,5 +0,0 @@ -INSERT INTO `rbac_permissions` (id, NAME) VALUES -(869, "Command: debug send playerchoice"); - -INSERT INTO `rbac_linked_permissions` (id, linkedId) VALUES -(192, 869); diff --git a/sql/updates/world/master/2017_12_31_00_world.sql b/sql/updates/world/master/2017_12_31_00_world.sql new file mode 100644 index 00000000000..7e9aab77d82 --- /dev/null +++ b/sql/updates/world/master/2017_12_31_00_world.sql @@ -0,0 +1,121 @@ +DELETE FROM `command` WHERE `name` IN ('debug send playerchoice'); +INSERT INTO `command` (`name`,`permission`,`help`) VALUES +('debug send playerchoice', 869, 'Syntax: .debug send playerchoice $choiceId\r\nSend given choice to player.'); + +-- +-- Table structure for table `playerchoice` +-- +DROP TABLE IF EXISTS `playerchoice`; +CREATE TABLE `playerchoice` ( + `ChoiceId` int(11) NOT NULL, + `Question` varchar(255), + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_locale` +-- +DROP TABLE IF EXISTS `playerchoice_locale`; +CREATE TABLE `playerchoice_locale` ( + `ChoiceId` int(11) NOT NULL, + `locale` varchar(4) NOT NULL, + `Question` varchar(255), + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response` +-- +DROP TABLE IF EXISTS `playerchoice_response`; +CREATE TABLE `playerchoice_response` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `Index` int(10) UNSIGNED NOT NULL, + `ChoiceArtFileId` int(11) NOT NULL DEFAULT '0', + `Header` varchar(511) NOT NULL, + `Answer` varchar(511) NOT NULL, + `Description` varchar(2047) NOT NULL, + `Confirmation` varchar(127) NOT NULL, + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`,`ResponseId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response_locale` +-- +DROP TABLE IF EXISTS `playerchoice_response_locale`; +CREATE TABLE `playerchoice_response_locale` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `locale` varchar(4) NOT NULL, + `Header` varchar(511) NOT NULL DEFAULT '', + `Answer` varchar(511) NOT NULL DEFAULT '', + `Description` varchar(2047) NOT NULL DEFAULT '', + `Confirmation` varchar(127) NOT NULL DEFAULT '', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceID`,`ResponseID`,`locale`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response_reward` +-- +DROP TABLE IF EXISTS `playerchoice_response_reward`; +CREATE TABLE `playerchoice_response_reward` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `TitleId` int(11) NOT NULL DEFAULT '0', + `PackageId` int(11) NOT NULL DEFAULT '0', + `SkillLineId` int(10) UNSIGNED NOT NULL DEFAULT '0', + `SkillPointCount` int(10) UNSIGNED NOT NULL DEFAULT '0', + `ArenaPointCount` int(10) UNSIGNED NOT NULL DEFAULT '0', + `HonorPointCount` int(10) UNSIGNED NOT NULL DEFAULT '0', + `Money` bigint(20) UNSIGNED NOT NULL DEFAULT '0', + `Xp` int(10) UNSIGNED NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`, `ResponseId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response_reward_currency` +-- +DROP TABLE IF EXISTS `playerchoice_response_reward_currency`; +CREATE TABLE `playerchoice_response_reward_currency` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `Index` int(10) UNSIGNED NOT NULL, + `CurrencyId` int(10) UNSIGNED NOT NULL DEFAULT '0', + `Quantity` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`, `ResponseId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response_reward_faction` +-- +DROP TABLE IF EXISTS `playerchoice_response_reward_faction`; +CREATE TABLE `playerchoice_response_reward_faction` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `Index` int(10) UNSIGNED NOT NULL, + `FactionId` int(10) UNSIGNED NOT NULL DEFAULT '0', + `Quantity` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`, `ResponseId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- +-- Table structure for table `playerchoice_response_reward_item` +-- +DROP TABLE IF EXISTS `playerchoice_response_reward_item`; +CREATE TABLE `playerchoice_response_reward_item` ( + `ChoiceId` int(11) NOT NULL, + `ResponseId` int(11) NOT NULL, + `Index` int(10) UNSIGNED NOT NULL, + `ItemId` int(10) UNSIGNED NOT NULL DEFAULT '0', + `BonusListIDs` text, + `Quantity` int(11) NOT NULL DEFAULT '0', + `VerifiedBuild` smallint(6) NOT NULL DEFAULT '0', + PRIMARY KEY (`ChoiceId`, `ResponseId`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; diff --git a/sql/updates/world/master/9999_99_99_99_playerchoice.sql b/sql/updates/world/master/9999_99_99_99_playerchoice.sql deleted file mode 100644 index 4e4611428db..00000000000 --- a/sql/updates/world/master/9999_99_99_99_playerchoice.sql +++ /dev/null @@ -1,83 +0,0 @@ -DELETE FROM `command` WHERE `name` IN ('debug send playerchoice'); -INSERT INTO `command` (`name`, `permission`, `help`) VALUES -('debug send playerchoice', 869, 'Syntax: .debug send playerchoice $choiceId\r\nSend given choice to player.'); - -DROP TABLE IF EXISTS `playerchoice`; -CREATE TABLE `playerchoice` ( - `ChoiceID` INT (10) NOT NULL, - `Question` VARCHAR (255), - PRIMARY KEY (`ChoiceID`) -); - -INSERT INTO playerchoice VALUES (231, "TODO"); - -DROP TABLE IF EXISTS `playerchoice_locale`; -CREATE TABLE `playerchoice_locale` ( - `ChoiceID` INT (10) NOT NULL, - `locale` VARCHAR (4) NOT NULL, - `Question` VARCHAR (255), - PRIMARY KEY (`ChoiceID`, `locale`) -); - -INSERT INTO playerchoice_locale VALUES (231, "frFR", "Quelle spécialisation de chasseur de démons voulez-vous apprendre ?"); - -DROP TABLE IF EXISTS `playerchoice_response`; -CREATE TABLE `playerchoice_response` ( - `ChoiceID` INT (10) NOT NULL, - `ResponseID` INT (10) NOT NULL, - `ChoiceArtFileID` INT (10), - `Header` TEXT, - `Answer` TEXT, - `Description` TEXT, - `Confirmation` TEXT, - PRIMARY KEY (`ChoiceID`, `ResponseID`) -); - -INSERT INTO playerchoice_response VALUES -(231, 478, 1274664, "TODO", "TODO", "TODO", ""), -(231, 479, 1274665, "TODO", "TODO", "TODO", ""); - -DROP TABLE IF EXISTS `playerchoice_response_locale`; -CREATE TABLE `playerchoice_response_locale` ( - `ChoiceID` INT (10) NOT NULL, - `ResponseID` INT (10) NOT NULL, - `locale` VARCHAR (4) NOT NULL, - `Header` TEXT, - `Answer` TEXT, - `Description` TEXT, - `Confirmation` TEXT, - PRIMARY KEY (`ChoiceID`, `ResponseID`, `locale`) -); - -INSERT INTO playerchoice_response_locale VALUES -(231, 478, "frFR", "Dévastation", "Dévastation", "Conserver votre spécialisation : Dévastation. - -Les chasseurs de démons Dévastation peuvent utiliser Métamorphose pour se transformer en démons ailés. Ils se concentrent sur les dégâts en mêlée. - -Choisir Dévastation confère |cFFFF0000|Hspell:162264|h[Métamorphose]|h|r et |cFFFF0000|Hspell:185164|h[Maîtrise : Présence démoniaque]|h|r.", ""), -(231, 479, "frFR", "Vengeance", "Vengeance", "Changer de spécialisation : Vengeance. - -Les chasseurs de démons Vengeance peuvent utiliser Métamorphose pour se transformer en démons couverts de pointes. Ils se concentrent sur le rôle de tank. - -Choisir Vengeance confère |cFFFF0000|Hspell:187827|h[Métamorphose]|h|r et |cFFFF0000|Hspell:203747|h[Maîtrise : Gangresang]|h|r. - -Votre technique |cFFFF0000|Hspell:193921|h[Rayon accablant]|h|r est remplacée par |cFFFF0000|Hspell:203720|h[Pointes démoniaques]|h|r.", ""); - -DROP TABLE IF EXISTS `playerchoice_response_reward`; -CREATE TABLE `playerchoice_response_reward` ( - `ChoiceID` INT (10) NOT NULL, - `ResponseID` INT (10) NOT NULL, - `TitleID` INT (10), - `PackageID` INT (10), - `SkillLineID` INT (10) UNSIGNED, - `SkillPointCount` INT (10) UNSIGNED, - `ArenaPointCount` INT (10) UNSIGNED, - `HonorPointCount` INT (10) UNSIGNED, - `Money` BIGINT (20) UNSIGNED, - `Xp` INT (10) UNSIGNED, - PRIMARY KEY (`ChoiceID`, `ResponseID`) -); - -INSERT INTO playerchoice_response_reward VALUES -(231, 478, 0, 0, 0, 0, 0, 0, 0, 0), -(231, 479, 0, 0, 0, 0, 0, 0, 0, 0); diff --git a/src/server/game/Entities/Creature/GossipDef.h b/src/server/game/Entities/Creature/GossipDef.h index e15eb506a0a..0d8b0e81001 100644 --- a/src/server/game/Entities/Creature/GossipDef.h +++ b/src/server/game/Entities/Creature/GossipDef.h @@ -243,10 +243,12 @@ class InteractionData { SourceGuid.Clear(); TrainerId = 0; + PlayerChoiceId = 0; } ObjectGuid SourceGuid; uint32 TrainerId; + uint32 PlayerChoiceId; }; class TC_GAME_API PlayerMenu diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 1e084d87850..5c06fe68027 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -15066,6 +15066,49 @@ bool Player::CanSelectQuestPackageItem(QuestPackageItemEntry const* questPackage return false; } +void Player::RewardQuestPackage(uint32 questPackageId, uint32 onlyItemId /*= 0*/) +{ + bool hasFilteredQuestPackageReward = false; + if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(questPackageId)) + { + for (QuestPackageItemEntry const* questPackageItem : *questPackageItems) + { + if (onlyItemId && questPackageItem->ItemID != onlyItemId) + continue; + + if (CanSelectQuestPackageItem(questPackageItem)) + { + hasFilteredQuestPackageReward = true; + ItemPosCountVec dest; + if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK) + { + Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomPropertyId(questPackageItem->ItemID)); + SendNewItem(item, questPackageItem->ItemCount, true, false); + } + } + } + } + + if (!hasFilteredQuestPackageReward) + { + if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(questPackageId)) + { + for (QuestPackageItemEntry const* questPackageItem : *questPackageItems) + { + if (onlyItemId && questPackageItem->ItemID != onlyItemId) + continue; + + ItemPosCountVec dest; + if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK) + { + Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomPropertyId(questPackageItem->ItemID)); + SendNewItem(item, questPackageItem->ItemCount, true, false); + } + } + } + } +} + void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce) { //this THING should be here to protect code from quest, which cast on player far teleport as a reward @@ -15122,47 +15165,7 @@ void Player::RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, // QuestPackageItem.db2 if (rewardProto && quest->GetQuestPackageID()) - { - bool hasFilteredQuestPackageReward = false; - if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItems(quest->GetQuestPackageID())) - { - for (QuestPackageItemEntry const* questPackageItem : *questPackageItems) - { - if (questPackageItem->ItemID != reward) - continue; - - if (CanSelectQuestPackageItem(questPackageItem)) - { - hasFilteredQuestPackageReward = true; - ItemPosCountVec dest; - if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK) - { - Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomPropertyId(questPackageItem->ItemID)); - SendNewItem(item, questPackageItem->ItemCount, true, false); - } - } - } - } - - if (!hasFilteredQuestPackageReward) - { - if (std::vector<QuestPackageItemEntry const*> const* questPackageItems = sDB2Manager.GetQuestPackageItemsFallback(quest->GetQuestPackageID())) - { - for (QuestPackageItemEntry const* questPackageItem : *questPackageItems) - { - if (questPackageItem->ItemID != reward) - continue; - - ItemPosCountVec dest; - if (CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, questPackageItem->ItemID, questPackageItem->ItemCount) == EQUIP_ERR_OK) - { - Item* item = StoreNewItem(dest, questPackageItem->ItemID, true, GenerateItemRandomPropertyId(questPackageItem->ItemID)); - SendNewItem(item, questPackageItem->ItemCount, true, false); - } - } - } - } - } + RewardQuestPackage(quest->GetQuestPackageID(), reward); if (quest->GetRewItemsCount() > 0) { @@ -27121,35 +27124,90 @@ void Player::SendMovementSetCollisionHeight(float height) SendMessageToSet(updateCollisionHeight.Write(), false); } -void Player::SendPlayerChoice(ObjectGuid sender, uint32 choiceID) +void Player::SendPlayerChoice(ObjectGuid sender, int32 choiceId) { - PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(choiceID); + PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(choiceId); if (!playerChoice) return; - PlayerChoice localizedPlayerChoice = *playerChoice; - LocaleConstant locale = GetSession()->GetSessionDbLocaleIndex(); - if (locale != DEFAULT_LOCALE) - { - if (PlayerChoiceLocale const* playerChoiceLocale = sObjectMgr->GetPlayerChoiceLocale(localizedPlayerChoice.ChoiceId)) - sObjectMgr->GetLocaleString(playerChoiceLocale->Question, locale, localizedPlayerChoice.Question); + PlayerChoiceLocale const* playerChoiceLocale = locale != DEFAULT_LOCALE ? sObjectMgr->GetPlayerChoiceLocale(choiceId) : nullptr; - for (auto& playerChoiceResponse : localizedPlayerChoice.Responses) - { - if (PlayerChoiceResponseLocale const* playerChoiceResponseLocale = sObjectMgr->GetPlayerChoiceResponseLocale(localizedPlayerChoice.ChoiceId, playerChoiceResponse.second.ResponseID)) + PlayerTalkClass->GetInteractionData().Reset(); + PlayerTalkClass->GetInteractionData().SourceGuid = sender; + PlayerTalkClass->GetInteractionData().PlayerChoiceId = uint32(choiceId); + + WorldPackets::Quest::DisplayPlayerChoice displayPlayerChoice; + displayPlayerChoice.SenderGUID = sender; + displayPlayerChoice.ChoiceID = choiceId; + displayPlayerChoice.Question = playerChoice->Question; + if (playerChoiceLocale) + ObjectMgr::GetLocaleString(playerChoiceLocale->Question, locale, displayPlayerChoice.Question); + + displayPlayerChoice.Responses.resize(playerChoice->Responses.size()); + displayPlayerChoice.CloseChoiceFrame = false; + + for (std::size_t i = 0; i < playerChoice->Responses.size(); ++i) + { + PlayerChoiceResponse const& playerChoiceResponseTemplate = playerChoice->Responses[i]; + WorldPackets::Quest::PlayerChoiceResponse& playerChoiceResponse = displayPlayerChoice.Responses[i]; + playerChoiceResponse.ResponseID = playerChoiceResponseTemplate.ResponseId; + playerChoiceResponse.ChoiceArtFileID = playerChoiceResponseTemplate.ChoiceArtFileId; + playerChoiceResponse.Answer = playerChoiceResponseTemplate.Answer; + playerChoiceResponse.Header = playerChoiceResponseTemplate.Header; + playerChoiceResponse.Description = playerChoiceResponseTemplate.Description; + playerChoiceResponse.Confirmation = playerChoiceResponseTemplate.Confirmation; + if (playerChoiceLocale) + { + if (PlayerChoiceResponseLocale const* playerChoiceResponseLocale = Trinity::Containers::MapGetValuePtr(playerChoiceLocale->Responses, playerChoiceResponseTemplate.ResponseId)) + { + ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Answer, locale, playerChoiceResponse.Answer); + ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Header, locale, playerChoiceResponse.Header); + ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Description, locale, playerChoiceResponse.Description); + ObjectMgr::GetLocaleString(playerChoiceResponseLocale->Confirmation, locale, playerChoiceResponse.Confirmation); + } + } + + if (playerChoiceResponseTemplate.Reward) + { + playerChoiceResponse.Reward = boost::in_place(); + playerChoiceResponse.Reward->TitleID = playerChoiceResponseTemplate.Reward->TitleId; + playerChoiceResponse.Reward->PackageID = playerChoiceResponseTemplate.Reward->PackageId; + playerChoiceResponse.Reward->SkillLineID = playerChoiceResponseTemplate.Reward->SkillLineId; + playerChoiceResponse.Reward->SkillPointCount = playerChoiceResponseTemplate.Reward->SkillPointCount; + playerChoiceResponse.Reward->ArenaPointCount = playerChoiceResponseTemplate.Reward->ArenaPointCount; + playerChoiceResponse.Reward->HonorPointCount = playerChoiceResponseTemplate.Reward->HonorPointCount; + playerChoiceResponse.Reward->Money = playerChoiceResponseTemplate.Reward->Money; + playerChoiceResponse.Reward->Xp = playerChoiceResponseTemplate.Reward->Xp; + for (PlayerChoiceResponseRewardItem const& item : playerChoiceResponseTemplate.Reward->Items) + { + playerChoiceResponse.Reward->Items.emplace_back(); + WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back(); + rewardEntry.Item.ItemID = item.Id; + rewardEntry.Quantity = item.Quantity; + if (!item.BonusListIDs.empty()) + { + rewardEntry.Item.ItemBonus = boost::in_place(); + rewardEntry.Item.ItemBonus->BonusListIDs = item.BonusListIDs; + } + } + for (PlayerChoiceResponseRewardEntry const& currency : playerChoiceResponseTemplate.Reward->Currency) { - sObjectMgr->GetLocaleString(playerChoiceResponseLocale->Header, locale, playerChoiceResponse.second.Header); - sObjectMgr->GetLocaleString(playerChoiceResponseLocale->Answer, locale, playerChoiceResponse.second.Answer); - sObjectMgr->GetLocaleString(playerChoiceResponseLocale->Description, locale, playerChoiceResponse.second.Description); - sObjectMgr->GetLocaleString(playerChoiceResponseLocale->Confirmation, locale, playerChoiceResponse.second.Confirmation); + playerChoiceResponse.Reward->Items.emplace_back(); + WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back(); + rewardEntry.Item.ItemID = currency.Id; + rewardEntry.Quantity = currency.Quantity; + } + for (PlayerChoiceResponseRewardEntry const& faction : playerChoiceResponseTemplate.Reward->Faction) + { + playerChoiceResponse.Reward->Items.emplace_back(); + WorldPackets::Quest::PlayerChoiceResponseRewardEntry& rewardEntry = playerChoiceResponse.Reward->Items.back(); + rewardEntry.Item.ItemID = faction.Id; + rewardEntry.Quantity = faction.Quantity; } } } - WorldPackets::Quest::DisplayPlayerChoice displayPlayerChoice; - displayPlayerChoice.Choice = &localizedPlayerChoice; - displayPlayerChoice.SenderGUID = sender; SendDirectMessage(displayPlayerChoice.Write()); } diff --git a/src/server/game/Entities/Player/Player.h b/src/server/game/Entities/Player/Player.h index 1391ad7e532..5af181dd5a5 100644 --- a/src/server/game/Entities/Player/Player.h +++ b/src/server/game/Entities/Player/Player.h @@ -1358,6 +1358,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> uint32 GetQuestMoneyReward(Quest const* quest) const; uint32 GetQuestXPReward(Quest const* quest); bool CanSelectQuestPackageItem(QuestPackageItemEntry const* questPackageItem) const; + void RewardQuestPackage(uint32 questPackageId, uint32 onlyItemId = 0); void RewardQuest(Quest const* quest, uint32 reward, Object* questGiver, bool announce = true); void SetRewardedQuest(uint32 quest_id); void FailQuest(uint32 quest_id); @@ -2338,7 +2339,7 @@ class TC_GAME_API Player : public Unit, public GridObject<Player> SceneMgr& GetSceneMgr() { return m_sceneMgr; } RestMgr& GetRestMgr() const { return *_restMgr; } - void SendPlayerChoice(ObjectGuid sender, uint32 choiceID); + void SendPlayerChoice(ObjectGuid sender, int32 choiceId); protected: // Gamemaster whisper whitelist diff --git a/src/server/game/Globals/ObjectMgr.cpp b/src/server/game/Globals/ObjectMgr.cpp index cc8215b75b0..ff2b7b807b2 100644 --- a/src/server/game/Globals/ObjectMgr.cpp +++ b/src/server/game/Globals/ObjectMgr.cpp @@ -35,7 +35,6 @@ #include "LootMgr.h" #include "Mail.h" #include "MapManager.h" -#include "MiscPackets.h" #include "MotionMaster.h" #include "ObjectAccessor.h" #include "ObjectDefines.h" @@ -9789,38 +9788,9 @@ bool ObjectMgr::GetRealmName(uint32 realmId, std::string& name, std::string& nor return false; } -uint8 ObjectMgr::GetRaceExpansionRequirement(uint8 race) const -{ - auto itr = _raceExpansionRequirementStore.find(race); - if (itr != _raceExpansionRequirementStore.end()) - return itr->second; - return EXPANSION_CLASSIC; -} - -uint8 ObjectMgr::GetClassExpansionRequirement(uint8 class_) const -{ - auto itr = _classExpansionRequirementStore.find(class_); - if (itr != _classExpansionRequirementStore.end()) - return itr->second; - return EXPANSION_CLASSIC; -} - -SceneTemplate const* ObjectMgr::GetSceneTemplate(uint32 sceneId) const -{ - auto itr = _sceneTemplateStore.find(sceneId); - if (itr != _sceneTemplateStore.end()) - return &itr->second; - - return nullptr; -} - PlayerChoice const* ObjectMgr::GetPlayerChoice(int32 choiceId) const { - auto itr = _playerChoiceContainer.find(choiceId); - if (itr != _playerChoiceContainer.end()) - return &itr->second; - - return nullptr; + return Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); } void ObjectMgr::LoadGameObjectQuestItems() @@ -9947,9 +9917,9 @@ void ObjectMgr::LoadSceneTemplates() void ObjectMgr::LoadPlayerChoices() { uint32 oldMSTime = getMSTime(); - _playerChoiceContainer.clear(); + _playerChoices.clear(); - QueryResult choices = WorldDatabase.Query("SELECT ChoiceID, Question FROM playerchoice"); + QueryResult choices = WorldDatabase.Query("SELECT ChoiceId, Question FROM playerchoice"); if (!choices) { @@ -9959,6 +9929,9 @@ void ObjectMgr::LoadPlayerChoices() uint32 responseCount = 0; uint32 rewardCount = 0; + uint32 itemRewardCount = 0; + uint32 currencyRewardCount = 0; + uint32 factionRewardCount = 0; do { @@ -9966,97 +9939,245 @@ void ObjectMgr::LoadPlayerChoices() int32 choiceId = fields[0].GetInt32(); - PlayerChoice& choice = _playerChoiceContainer[choiceId]; + PlayerChoice& choice = _playerChoices[choiceId]; choice.ChoiceId = choiceId; choice.Question = fields[1].GetString(); - } while (choices->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " player choices in %u ms.", _playerChoiceContainer.size(), GetMSTimeDiffToNow(oldMSTime)); + } while (choices->NextRow()); - QueryResult responses = WorldDatabase.Query("SELECT ChoiceID, ResponseID, ChoiceArtFileID, Header, Answer, Description, Confirmation FROM playerchoice_response"); - if (responses) + if (QueryResult responses = WorldDatabase.Query("SELECT ChoiceId, ResponseId, ChoiceArtFileId, Header, Answer, Description, Confirmation FROM playerchoice_response ORDER BY `Index` ASC")) { do { - ++responseCount; Field* fields = responses->Fetch(); int32 choiceId = fields[0].GetInt32(); - int32 ResponseID = fields[1].GetInt32(); + int32 responseId = fields[1].GetInt32(); - if (_playerChoiceContainer.find(choiceId) == _playerChoiceContainer.end()) + PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); + if (!choice) { - TC_LOG_ERROR("sql.sql", "Table `playerchoice_response` has nonexistent choiceId: %u (ResponseID : %u), skipped", choiceId, ResponseID); + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response` references non-existing ChoiceId: %d (ResponseId: %d), skipped", choiceId, responseId); continue; } - PlayerChoice& choice = _playerChoiceContainer[choiceId]; - PlayerChoiceResponse& response = choice.Responses[ResponseID]; + choice->Responses.emplace_back(); - response.ResponseID = ResponseID; - response.ChoiceArtFileID = fields[2].GetInt32(); + PlayerChoiceResponse& response = choice->Responses.back(); + response.ResponseId = responseId; + response.ChoiceArtFileId = fields[2].GetInt32(); response.Header = fields[3].GetString(); response.Answer = fields[4].GetString(); response.Description = fields[5].GetString(); response.Confirmation = fields[6].GetString(); - } while (responses->NextRow()); + ++responseCount; - TC_LOG_INFO("server.loading", ">> Loaded %u player choices response in %u ms.", responseCount, GetMSTimeDiffToNow(oldMSTime)); - } - else - { - TC_LOG_INFO("server.loading", ">> Loaded 0 player choices responses. DB table `playerchoice_response` is empty."); + } while (responses->NextRow()); } - QueryResult rewards = WorldDatabase.Query("SELECT ChoiceID, ResponseID, TitleID, PackageID, SkillLineID, SkillPointCount, ArenaPointCount, HonorPointCount, Money, Xp FROM playerchoice_response_reward"); - - if (rewards) + if (QueryResult rewards = WorldDatabase.Query("SELECT ChoiceId, ResponseId, TitleId, PackageId, SkillLineId, SkillPointCount, ArenaPointCount, HonorPointCount, Money, Xp FROM playerchoice_response_reward")) { do { - ++rewardCount; Field* fields = rewards->Fetch(); int32 choiceId = fields[0].GetInt32(); - int32 ResponseID = fields[1].GetInt32(); + int32 responseId = fields[1].GetInt32(); + + PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); + if (!choice) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` references non-existing ChoiceId: %d (ResponseId: %d), skipped", choiceId, responseId); + continue; + } - if (_playerChoiceContainer.find(choiceId) == _playerChoiceContainer.end()) + auto responseItr = std::find_if(choice->Responses.begin(), choice->Responses.end(), + [responseId](PlayerChoiceResponse const& playerChoiceResponse) { return playerChoiceResponse.ResponseId == responseId; }); + if (responseItr == choice->Responses.end()) { - TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` has nonexistent choiceId: %u (ResponseID : %u), skipped", choiceId, ResponseID); + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` references non-existing ResponseId: %d for ChoiceId %d, skipped", responseId, choiceId); continue; } - PlayerChoice& choice = _playerChoiceContainer[choiceId]; + responseItr->Reward = boost::in_place(); - if (choice.Responses.find(ResponseID) == choice.Responses.end()) + PlayerChoiceResponseReward* reward = responseItr->Reward.get_ptr(); + reward->TitleId = fields[2].GetInt32(); + reward->PackageId = fields[3].GetInt32(); + reward->SkillLineId = fields[4].GetInt32(); + reward->SkillPointCount = fields[5].GetUInt32(); + reward->ArenaPointCount = fields[6].GetUInt32(); + reward->HonorPointCount = fields[7].GetUInt32(); + reward->Money = fields[8].GetUInt64(); + reward->Xp = fields[9].GetUInt32(); + ++rewardCount; + + if (reward->TitleId && !sCharTitlesStore.LookupEntry(reward->TitleId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` references non-existing Title %d for ChoiceId %d, ResponseId: %d, set to 0", + reward->TitleId, choiceId, responseId); + reward->TitleId = 0; + } + + if (reward->PackageId && !sDB2Manager.GetQuestPackageItems(reward->PackageId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` references non-existing QuestPackage %d for ChoiceId %d, ResponseId: %d, set to 0", + reward->TitleId, choiceId, responseId); + reward->PackageId = 0; + } + + if (reward->SkillLineId && !sSkillLineStore.LookupEntry(reward->SkillLineId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` references non-existing SkillLine %d for ChoiceId %d, ResponseId: %d, set to 0", + reward->TitleId, choiceId, responseId); + reward->SkillLineId = 0; + reward->SkillPointCount = 0; + } + + } while (rewards->NextRow()); + } + + if (QueryResult rewards = WorldDatabase.Query("SELECT ChoiceId, ResponseId, ItemId, BonusListIDs, Quantity FROM playerchoice_response_reward_item ORDER BY `Index` ASC")) + { + do + { + Field* fields = rewards->Fetch(); + + int32 choiceId = fields[0].GetInt32(); + int32 responseId = fields[1].GetInt32(); + uint32 itemId = fields[2].GetUInt32(); + Tokenizer bonusListIDsTok(fields[3].GetString(), ' '); + std::vector<int32> bonusListIds; + for (char const* token : bonusListIDsTok) + bonusListIds.push_back(int32(atol(token))); + int32 quantity = fields[4].GetInt32(); + + PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); + if (!choice) { - TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` has nonexistent ResponseID: %u for choiceId %u, skipped", ResponseID, choiceId); + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_item` references non-existing ChoiceId: %d (ResponseId: %d), skipped", choiceId, responseId); continue; } - PlayerChoiceResponse& response = choice.Responses[ResponseID]; + auto responseItr = std::find_if(choice->Responses.begin(), choice->Responses.end(), + [responseId](PlayerChoiceResponse const& playerChoiceResponse) { return playerChoiceResponse.ResponseId == responseId; }); + if (responseItr == choice->Responses.end()) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_item` references non-existing ResponseId: %d for ChoiceId %d, skipped", responseId, choiceId); + continue; + } - PlayerChoiceResponseReward reward; + if (!responseItr->Reward) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_item` references non-existing player choice reward for ChoiceId %d, ResponseId: %d, skipped", + choiceId, responseId); + continue; + } - reward.TitleID = fields[2].GetInt32(); - reward.PackageID = fields[3].GetInt32(); - reward.SkillLineID = fields[4].GetUInt32(); - reward.SkillPointCount = fields[5].GetUInt32(); - reward.ArenaPointCount = fields[6].GetUInt32(); - reward.HonorPointCount = fields[7].GetUInt32(); - reward.Money = fields[8].GetUInt64(); - reward.Xp = fields[9].GetUInt32(); + if (!GetItemTemplate(itemId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_item` references non-existing item %u for ChoiceId %d, ResponseId: %d, skipped", + itemId, choiceId, responseId); + continue; + } - response.Reward = reward; + responseItr->Reward->Items.emplace_back(itemId, std::move(bonusListIds), quantity); } while (rewards->NextRow()); + } - TC_LOG_INFO("server.loading", ">> Loaded %u player choices reward in %u ms.", rewardCount, GetMSTimeDiffToNow(oldMSTime)); + if (QueryResult rewards = WorldDatabase.Query("SELECT ChoiceId, ResponseId, CurrencyId, Quantity FROM playerchoice_response_reward_currency ORDER BY `Index` ASC")) + { + do + { + Field* fields = rewards->Fetch(); + + int32 choiceId = fields[0].GetInt32(); + int32 responseId = fields[1].GetInt32(); + uint32 currencyId = fields[2].GetUInt32(); + int32 quantity = fields[3].GetInt32(); + + PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); + if (!choice) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_currency` references non-existing ChoiceId: %d (ResponseId: %d), skipped", choiceId, responseId); + continue; + } + + auto responseItr = std::find_if(choice->Responses.begin(), choice->Responses.end(), + [responseId](PlayerChoiceResponse const& playerChoiceResponse) { return playerChoiceResponse.ResponseId == responseId; }); + if (responseItr == choice->Responses.end()) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_currency` references non-existing ResponseId: %d for ChoiceId %d, skipped", responseId, choiceId); + continue; + } + + if (!responseItr->Reward) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_currency` references non-existing player choice reward for ChoiceId %d, ResponseId: %d, skipped", + choiceId, responseId); + continue; + } + + if (!sCurrencyTypesStore.LookupEntry(currencyId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_currency` references non-existing currency %u for ChoiceId %d, ResponseId: %d, skipped", + currencyId, choiceId, responseId); + continue; + } + + responseItr->Reward->Currency.emplace_back(currencyId, quantity); + + } while (rewards->NextRow()); } - else + + if (QueryResult rewards = WorldDatabase.Query("SELECT ChoiceId, ResponseId, FactionId, Quantity FROM playerchoice_response_reward_faction ORDER BY `Index` ASC")) { - TC_LOG_INFO("server.loading", ">> Loaded 0 player choices responses reward. DB table `playerchoice_response_reward` is empty."); + do + { + Field* fields = rewards->Fetch(); + + int32 choiceId = fields[0].GetInt32(); + int32 responseId = fields[1].GetInt32(); + uint32 factionId = fields[2].GetUInt32(); + int32 quantity = fields[3].GetInt32(); + + PlayerChoice* choice = Trinity::Containers::MapGetValuePtr(_playerChoices, choiceId); + if (!choice) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_faction` references non-existing ChoiceId: %d (ResponseId: %d), skipped", choiceId, responseId); + continue; + } + + auto responseItr = std::find_if(choice->Responses.begin(), choice->Responses.end(), + [responseId](PlayerChoiceResponse const& playerChoiceResponse) { return playerChoiceResponse.ResponseId == responseId; }); + if (responseItr == choice->Responses.end()) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_faction` references non-existing ResponseId: %d for ChoiceId %d, skipped", responseId, choiceId); + continue; + } + + if (!responseItr->Reward) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_faction` references non-existing player choice reward for ChoiceId %d, ResponseId: %d, skipped", + choiceId, responseId); + continue; + } + + if (!sFactionStore.LookupEntry(factionId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward_faction` references non-existing faction %u for ChoiceId %d, ResponseId: %d, skipped", + factionId, choiceId, responseId); + continue; + } + + responseItr->Reward->Faction.emplace_back(factionId, quantity); + + } while (rewards->NextRow()); } + + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " player choices, %u responses, %u rewards, %u item rewards, %u currency rewards and %u faction rewards in %u ms.", + _playerChoices.size(), responseCount, rewardCount, itemRewardCount, currencyRewardCount, factionRewardCount, GetMSTimeDiffToNow(oldMSTime)); } void ObjectMgr::LoadPlayerChoicesLocale() @@ -10064,63 +10185,77 @@ void ObjectMgr::LoadPlayerChoicesLocale() uint32 oldMSTime = getMSTime(); // need for reload case - _playerChoiceLocaleContainer.clear(); - _playerChoiceResponseLocaleContainer.clear(); + _playerChoiceLocales.clear(); - // 0 1 2 - QueryResult result = WorldDatabase.Query("SELECT ChoiceID, locale, Question FROM playerchoice_locale"); - if (result) + // 0 1 2 + if (QueryResult result = WorldDatabase.Query("SELECT ChoiceId, locale, Question FROM playerchoice_locale")) { do { Field* fields = result->Fetch(); - uint32 ChoiceID = fields[0].GetUInt32(); + uint32 choiceId = fields[0].GetUInt32(); std::string localeName = fields[1].GetString(); - std::string question = fields[2].GetString(); - PlayerChoiceLocale& data = _playerChoiceLocaleContainer[ChoiceID]; + if (!GetPlayerChoice(choiceId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_locale` references non-existing ChoiceId: %d for locale %s, skipped", choiceId, localeName.c_str()); + continue; + } + LocaleConstant locale = GetLocaleByName(localeName); if (locale == LOCALE_enUS) continue; - AddLocaleString(question, locale, data.Question); + PlayerChoiceLocale& data = _playerChoiceLocales[choiceId]; + AddLocaleString(fields[2].GetString(), locale, data.Question); } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice locale strings in %u ms", _playerChoiceLocaleContainer.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice locale strings in %u ms", _playerChoiceLocales.size(), GetMSTimeDiffToNow(oldMSTime)); } oldMSTime = getMSTime(); - // 0 1 2 3 4 5 6 - result = WorldDatabase.Query("SELECT ChoiceID, ResponseID, locale, Header, Answer, Description, Confirmation FROM playerchoice_response_locale"); - if (result) + // 0 1 2 3 4 5 6 + if (QueryResult result = WorldDatabase.Query("SELECT ChoiceID, ResponseID, locale, Header, Answer, Description, Confirmation FROM playerchoice_response_locale")) { + std::size_t count = 0; do { Field* fields = result->Fetch(); - uint32 ChoiceID = fields[0].GetUInt32(); - uint32 ResponseID = fields[1].GetUInt32(); - std::string localeName = fields[2].GetString(); - std::string Header = fields[3].GetString(); - std::string Answer = fields[4].GetString(); - std::string Description = fields[5].GetString(); - std::string Confirmation = fields[6].GetString(); + int32 choiceId = fields[0].GetInt32(); + int32 responseId = fields[1].GetInt32(); + std::string localeName = fields[2].GetString(); - std::pair<uint32, uint32> pair = std::make_pair(ChoiceID, ResponseID); + auto itr = _playerChoiceLocales.find(choiceId); + if (itr == _playerChoiceLocales.end()) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_locale` references non-existing ChoiceId: %d for ResponseId %d locale %s, skipped", + choiceId, responseId, localeName.c_str()); + continue; + } + + PlayerChoice const* playerChoice = ASSERT_NOTNULL(GetPlayerChoice(choiceId)); + if (!playerChoice->GetResponse(responseId)) + { + TC_LOG_ERROR("sql.sql", "Table `playerchoice_locale` references non-existing ResponseId: %d for ChoiceId %d locale %s, skipped", + responseId, choiceId, localeName.c_str()); + continue; + } - PlayerChoiceResponseLocale& data = _playerChoiceResponseLocaleContainer[pair]; LocaleConstant locale = GetLocaleByName(localeName); if (locale == LOCALE_enUS) continue; - AddLocaleString(Header, locale, data.Header); - AddLocaleString(Answer, locale, data.Answer); - AddLocaleString(Description, locale, data.Description); - AddLocaleString(Confirmation, locale, data.Confirmation); + PlayerChoiceResponseLocale& data = itr->second.Responses[responseId]; + AddLocaleString(fields[3].GetString(), locale, data.Header); + AddLocaleString(fields[4].GetString(), locale, data.Answer); + AddLocaleString(fields[5].GetString(), locale, data.Description); + AddLocaleString(fields[6].GetString(), locale, data.Confirmation); + ++count; } while (result->NextRow()); - TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice Response locale strings in %u ms", _playerChoiceResponseLocaleContainer.size(), GetMSTimeDiffToNow(oldMSTime)); + TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice Response locale strings in %u ms", count, GetMSTimeDiffToNow(oldMSTime)); } } diff --git a/src/server/game/Globals/ObjectMgr.h b/src/server/game/Globals/ObjectMgr.h index 043575b492c..4b7faf21b2d 100644 --- a/src/server/game/Globals/ObjectMgr.h +++ b/src/server/game/Globals/ObjectMgr.h @@ -518,8 +518,8 @@ typedef std::unordered_map<uint32, PointOfInterestLocale> PointOfInterestLocaleC struct PlayerChoiceResponseLocale { - std::vector<std::string> Header; std::vector<std::string> Answer; + std::vector<std::string> Header; std::vector<std::string> Description; std::vector<std::string> Confirmation; }; @@ -527,11 +527,9 @@ struct PlayerChoiceResponseLocale struct PlayerChoiceLocale { std::vector<std::string> Question; + std::unordered_map<int32 /*ResponseId*/, PlayerChoiceResponseLocale> Responses; }; -typedef std::unordered_map<uint32, PlayerChoiceLocale> PlayerChoiceLocaleContainer; -typedef std::unordered_map<std::pair<uint32, uint32>, PlayerChoiceResponseLocale> PlayerChoiceResponseLocaleContainer; - typedef std::unordered_map<uint32, TrinityString> TrinityStringContainer; typedef std::multimap<uint32, uint32> QuestRelations; // unit/go -> quest @@ -768,33 +766,48 @@ struct SceneTemplate typedef std::unordered_map<uint32, SceneTemplate> SceneTemplateContainer; +struct PlayerChoiceResponseRewardItem +{ + PlayerChoiceResponseRewardItem() : Id(0), Quantity(0) { } + PlayerChoiceResponseRewardItem(uint32 id, std::vector<int32> bonusListIDs, int32 quantity) : Id(id), BonusListIDs(std::move(bonusListIDs)), Quantity(quantity) { } + + uint32 Id; + std::vector<int32> BonusListIDs; + int32 Quantity; +}; + +struct PlayerChoiceResponseRewardEntry +{ + PlayerChoiceResponseRewardEntry() : Id(0), Quantity(0) { } + PlayerChoiceResponseRewardEntry(uint32 id, int32 quantity) : Id(id), Quantity(quantity) { } + + uint32 Id; + int32 Quantity; +}; + struct PlayerChoiceResponseReward { - int32 TitleID; - int32 PackageID; - int32 SkillLineID; + int32 TitleId; + int32 PackageId; + int32 SkillLineId; uint32 SkillPointCount; uint32 ArenaPointCount; uint32 HonorPointCount; uint64 Money; uint32 Xp; - - //std::vector<Item> Items; - //std::vector<Currency> Currency; - //std::vector<Faction> Faction; - //std::vector<ItemChoice> ItemChoice; + std::vector<PlayerChoiceResponseRewardItem> Items; + std::vector<PlayerChoiceResponseRewardEntry> Currency; + std::vector<PlayerChoiceResponseRewardEntry> Faction; }; struct PlayerChoiceResponse { - int32 ResponseID; - int32 ChoiceArtFileID; - + int32 ResponseId; + int32 ChoiceArtFileId; std::string Header; std::string Answer; std::string Description; std::string Confirmation; - Optional<PlayerChoiceResponseReward> Reward; }; @@ -802,10 +815,15 @@ struct PlayerChoice { int32 ChoiceId; std::string Question; - std::unordered_map<int32 /*ResponseID*/, PlayerChoiceResponse> Responses; -}; + std::vector<PlayerChoiceResponse> Responses; -typedef std::unordered_map<int32 /*choiceId*/, PlayerChoice> PlayerChoiceContainer; + PlayerChoiceResponse const* GetResponse(int32 responseId) const + { + auto itr = std::find_if(Responses.begin(), Responses.end(), + [responseId](PlayerChoiceResponse const& playerChoiceResponse) { return playerChoiceResponse.ResponseId == responseId; }); + return itr != Responses.end() ? &(*itr) : nullptr; + } +}; enum SkillRangeType { @@ -1384,19 +1402,12 @@ class TC_GAME_API ObjectMgr if (itr == _pointOfInterestLocaleStore.end()) return nullptr; return &itr->second; } - PlayerChoiceLocale const* GetPlayerChoiceLocale(uint32 ChoiceID) const - { - PlayerChoiceLocaleContainer::const_iterator itr = _playerChoiceLocaleContainer.find(ChoiceID); - if (itr == _playerChoiceLocaleContainer.end()) return nullptr; - return &itr->second; - } - PlayerChoiceResponseLocale const* GetPlayerChoiceResponseLocale(uint32 ChoiceID, uint32 ResponseID) const + PlayerChoiceLocale const* GetPlayerChoiceLocale(int32 ChoiceID) const { - PlayerChoiceResponseLocaleContainer::const_iterator itr = _playerChoiceResponseLocaleContainer.find(std::make_pair(ChoiceID, ResponseID)); - if (itr == _playerChoiceResponseLocaleContainer.end()) return nullptr; + auto itr = _playerChoiceLocales.find(ChoiceID); + if (itr == _playerChoiceLocales.end()) return nullptr; return &itr->second; } - GameObjectData const* GetGOData(ObjectGuid::LowType guid) const { GameObjectDataContainer::const_iterator itr = _gameObjectDataStore.find(guid); @@ -1558,12 +1569,31 @@ class TC_GAME_API ObjectMgr bool GetRealmName(uint32 realmId, std::string& name, std::string& normalizedName) const; std::unordered_map<uint8, uint8> const& GetRaceExpansionRequirements() const { return _raceExpansionRequirementStore; } - uint8 GetRaceExpansionRequirement(uint8 race) const; + uint8 GetRaceExpansionRequirement(uint8 race) const + { + auto itr = _raceExpansionRequirementStore.find(race); + if (itr != _raceExpansionRequirementStore.end()) + return itr->second; + return EXPANSION_CLASSIC; + } std::unordered_map<uint8, uint8> const& GetClassExpansionRequirements() const { return _classExpansionRequirementStore; } - uint8 GetClassExpansionRequirement(uint8 class_) const; + uint8 GetClassExpansionRequirement(uint8 class_) const + { + auto itr = _classExpansionRequirementStore.find(class_); + if (itr != _classExpansionRequirementStore.end()) + return itr->second; + return EXPANSION_CLASSIC; + } + + SceneTemplate const* GetSceneTemplate(uint32 sceneId) const + { + auto itr = _sceneTemplateStore.find(sceneId); + if (itr != _sceneTemplateStore.end()) + return &itr->second; - SceneTemplate const* GetSceneTemplate(uint32 sceneId) const; + return nullptr; + } PlayerChoice const* GetPlayerChoice(int32 choiceId) const; @@ -1700,7 +1730,7 @@ class TC_GAME_API ObjectMgr GameObjectTemplateAddonContainer _gameObjectTemplateAddonStore; /// Stores temp summon data grouped by summoner's entry, summoner's type and group id TempSummonDataContainer _tempSummonDataStore; - PlayerChoiceContainer _playerChoiceContainer; + std::unordered_map<int32 /*choiceId*/, PlayerChoice> _playerChoices; ItemTemplateContainer _itemTemplateStore; QuestTemplateLocaleContainer _questTemplateLocaleStore; @@ -1711,8 +1741,7 @@ class TC_GAME_API ObjectMgr GossipMenuItemsLocaleContainer _gossipMenuItemsLocaleStore; PointOfInterestLocaleContainer _pointOfInterestLocaleStore; - PlayerChoiceLocaleContainer _playerChoiceLocaleContainer; - PlayerChoiceResponseLocaleContainer _playerChoiceResponseLocaleContainer; + std::unordered_map<int32, PlayerChoiceLocale> _playerChoiceLocales; TrinityStringContainer _trinityStringStore; diff --git a/src/server/game/Handlers/QuestHandler.cpp b/src/server/game/Handlers/QuestHandler.cpp index 68a71e5dd5e..4cd997c0a99 100644 --- a/src/server/game/Handlers/QuestHandler.cpp +++ b/src/server/game/Handlers/QuestHandler.cpp @@ -32,6 +32,7 @@ #include "Player.h" #include "QuestDef.h" #include "QuestPackets.h" +#include "ReputationMgr.h" #include "ScriptMgr.h" #include "UnitAI.h" #include "World.h" @@ -674,7 +675,63 @@ void WorldSession::HandleRequestWorldQuestUpdate(WorldPackets::Quest::RequestWor SendPacket(response.Write()); } -void WorldSession::HandlePlayerChoiceResponse(WorldPackets::Quest::PlayerChoiceResponse& packet) +void WorldSession::HandlePlayerChoiceResponse(WorldPackets::Quest::ChoiceResponse& choiceResponse) { - sScriptMgr->OnPlayerChoiceResponse(GetPlayer(), packet.ChoiceID, packet.ResponseID); + if (_player->PlayerTalkClass->GetInteractionData().PlayerChoiceId != uint32(choiceResponse.ChoiceID)) + { + TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_CHOICE_RESPONSE: %s tried to respond to invalid player choice %d (allowed %u) (possible packet-hacking detected)", + GetPlayerInfo().c_str(), choiceResponse.ChoiceID, _player->PlayerTalkClass->GetInteractionData().PlayerChoiceId); + return; + } + + PlayerChoice const* playerChoice = sObjectMgr->GetPlayerChoice(choiceResponse.ChoiceID); + if (!playerChoice) + return; + + PlayerChoiceResponse const* playerChoiceResponse = playerChoice->GetResponse(choiceResponse.ResponseID); + if (!playerChoiceResponse) + { + TC_LOG_ERROR("entities.player.cheat", "Error in CMSG_CHOICE_RESPONSE: %s tried to select invalid player choice response %d (possible packet-hacking detected)", + GetPlayerInfo().c_str(), choiceResponse.ResponseID); + return; + } + + sScriptMgr->OnPlayerChoiceResponse(GetPlayer(), choiceResponse.ChoiceID, choiceResponse.ResponseID); + + if (playerChoiceResponse->Reward) + { + if (playerChoiceResponse->Reward->TitleId) + _player->SetTitle(sCharTitlesStore.AssertEntry(playerChoiceResponse->Reward->TitleId), false); + + if (playerChoiceResponse->Reward->PackageId) + _player->RewardQuestPackage(playerChoiceResponse->Reward->PackageId); + + if (playerChoiceResponse->Reward->SkillLineId && _player->HasSkill(playerChoiceResponse->Reward->SkillLineId)) + _player->UpdateSkillPro(playerChoiceResponse->Reward->SkillLineId, 1000, playerChoiceResponse->Reward->SkillPointCount); + + if (playerChoiceResponse->Reward->HonorPointCount) + _player->AddHonorXP(playerChoiceResponse->Reward->HonorPointCount); + + if (playerChoiceResponse->Reward->Money) + _player->ModifyMoney(playerChoiceResponse->Reward->Money, false); + + if (playerChoiceResponse->Reward->Xp) + _player->GiveXP(playerChoiceResponse->Reward->Xp, nullptr, 0.0f); + + for (PlayerChoiceResponseRewardItem const& item : playerChoiceResponse->Reward->Items) + { + ItemPosCountVec dest; + if (_player->CanStoreNewItem(NULL_BAG, NULL_SLOT, dest, item.Id, item.Quantity) == EQUIP_ERR_OK) + { + Item* newItem = _player->StoreNewItem(dest, item.Id, true, GenerateItemRandomPropertyId(item.Id), {}, 0, item.BonusListIDs); + _player->SendNewItem(newItem, item.Quantity, true, false); + } + } + + for (PlayerChoiceResponseRewardEntry const& currency : playerChoiceResponse->Reward->Currency) + _player->ModifyCurrency(currency.Id, currency.Quantity); + + for (PlayerChoiceResponseRewardEntry const& faction : playerChoiceResponse->Reward->Faction) + _player->GetReputationMgr().ModifyReputation(sFactionStore.AssertEntry(faction.Id), faction.Quantity); + } } diff --git a/src/server/game/Scripting/ScriptMgr.cpp b/src/server/game/Scripting/ScriptMgr.cpp index 4b8d5545588..168ba1c4d16 100644 --- a/src/server/game/Scripting/ScriptMgr.cpp +++ b/src/server/game/Scripting/ScriptMgr.cpp @@ -2297,9 +2297,9 @@ void ScriptMgr::OnMovieComplete(Player* player, uint32 movieId) FOREACH_SCRIPT(PlayerScript)->OnMovieComplete(player, movieId); } -void ScriptMgr::OnPlayerChoiceResponse(Player* player, uint32 choiceID, uint32 responseID) +void ScriptMgr::OnPlayerChoiceResponse(Player* player, uint32 choiceId, uint32 responseId) { - FOREACH_SCRIPT(PlayerScript)->OnPlayerChoiceResponse(player, choiceID, responseID); + FOREACH_SCRIPT(PlayerScript)->OnPlayerChoiceResponse(player, choiceId, responseId); } // Account diff --git a/src/server/game/Scripting/ScriptMgr.h b/src/server/game/Scripting/ScriptMgr.h index e27a68b7508..11c69ea03e7 100644 --- a/src/server/game/Scripting/ScriptMgr.h +++ b/src/server/game/Scripting/ScriptMgr.h @@ -757,7 +757,7 @@ class TC_GAME_API PlayerScript : public UnitScript virtual void OnMovieComplete(Player* /*player*/, uint32 /*movieId*/) { } // Called when a player choose a response from a PlayerChoice - virtual void OnPlayerChoiceResponse(Player* /*player*/, uint32 /*choiceID*/, uint32 /*responseID*/) { } + virtual void OnPlayerChoiceResponse(Player* /*player*/, uint32 /*choiceId*/, uint32 /*responseId*/) { } }; class TC_GAME_API AccountScript : public ScriptObject @@ -1146,7 +1146,7 @@ class TC_GAME_API ScriptMgr void OnPlayerUpdateZone(Player* player, uint32 newZone, uint32 newArea); void OnQuestStatusChange(Player* player, uint32 questId); void OnMovieComplete(Player* player, uint32 movieId); - void OnPlayerChoiceResponse(Player* player, uint32 choiceID, uint32 responseID); + void OnPlayerChoiceResponse(Player* player, uint32 choiceId, uint32 responseId); public: /* AccountScript */ diff --git a/src/server/game/Server/Packets/QuestPackets.cpp b/src/server/game/Server/Packets/QuestPackets.cpp index d076315fde3..39981b9ba9d 100644 --- a/src/server/game/Server/Packets/QuestPackets.cpp +++ b/src/server/game/Server/Packets/QuestPackets.cpp @@ -600,77 +600,82 @@ WorldPacket const* WorldPackets::Quest::WorldQuestUpdate::Write() return &_worldPacket; } -ByteBuffer& operator<<(ByteBuffer& data, PlayerChoiceResponse const& response) +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::PlayerChoiceResponseRewardEntry const& playerChoiceResponseRewardEntry) { - data << int32(response.ResponseID); - data << int32(response.ChoiceArtFileID); + data << playerChoiceResponseRewardEntry.Item; + data << int32(playerChoiceResponseRewardEntry.Quantity); + return data; +} - data.WriteBits(response.Answer.length(), 9); - data.WriteBits(response.Header.length(), 9); - data.WriteBits(response.Description.length(), 11); - data.WriteBits(response.Confirmation.length(), 7); +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::PlayerChoiceResponseReward const& playerChoiceResponseReward) +{ + data << int32(playerChoiceResponseReward.TitleID); + data << int32(playerChoiceResponseReward.PackageID); + data << int32(playerChoiceResponseReward.SkillLineID); + data << uint32(playerChoiceResponseReward.SkillPointCount); + data << uint32(playerChoiceResponseReward.ArenaPointCount); + data << uint32(playerChoiceResponseReward.HonorPointCount); + data << uint64(playerChoiceResponseReward.Money); + data << uint32(playerChoiceResponseReward.Xp); + data << uint32(playerChoiceResponseReward.Items.size()); + data << uint32(playerChoiceResponseReward.Currencies.size()); + data << uint32(playerChoiceResponseReward.Factions.size()); + data << uint32(playerChoiceResponseReward.ItemChoices.size()); - data.WriteBit(response.Reward.is_initialized()); - data.FlushBits(); + for (WorldPackets::Quest::PlayerChoiceResponseRewardEntry const& item : playerChoiceResponseReward.Items) + data << item; + + for (WorldPackets::Quest::PlayerChoiceResponseRewardEntry const& currency : playerChoiceResponseReward.Currencies) + data << currency; - if (response.Reward.is_initialized()) - data << (*response.Reward); + for (WorldPackets::Quest::PlayerChoiceResponseRewardEntry const& faction : playerChoiceResponseReward.Factions) + data << faction; + + for (WorldPackets::Quest::PlayerChoiceResponseRewardEntry const& itemChoice : playerChoiceResponseReward.ItemChoices) + data << itemChoice; - data.WriteString(response.Answer); - data.WriteString(response.Header); - data.WriteString(response.Description); - data.WriteString(response.Confirmation); return data; } -ByteBuffer& operator<<(ByteBuffer& data, PlayerChoiceResponseReward const& reward) +ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::PlayerChoiceResponse const& playerChoiceResponse) { - data << int32(reward.TitleID); - data << int32(reward.PackageID); - data << int32(reward.SkillLineID); - data << uint32(reward.SkillPointCount); - data << uint32(reward.ArenaPointCount); - data << uint32(reward.HonorPointCount); - data << uint64(reward.Money); - data << uint32(reward.Xp); - - data << uint32(0); // itemCount - data << uint32(0); // currencyCount - data << uint32(0); // factionCount - data << uint32(0); // itemChoiceCount - - /*for (var i = 0u; i < itemCount; ++i) - ReadPlayerChoiceResponseRewardEntry(packet, "Item", i); + data << int32(playerChoiceResponse.ResponseID); + data << int32(playerChoiceResponse.ChoiceArtFileID); - for (var i = 0u; i < currencyCount; ++i) - ReadPlayerChoiceResponseRewardEntry(packet, "Currency", i); - - for (var i = 0u; i < factionCount; ++i) - ReadPlayerChoiceResponseRewardEntry(packet, "Faction", i); + data.WriteBits(playerChoiceResponse.Answer.length(), 9); + data.WriteBits(playerChoiceResponse.Header.length(), 9); + data.WriteBits(playerChoiceResponse.Description.length(), 11); + data.WriteBits(playerChoiceResponse.Confirmation.length(), 7); + data.WriteBit(playerChoiceResponse.Reward.is_initialized()); + data.FlushBits(); - for (var i = 0u; i < itemChoiceCount; ++i) - ReadPlayerChoiceResponseRewardEntry(packet, "ItemChoice", i);*/ + if (playerChoiceResponse.Reward) + data << *playerChoiceResponse.Reward; + data.WriteString(playerChoiceResponse.Answer); + data.WriteString(playerChoiceResponse.Header); + data.WriteString(playerChoiceResponse.Description); + data.WriteString(playerChoiceResponse.Confirmation); return data; } WorldPacket const* WorldPackets::Quest::DisplayPlayerChoice::Write() { - _worldPacket << int32(Choice->ChoiceId); - _worldPacket << uint32(Choice->Responses.size()); + _worldPacket << int32(ChoiceID); + _worldPacket << uint32(Responses.size()); _worldPacket << SenderGUID; - _worldPacket.WriteBits(Choice->Question.length(), 8); + _worldPacket.WriteBits(Question.length(), 8); _worldPacket.WriteBit(CloseChoiceFrame); _worldPacket.FlushBits(); - for (auto response : Choice->Responses) - _worldPacket << response.second; + for (PlayerChoiceResponse const& response : Responses) + _worldPacket << response; - _worldPacket.WriteString(Choice->Question); + _worldPacket.WriteString(Question); return &_worldPacket; } -void WorldPackets::Quest::PlayerChoiceResponse::Read() +void WorldPackets::Quest::ChoiceResponse::Read() { _worldPacket >> ChoiceID; _worldPacket >> ResponseID; diff --git a/src/server/game/Server/Packets/QuestPackets.h b/src/server/game/Server/Packets/QuestPackets.h index a087c5de241..7effcdfa4d5 100644 --- a/src/server/game/Server/Packets/QuestPackets.h +++ b/src/server/game/Server/Packets/QuestPackets.h @@ -20,12 +20,8 @@ #include "Packet.h" #include "ItemPacketsCommon.h" -#include "QuestDef.h" #include "ObjectGuid.h" - -struct PlayerChoice; -struct PlayerChoiceResponse; -struct PlayerChoiceResponseReward; +#include "QuestDef.h" namespace WorldPackets { @@ -638,6 +634,39 @@ namespace WorldPackets std::vector<WorldQuestUpdateInfo> WorldQuestUpdates; }; + struct PlayerChoiceResponseRewardEntry + { + WorldPackets::Item::ItemInstance Item; + int32 Quantity = 0; + }; + + struct PlayerChoiceResponseReward + { + int32 TitleID = 0; + int32 PackageID = 0; + int32 SkillLineID = 0; + uint32 SkillPointCount = 0; + uint32 ArenaPointCount = 0; + uint32 HonorPointCount = 0; + uint64 Money = 0; + uint32 Xp = 0; + std::vector<PlayerChoiceResponseRewardEntry> Items; + std::vector<PlayerChoiceResponseRewardEntry> Currencies; + std::vector<PlayerChoiceResponseRewardEntry> Factions; + std::vector<PlayerChoiceResponseRewardEntry> ItemChoices; + }; + + struct PlayerChoiceResponse + { + int32 ResponseID = 0; + int32 ChoiceArtFileID = 0; + std::string Answer; + std::string Header; + std::string Description; + std::string Confirmation; + Optional<PlayerChoiceResponseReward> Reward; + }; + class DisplayPlayerChoice final : public ServerPacket { public: @@ -646,26 +675,25 @@ namespace WorldPackets WorldPacket const* Write() override; ObjectGuid SenderGUID; - PlayerChoice const* Choice; + int32 ChoiceID = 0; + std::string Question; + std::vector<PlayerChoiceResponse> Responses; bool CloseChoiceFrame = false; }; - class PlayerChoiceResponse final : public ClientPacket + class ChoiceResponse final : public ClientPacket { public: - PlayerChoiceResponse(WorldPacket&& packet) : ClientPacket(CMSG_CHOICE_RESPONSE, std::move(packet)) { } + ChoiceResponse(WorldPacket&& packet) : ClientPacket(CMSG_CHOICE_RESPONSE, std::move(packet)) { } void Read() override; - int32 ChoiceID; - int32 ResponseID; + int32 ChoiceID = 0; + int32 ResponseID = 0; }; } } -ByteBuffer& operator<<(ByteBuffer& data, PlayerChoiceResponse const& response); -ByteBuffer& operator<<(ByteBuffer& data, PlayerChoiceResponseReward const& reward); - ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestRewards const& questRewards); ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Quest::QuestGiverOfferReward const& offer); diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 5d680a1dab1..1606d00acff 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -596,7 +596,7 @@ namespace WorldPackets class QuestPushResult; class PushQuestToParty; class RequestWorldQuestUpdate; - class PlayerChoiceResponse; + class ChoiceResponse; } namespace RaF @@ -1443,7 +1443,7 @@ class TC_GAME_API WorldSession void HandlePushQuestToParty(WorldPackets::Quest::PushQuestToParty& packet); void HandleQuestPushResult(WorldPackets::Quest::QuestPushResult& packet); void HandleRequestWorldQuestUpdate(WorldPackets::Quest::RequestWorldQuestUpdate& packet); - void HandlePlayerChoiceResponse(WorldPackets::Quest::PlayerChoiceResponse& packet); + void HandlePlayerChoiceResponse(WorldPackets::Quest::ChoiceResponse& choiceResponse); void HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& chatMessage); void HandleChatMessageWhisperOpcode(WorldPackets::Chat::ChatMessageWhisper& chatMessageWhisper); diff --git a/src/server/game/Spells/SpellEffects.cpp b/src/server/game/Spells/SpellEffects.cpp index feed2c9cbc6..8a9e761b761 100644 --- a/src/server/game/Spells/SpellEffects.cpp +++ b/src/server/game/Spells/SpellEffects.cpp @@ -5666,7 +5666,7 @@ void Spell::EffectEnableBattlePets(SpellEffIndex /*effIndex*/) plr->GetSession()->GetBattlePetMgr()->UnlockSlot(0); } -void Spell::EffectLaunchQuestChoice(SpellEffIndex effIndex) +void Spell::EffectLaunchQuestChoice(SpellEffIndex /*effIndex*/) { if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET) return; @@ -5674,7 +5674,7 @@ void Spell::EffectLaunchQuestChoice(SpellEffIndex effIndex) if (!unitTarget || !unitTarget->IsPlayer()) return; - unitTarget->ToPlayer()->SendPlayerChoice(GetCaster()->GetGUID(), GetEffect(effIndex)->MiscValue); + unitTarget->ToPlayer()->SendPlayerChoice(GetCaster()->GetGUID(), effectInfo->MiscValue); } void Spell::EffectUncageBattlePet(SpellEffIndex /*effIndex*/) |