aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2017-12-31 18:37:09 +0100
committerShauren <shauren.trinity@gmail.com>2017-12-31 23:22:55 +0100
commit66621a85e970bf370e4e16c690e0401f4e168c1c (patch)
tree07e146a35b688778dbb6f86106b2609d3207458d
parent89c91c271b94f34076be7256378610a2a45c9ed2 (diff)
Core/Quests: Implemented player choice rewards
-rw-r--r--sql/base/auth_database.sql7
-rw-r--r--sql/updates/auth/master/2017_12_31_00_auth.sql7
-rw-r--r--sql/updates/auth/master/9999_99_99_99_auth.sql5
-rw-r--r--sql/updates/world/master/2017_12_31_00_world.sql121
-rw-r--r--sql/updates/world/master/9999_99_99_99_playerchoice.sql83
-rw-r--r--src/server/game/Entities/Creature/GossipDef.h2
-rw-r--r--src/server/game/Entities/Player/Player.cpp176
-rw-r--r--src/server/game/Entities/Player/Player.h3
-rw-r--r--src/server/game/Globals/ObjectMgr.cpp341
-rw-r--r--src/server/game/Globals/ObjectMgr.h99
-rw-r--r--src/server/game/Handlers/QuestHandler.cpp61
-rw-r--r--src/server/game/Scripting/ScriptMgr.cpp4
-rw-r--r--src/server/game/Scripting/ScriptMgr.h4
-rw-r--r--src/server/game/Server/Packets/QuestPackets.cpp97
-rw-r--r--src/server/game/Server/Packets/QuestPackets.h54
-rw-r--r--src/server/game/Server/WorldSession.h4
-rw-r--r--src/server/game/Spells/SpellEffects.cpp4
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*/)