Core/Quests: Implemented player choices

* Implemented SPELL_EFFECT_LAUNCH_QUEST_CHOICE
* Script hook for player choices
This commit is contained in:
Traesh
2017-12-31 23:22:55 +01:00
committed by Shauren
parent 5dd686c080
commit 89c91c271b
18 changed files with 573 additions and 24 deletions
@@ -0,0 +1,5 @@
INSERT INTO `rbac_permissions` (id, NAME) VALUES
(869, "Command: debug send playerchoice");
INSERT INTO `rbac_linked_permissions` (id, linkedId) VALUES
(192, 869);
@@ -0,0 +1,83 @@
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);
+1
View File
@@ -773,6 +773,7 @@ enum RBACPermissions
RBAC_PERM_COMMAND_LIST_SPAWNPOINTS = 866, // reserved
RBAC_PERM_COMMAND_RELOAD_QUEST_GREETING_LOCALE = 867, // reserved
RBAC_PERM_COMMAND_MODIFY_POWER = 868,
RBAC_PERM_COMMAND_DEBUG_SEND_PLAYER_CHOICE = 869,
//
// IF YOU ADD NEW PERMISSIONS, ADD THEM IN 3.3.5 BRANCH AS WELL!
//
@@ -27121,6 +27121,38 @@ void Player::SendMovementSetCollisionHeight(float height)
SendMessageToSet(updateCollisionHeight.Write(), false);
}
void Player::SendPlayerChoice(ObjectGuid sender, uint32 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);
for (auto& playerChoiceResponse : localizedPlayerChoice.Responses)
{
if (PlayerChoiceResponseLocale const* playerChoiceResponseLocale = sObjectMgr->GetPlayerChoiceResponseLocale(localizedPlayerChoice.ChoiceId, playerChoiceResponse.second.ResponseID))
{
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);
}
}
}
WorldPackets::Quest::DisplayPlayerChoice displayPlayerChoice;
displayPlayerChoice.Choice = &localizedPlayerChoice;
displayPlayerChoice.SenderGUID = sender;
SendDirectMessage(displayPlayerChoice.Write());
}
float Player::GetCollisionHeight(bool mounted) const
{
if (mounted)
+2
View File
@@ -2338,6 +2338,8 @@ 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);
protected:
// Gamemaster whisper whitelist
GuidList WhisperList;
+216
View File
@@ -35,6 +35,7 @@
#include "LootMgr.h"
#include "Mail.h"
#include "MapManager.h"
#include "MiscPackets.h"
#include "MotionMaster.h"
#include "ObjectAccessor.h"
#include "ObjectDefines.h"
@@ -9788,6 +9789,40 @@ 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;
}
void ObjectMgr::LoadGameObjectQuestItems()
{
uint32 oldMSTime = getMSTime();
@@ -9908,3 +9943,184 @@ void ObjectMgr::LoadSceneTemplates()
TC_LOG_INFO("server.loading", ">> Loaded %u scene templates in %u ms.", count, GetMSTimeDiffToNow(oldMSTime));
}
void ObjectMgr::LoadPlayerChoices()
{
uint32 oldMSTime = getMSTime();
_playerChoiceContainer.clear();
QueryResult choices = WorldDatabase.Query("SELECT ChoiceID, Question FROM playerchoice");
if (!choices)
{
TC_LOG_INFO("server.loading", ">> Loaded 0 player choices. DB table `playerchoice` is empty.");
return;
}
uint32 responseCount = 0;
uint32 rewardCount = 0;
do
{
Field* fields = choices->Fetch();
int32 choiceId = fields[0].GetInt32();
PlayerChoice& choice = _playerChoiceContainer[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));
QueryResult responses = WorldDatabase.Query("SELECT ChoiceID, ResponseID, ChoiceArtFileID, Header, Answer, Description, Confirmation FROM playerchoice_response");
if (responses)
{
do
{
++responseCount;
Field* fields = responses->Fetch();
int32 choiceId = fields[0].GetInt32();
int32 ResponseID = fields[1].GetInt32();
if (_playerChoiceContainer.find(choiceId) == _playerChoiceContainer.end())
{
TC_LOG_ERROR("sql.sql", "Table `playerchoice_response` has nonexistent choiceId: %u (ResponseID : %u), skipped", choiceId, ResponseID);
continue;
}
PlayerChoice& choice = _playerChoiceContainer[choiceId];
PlayerChoiceResponse& response = choice.Responses[ResponseID];
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());
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.");
}
QueryResult rewards = WorldDatabase.Query("SELECT ChoiceID, ResponseID, TitleID, PackageID, SkillLineID, SkillPointCount, ArenaPointCount, HonorPointCount, Money, Xp FROM playerchoice_response_reward");
if (rewards)
{
do
{
++rewardCount;
Field* fields = rewards->Fetch();
int32 choiceId = fields[0].GetInt32();
int32 ResponseID = fields[1].GetInt32();
if (_playerChoiceContainer.find(choiceId) == _playerChoiceContainer.end())
{
TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` has nonexistent choiceId: %u (ResponseID : %u), skipped", choiceId, ResponseID);
continue;
}
PlayerChoice& choice = _playerChoiceContainer[choiceId];
if (choice.Responses.find(ResponseID) == choice.Responses.end())
{
TC_LOG_ERROR("sql.sql", "Table `playerchoice_response_reward` has nonexistent ResponseID: %u for choiceId %u, skipped", ResponseID, choiceId);
continue;
}
PlayerChoiceResponse& response = choice.Responses[ResponseID];
PlayerChoiceResponseReward reward;
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();
response.Reward = reward;
} while (rewards->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded %u player choices reward in %u ms.", rewardCount, GetMSTimeDiffToNow(oldMSTime));
}
else
{
TC_LOG_INFO("server.loading", ">> Loaded 0 player choices responses reward. DB table `playerchoice_response_reward` is empty.");
}
}
void ObjectMgr::LoadPlayerChoicesLocale()
{
uint32 oldMSTime = getMSTime();
// need for reload case
_playerChoiceLocaleContainer.clear();
_playerChoiceResponseLocaleContainer.clear();
// 0 1 2
QueryResult result = WorldDatabase.Query("SELECT ChoiceID, locale, Question FROM playerchoice_locale");
if (result)
{
do
{
Field* fields = result->Fetch();
uint32 ChoiceID = fields[0].GetUInt32();
std::string localeName = fields[1].GetString();
std::string question = fields[2].GetString();
PlayerChoiceLocale& data = _playerChoiceLocaleContainer[ChoiceID];
LocaleConstant locale = GetLocaleByName(localeName);
if (locale == LOCALE_enUS)
continue;
AddLocaleString(question, locale, data.Question);
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice locale strings in %u ms", _playerChoiceLocaleContainer.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)
{
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();
std::pair<uint32, uint32> pair = std::make_pair(ChoiceID, ResponseID);
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);
} while (result->NextRow());
TC_LOG_INFO("server.loading", ">> Loaded " SZFMTD " Player Choice Response locale strings in %u ms", _playerChoiceResponseLocaleContainer.size(), GetMSTimeDiffToNow(oldMSTime));
}
}
+78 -21
View File
@@ -516,6 +516,22 @@ struct PointOfInterestLocale
typedef std::unordered_map<uint32, PointOfInterestLocale> PointOfInterestLocaleContainer;
struct PlayerChoiceResponseLocale
{
std::vector<std::string> Header;
std::vector<std::string> Answer;
std::vector<std::string> Description;
std::vector<std::string> Confirmation;
};
struct PlayerChoiceLocale
{
std::vector<std::string> Question;
};
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
@@ -752,6 +768,45 @@ struct SceneTemplate
typedef std::unordered_map<uint32, SceneTemplate> SceneTemplateContainer;
struct PlayerChoiceResponseReward
{
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;
};
struct PlayerChoiceResponse
{
int32 ResponseID;
int32 ChoiceArtFileID;
std::string Header;
std::string Answer;
std::string Description;
std::string Confirmation;
Optional<PlayerChoiceResponseReward> Reward;
};
struct PlayerChoice
{
int32 ChoiceId;
std::string Question;
std::unordered_map<int32 /*ResponseID*/, PlayerChoiceResponse> Responses;
};
typedef std::unordered_map<int32 /*choiceId*/, PlayerChoice> PlayerChoiceContainer;
enum SkillRangeType
{
SKILL_RANGE_LANGUAGE, // 300..300
@@ -1175,6 +1230,9 @@ class TC_GAME_API ObjectMgr
void LoadSceneTemplates();
void LoadPlayerChoices();
void LoadPlayerChoicesLocale();
std::string GeneratePetName(uint32 entry);
uint32 GetBaseXP(uint8 level);
uint32 GetXPForLevel(uint8 level) const;
@@ -1326,6 +1384,18 @@ 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
{
PlayerChoiceResponseLocaleContainer::const_iterator itr = _playerChoiceResponseLocaleContainer.find(std::make_pair(ChoiceID, ResponseID));
if (itr == _playerChoiceResponseLocaleContainer.end()) return nullptr;
return &itr->second;
}
GameObjectData const* GetGOData(ObjectGuid::LowType guid) const
{
@@ -1488,31 +1558,14 @@ 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
{
auto itr = _raceExpansionRequirementStore.find(race);
if (itr != _raceExpansionRequirementStore.end())
return itr->second;
return EXPANSION_CLASSIC;
}
uint8 GetRaceExpansionRequirement(uint8 race) const;
std::unordered_map<uint8, uint8> const& GetClassExpansionRequirements() const { return _classExpansionRequirementStore; }
uint8 GetClassExpansionRequirement(uint8 class_) const
{
auto itr = _classExpansionRequirementStore.find(class_);
if (itr != _classExpansionRequirementStore.end())
return itr->second;
return EXPANSION_CLASSIC;
}
uint8 GetClassExpansionRequirement(uint8 class_) const;
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;
private:
// first free id for selected id type
@@ -1647,6 +1700,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;
ItemTemplateContainer _itemTemplateStore;
QuestTemplateLocaleContainer _questTemplateLocaleStore;
@@ -1657,6 +1711,9 @@ class TC_GAME_API ObjectMgr
GossipMenuItemsLocaleContainer _gossipMenuItemsLocaleStore;
PointOfInterestLocaleContainer _pointOfInterestLocaleStore;
PlayerChoiceLocaleContainer _playerChoiceLocaleContainer;
PlayerChoiceResponseLocaleContainer _playerChoiceResponseLocaleContainer;
TrinityStringContainer _trinityStringStore;
CacheVendorItemContainer _cacheVendorItemStore;
@@ -673,3 +673,8 @@ void WorldSession::HandleRequestWorldQuestUpdate(WorldPackets::Quest::RequestWor
SendPacket(response.Write());
}
void WorldSession::HandlePlayerChoiceResponse(WorldPackets::Quest::PlayerChoiceResponse& packet)
{
sScriptMgr->OnPlayerChoiceResponse(GetPlayer(), packet.ChoiceID, packet.ResponseID);
}
+5
View File
@@ -2297,6 +2297,11 @@ void ScriptMgr::OnMovieComplete(Player* player, uint32 movieId)
FOREACH_SCRIPT(PlayerScript)->OnMovieComplete(player, movieId);
}
void ScriptMgr::OnPlayerChoiceResponse(Player* player, uint32 choiceID, uint32 responseID)
{
FOREACH_SCRIPT(PlayerScript)->OnPlayerChoiceResponse(player, choiceID, responseID);
}
// Account
void ScriptMgr::OnAccountLogin(uint32 accountId)
{
+4
View File
@@ -755,6 +755,9 @@ class TC_GAME_API PlayerScript : public UnitScript
// Called when a player completes a movie
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*/) { }
};
class TC_GAME_API AccountScript : public ScriptObject
@@ -1143,6 +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);
public: /* AccountScript */
@@ -599,3 +599,79 @@ WorldPacket const* WorldPackets::Quest::WorldQuestUpdate::Write()
return &_worldPacket;
}
ByteBuffer& operator<<(ByteBuffer& data, PlayerChoiceResponse const& response)
{
data << int32(response.ResponseID);
data << int32(response.ChoiceArtFileID);
data.WriteBits(response.Answer.length(), 9);
data.WriteBits(response.Header.length(), 9);
data.WriteBits(response.Description.length(), 11);
data.WriteBits(response.Confirmation.length(), 7);
data.WriteBit(response.Reward.is_initialized());
data.FlushBits();
if (response.Reward.is_initialized())
data << (*response.Reward);
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)
{
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);
for (var i = 0u; i < currencyCount; ++i)
ReadPlayerChoiceResponseRewardEntry(packet, "Currency", i);
for (var i = 0u; i < factionCount; ++i)
ReadPlayerChoiceResponseRewardEntry(packet, "Faction", i);
for (var i = 0u; i < itemChoiceCount; ++i)
ReadPlayerChoiceResponseRewardEntry(packet, "ItemChoice", i);*/
return data;
}
WorldPacket const* WorldPackets::Quest::DisplayPlayerChoice::Write()
{
_worldPacket << int32(Choice->ChoiceId);
_worldPacket << uint32(Choice->Responses.size());
_worldPacket << SenderGUID;
_worldPacket.WriteBits(Choice->Question.length(), 8);
_worldPacket.WriteBit(CloseChoiceFrame);
_worldPacket.FlushBits();
for (auto response : Choice->Responses)
_worldPacket << response.second;
_worldPacket.WriteString(Choice->Question);
return &_worldPacket;
}
void WorldPackets::Quest::PlayerChoiceResponse::Read()
{
_worldPacket >> ChoiceID;
_worldPacket >> ResponseID;
}
@@ -23,6 +23,10 @@
#include "QuestDef.h"
#include "ObjectGuid.h"
struct PlayerChoice;
struct PlayerChoiceResponse;
struct PlayerChoiceResponseReward;
namespace WorldPackets
{
namespace Quest
@@ -633,9 +637,35 @@ namespace WorldPackets
std::vector<WorldQuestUpdateInfo> WorldQuestUpdates;
};
class DisplayPlayerChoice final : public ServerPacket
{
public:
DisplayPlayerChoice() : ServerPacket(SMSG_DISPLAY_PLAYER_CHOICE) { }
WorldPacket const* Write() override;
ObjectGuid SenderGUID;
PlayerChoice const* Choice;
bool CloseChoiceFrame = false;
};
class PlayerChoiceResponse final : public ClientPacket
{
public:
PlayerChoiceResponse(WorldPacket&& packet) : ClientPacket(CMSG_CHOICE_RESPONSE, std::move(packet)) { }
void Read() override;
int32 ChoiceID;
int32 ResponseID;
};
}
}
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);
+2 -2
View File
@@ -322,7 +322,7 @@ void OpcodeTable::Initialize()
DEFINE_HANDLER(CMSG_CHAT_UNREGISTER_ALL_ADDON_PREFIXES, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleUnregisterAllAddonPrefixesOpcode);
DEFINE_HANDLER(CMSG_CHECK_RAF_EMAIL_ENABLED, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_CHECK_WOW_TOKEN_VETERAN_ELIGIBILITY, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_CHOICE_RESPONSE, STATUS_UNHANDLED, PROCESS_INPLACE, &WorldSession::Handle_NULL);
DEFINE_HANDLER(CMSG_CHOICE_RESPONSE, STATUS_LOGGEDIN, PROCESS_INPLACE, &WorldSession::HandlePlayerChoiceResponse);
DEFINE_HANDLER(CMSG_CLEAR_RAID_MARKER, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearRaidMarker);
DEFINE_HANDLER(CMSG_CLEAR_TRADE_ITEM, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandleClearTradeItemOpcode);
DEFINE_HANDLER(CMSG_CLIENT_PORT_GRAVEYARD, STATUS_LOGGEDIN, PROCESS_THREADUNSAFE, &WorldSession::HandlePortGraveyard);
@@ -1108,7 +1108,7 @@ void OpcodeTable::Initialize()
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISMOUNT_RESULT, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPEL_FAILED, STATUS_NEVER, CONNECTION_TYPE_INSTANCE);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_GAME_ERROR, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PLAYER_CHOICE, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PLAYER_CHOICE, STATUS_NEVER, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_PROMOTION, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_QUEST_POPUP, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
DEFINE_SERVER_OPCODE_HANDLER(SMSG_DISPLAY_TOAST, STATUS_UNHANDLED, CONNECTION_TYPE_REALM);
+2
View File
@@ -596,6 +596,7 @@ namespace WorldPackets
class QuestPushResult;
class PushQuestToParty;
class RequestWorldQuestUpdate;
class PlayerChoiceResponse;
}
namespace RaF
@@ -1442,6 +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 HandleChatMessageOpcode(WorldPackets::Chat::ChatMessage& chatMessage);
void HandleChatMessageWhisperOpcode(WorldPackets::Chat::ChatMessageWhisper& chatMessageWhisper);
+1
View File
@@ -468,6 +468,7 @@ class TC_GAME_API Spell
void EffectActivateGarrisonBuilding(SpellEffIndex effIndex);
void EffectHealBattlePetPct(SpellEffIndex effIndex);
void EffectEnableBattlePets(SpellEffIndex effIndex);
void EffectLaunchQuestChoice(SpellEffIndex effIndex);
void EffectUncageBattlePet(SpellEffIndex effIndex);
void EffectCreateHeirloomItem(SpellEffIndex effIndex);
void EffectUpgradeHeirloom(SpellEffIndex effIndex);
+12 -1
View File
@@ -278,7 +278,7 @@ pEffect SpellEffects[TOTAL_SPELL_EFFECTS]=
&Spell::EffectNULL, //202 SPELL_EFFECT_202
&Spell::EffectNULL, //203 SPELL_EFFECT_203
&Spell::EffectNULL, //204 SPELL_EFFECT_CHANGE_BATTLEPET_QUALITY
&Spell::EffectNULL, //205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE
&Spell::EffectLaunchQuestChoice, //205 SPELL_EFFECT_LAUNCH_QUEST_CHOICE
&Spell::EffectNULL, //206 SPELL_EFFECT_ALTER_ITEM
&Spell::EffectNULL, //207 SPELL_EFFECT_LAUNCH_QUEST_TASK
&Spell::EffectNULL, //208 SPELL_EFFECT_208
@@ -5666,6 +5666,17 @@ void Spell::EffectEnableBattlePets(SpellEffIndex /*effIndex*/)
plr->GetSession()->GetBattlePetMgr()->UnlockSlot(0);
}
void Spell::EffectLaunchQuestChoice(SpellEffIndex effIndex)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT_TARGET)
return;
if (!unitTarget || !unitTarget->IsPlayer())
return;
unitTarget->ToPlayer()->SendPlayerChoice(GetCaster()->GetGUID(), GetEffect(effIndex)->MiscValue);
}
void Spell::EffectUncageBattlePet(SpellEffIndex /*effIndex*/)
{
if (effectHandleMode != SPELL_EFFECT_HANDLE_HIT)
+6
View File
@@ -1851,6 +1851,12 @@ void World::SetInitialWorldSettings()
TC_LOG_INFO("server.loading", "Loading Scenes Templates...");
sObjectMgr->LoadSceneTemplates();
TC_LOG_INFO("server.loading", "Loading Player Choices...");
sObjectMgr->LoadPlayerChoices();
TC_LOG_INFO("server.loading", "Loading Player Choices Locales...");
sObjectMgr->LoadPlayerChoicesLocale();
CharacterDatabaseCleaner::CleanDatabase();
TC_LOG_INFO("server.loading", "Loading the max pet number...");
+13
View File
@@ -71,6 +71,7 @@ public:
{ "sellerror", rbac::RBAC_PERM_COMMAND_DEBUG_SEND_SELLERROR, false, &HandleDebugSendSellErrorCommand, "" },
{ "setphaseshift", rbac::RBAC_PERM_COMMAND_DEBUG_SEND_SETPHASESHIFT, false, &HandleDebugSendSetPhaseShiftCommand, "" },
{ "spellfail", rbac::RBAC_PERM_COMMAND_DEBUG_SEND_SPELLFAIL, false, &HandleDebugSendSpellFailCommand, "" },
{ "playerchoice", rbac::RBAC_PERM_COMMAND_DEBUG_SEND_PLAYER_CHOICE, false, &HandleDebugSendPlayerChoiceCommand, "" },
};
static std::vector<ChatCommand> debugCommandTable =
{
@@ -245,6 +246,18 @@ public:
return true;
}
static bool HandleDebugSendPlayerChoiceCommand(ChatHandler* handler, char const* args)
{
if (!*args)
return false;
int32 choiceId = atoi(args);
Player* player = handler->GetSession()->GetPlayer();
player->SendPlayerChoice(player->GetGUID(), choiceId);
return true;
}
static bool HandleDebugSendEquipErrorCommand(ChatHandler* handler, char const* args)
{
if (!*args)