/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#ifndef TRINITYCORE_GOSSIP_H
#define TRINITYCORE_GOSSIP_H
#include "Common.h"
#include "Duration.h"
#include "ObjectGuid.h"
#include "Optional.h"
#include
class Object;
class Quest;
class WorldSession;
struct GossipMenuItems;
enum class PlayerInteractionType : int32;
enum class QuestGiverStatus : uint64;
#define GOSSIP_MAX_MENU_ITEMS 32
#define DEFAULT_GOSSIP_MESSAGE 0xffffff
enum class GossipOptionNpc : uint8
{
None = 0, // White chat bubble. Default
Vendor = 1, // Brown bag
Taxinode = 2, // White wing
Trainer = 3, // Brown book
SpiritHealer = 4, // Golden interaction wheel (with red center)
Binder = 5, // Golden interaction wheel
Banker = 6, // Brown bag (with gold coin in lower corner)
PetitionVendor = 7, // White chat bubble (with "..." inside)
GuildTabardVendor = 8, // White tabard
Battlemaster = 9, // Two crossed swords
Auctioneer = 10, // Stack of gold coins
TalentMaster = 11, // White chat bubble
Stablemaster = 12, // White chat bubble
PetSpecializationMaster = 13, /*DEPRECATED*/ // White chat bubble
GuildBanker = 14, // White chat bubble
Spellclick = 15, // White chat bubble
DisableXPGain = 16, // White chat bubble
EnableXPGain = 17, // White chat bubble
Mailbox = 18, // White chat bubble
WorldPvPQueue = 19, /*NYI*/ // White chat bubble
LFGDungeon = 20, /*NYI*/ // White chat bubble
ArtifactRespec = 21, /*NYI*/ // White chat bubble
CemeterySelect = 22, /*DEPRECATED*/ // White chat bubble
SpecializationMaster = 23, /*DEPRECATED*/ // White chat bubble
GlyphMaster = 24, /*DEPRECATED*/ // White chat bubble
QueueScenario = 25, /*NYI*/ // White chat bubble
GarrisonArchitect = 26, /*NYI*/ // White chat bubble
GarrisonMissionNpc = 27, /*NYI*/ // White chat bubble
ShipmentCrafter = 28, /*NYI*/ // Brown document
GarrisonTradeskillNpc = 29, /*NYI*/ // White chat bubble
GarrisonRecruitment = 30, /*NYI*/ // White chat bubble
AdventureMap = 31, /*NYI*/ // White chat bubble
GarrisonTalent = 32, // White chat bubble
ContributionCollector = 33, /*NYI*/ // White chat bubble
Transmogrify = 34, // Purple helm
AzeriteRespec = 35, // White chat bubble
IslandsMissionNpc = 36, /*NYI*/ // White chat bubble
UIItemInteraction = 37, /*NYI*/ // White chat bubble
WorldMap = 38, /*NYI*/ // White chat bubble
Soulbind = 39, /*NYI*/ // White chat bubble
ChromieTimeNpc = 40, /*NYI*/ // White chat bubble
CovenantPreviewNpc = 41, /*NYI*/ // White chat bubble
RuneforgeLegendaryCrafting = 42, /*NYI*/ // White chat bubble
NewPlayerGuide = 43, /*NYI*/ // White chat bubble
RuneforgeLegendaryUpgrade = 44, /*NYI*/ // White chat bubble
CovenantRenownNpc = 45, /*NYI*/ // White chat bubble
BlackMarketAuctionHouse = 46,
PerksProgramVendor = 47,
ProfessionsCraftingOrder = 48,
ProfessionsOpen = 49,
ProfessionsCustomerOrder = 50,
TraitSystem = 51,
BarbersChoice = 52,
MajorFactionRenown = 53,
PersonalTabardVendor = 54,
ForgeMaster = 55,
CharacterBanker = 56,
AccountBanker = 57,
ProfessionRespec = 58,
Placeholder1 = 59,
Placeholder2 = 60,
Placeholder3 = 61,
GuildRename = 62,
Placeholder4 = 63,
ItemUpgrade = 64,
Count
};
enum class GossipOptionStatus : uint8
{
Available = 0,
Unavailable = 1,
Locked = 2,
AlreadyComplete = 3
};
enum class GossipOptionRewardType : uint8
{
Item = 0,
Currency = 1
};
enum class GossipOptionFlags : int32
{
None = 0x0,
QuestLabelPrepend = 0x1,
HideOptionIDFromClient = 0x2,
PlayMovieLabelPrepend = 0x4
};
struct GossipMenuItem
{
int32 GossipOptionID;
uint32 OrderIndex;
GossipOptionNpc OptionNpc;
std::string OptionText;
uint32 Language;
GossipOptionFlags Flags;
Optional GossipNpcOptionID;
bool BoxCoded;
uint64 BoxMoney;
std::string BoxText;
Optional SpellID;
Optional OverrideIconID;
// action data
uint32 ActionMenuID;
uint32 ActionPoiID;
// additional scripting identifiers
uint32 Sender;
uint32 Action;
};
// need an ordered container
typedef std::vector GossipMenuItemContainer;
struct QuestMenuItem
{
uint32 QuestId;
uint8 QuestIcon;
};
typedef std::vector QuestMenuItemList;
class TC_GAME_API GossipMenu
{
public:
GossipMenu();
GossipMenu(GossipMenu const&) = delete;
GossipMenu(GossipMenu&&) = delete;
GossipMenu& operator=(GossipMenu const&) = delete;
GossipMenu& operator=(GossipMenu&&) = delete;
~GossipMenu();
uint32 AddMenuItem(int32 gossipOptionId, int32 orderIndex, GossipOptionNpc optionNpc, std::string optionText, uint32 language, GossipOptionFlags flags,
Optional gossipNpcOptionId, uint32 actionMenuId, uint32 actionPoiId, bool boxCoded, uint64 boxMoney,
std::string boxText, Optional spellId, Optional overrideIconId, uint32 sender, uint32 action);
void AddMenuItem(uint32 menuId, uint32 menuItemId, uint32 sender, uint32 action);
void AddMenuItem(GossipMenuItems const& menuItem, uint32 sender, uint32 action);
void SetMenuId(uint32 menu_id) { _menuId = menu_id; }
uint32 GetMenuId() const { return _menuId; }
void SetLocale(LocaleConstant locale) { _locale = locale; }
LocaleConstant GetLocale() const { return _locale; }
uint32 GetMenuItemCount() const
{
return _menuItems.size();
}
bool Empty() const
{
return _menuItems.empty();
}
GossipMenuItem const* GetItem(int32 gossipOptionId) const;
GossipMenuItem const* GetItemByIndex(uint32 orderIndex) const;
uint32 GetMenuItemSender(uint32 orderIndex) const;
uint32 GetMenuItemAction(uint32 orderIndex) const;
bool IsMenuItemCoded(uint32 orderIndex) const;
void ClearMenu();
GossipMenuItemContainer const& GetMenuItems() const
{
return _menuItems;
}
private:
GossipMenuItemContainer _menuItems;
uint32 _menuId;
LocaleConstant _locale;
};
class TC_GAME_API QuestMenu
{
public:
QuestMenu();
QuestMenu(QuestMenu const&) = delete;
QuestMenu(QuestMenu&&) = delete;
QuestMenu& operator=(QuestMenu const&) = delete;
QuestMenu& operator=(QuestMenu&&) = delete;
~QuestMenu();
void AddMenuItem(uint32 QuestId, uint8 Icon);
void ClearMenu();
uint8 GetMenuItemCount() const{ return uint8(_questMenuItems.size()); }
bool Empty() const { return _questMenuItems.empty(); }
bool HasItem(uint32 questId) const;
QuestMenuItem const& GetItem(uint16 index) const { return _questMenuItems[index]; }
private:
QuestMenuItemList _questMenuItems;
};
class PlayerChoiceData
{
public:
PlayerChoiceData() = default;
explicit PlayerChoiceData(uint32 choiceId) : _choiceId(choiceId) { }
uint32 GetChoiceId() const { return _choiceId; }
void SetChoiceId(uint32 choiceId) { _choiceId = choiceId; }
Optional FindIdByClientIdentifier(uint16 clientIdentifier) const;
void AddResponse(uint32 id, uint16 clientIdentifier);
Optional GetExpireTime() const { return _expireTime; }
void SetExpireTime(Optional expireTime) { _expireTime = expireTime; }
private:
struct Response
{
uint32 Id = 0;
uint16 ClientIdentifier = 0;
};
uint32 _choiceId = 0;
std::vector _responses;
Optional _expireTime;
};
class TC_GAME_API InteractionData
{
template
struct TaggedId
{
TaggedId() = default;
explicit TaggedId(uint32 id) : Id(id) { }
uint32 Id = 0;
};
struct TrainerTag;
using TrainerData = TaggedId;
public:
InteractionData();
InteractionData(InteractionData const& other);
InteractionData(InteractionData&& other) noexcept;
InteractionData& operator=(InteractionData const& other);
InteractionData& operator=(InteractionData&& other) noexcept;
~InteractionData();
void StartInteraction(ObjectGuid target, PlayerInteractionType type);
bool IsInteractingWith(ObjectGuid target, PlayerInteractionType type) const { return SourceGuid == target && Type == type; }
void Reset();
ObjectGuid SourceGuid;
PlayerInteractionType Type = { };
TrainerData* GetTrainer() { return std::holds_alternative(_data) ? &std::get(_data) : nullptr; }
PlayerChoiceData* GetPlayerChoice() { return std::holds_alternative(_data) ? &std::get(_data) : nullptr; }
uint16 AddPlayerChoiceResponse(uint32 responseId)
{
std::get(_data).AddResponse(responseId, ++_playerChoiceResponseIdentifierGenerator);
return _playerChoiceResponseIdentifierGenerator;
}
bool IsLaunchedByQuest = false;
private:
uint16 _playerChoiceResponseIdentifierGenerator = 0; // not reset between interactions
std::variant _data;
};
class TC_GAME_API PlayerMenu
{
public:
explicit PlayerMenu(WorldSession* session);
PlayerMenu(PlayerMenu const&) = delete;
PlayerMenu(PlayerMenu&&) = delete;
PlayerMenu& operator=(PlayerMenu const&) = delete;
PlayerMenu& operator=(PlayerMenu&&) = delete;
~PlayerMenu();
GossipMenu& GetGossipMenu() { return _gossipMenu; }
QuestMenu& GetQuestMenu() { return _questMenu; }
InteractionData& GetInteractionData() { return _interactionData; }
bool Empty() const { return _gossipMenu.Empty() && _questMenu.Empty(); }
void ClearMenus();
uint32 GetGossipOptionSender(uint32 selection) const { return _gossipMenu.GetMenuItemSender(selection); }
uint32 GetGossipOptionAction(uint32 selection) const { return _gossipMenu.GetMenuItemAction(selection); }
bool IsGossipOptionCoded(uint32 selection) const { return _gossipMenu.IsMenuItemCoded(selection); }
void SendGossipMenu(uint32 titleTextId, ObjectGuid objectGUID);
void SendCloseGossip();
void SendPointOfInterest(uint32 poiId) const;
/*********************************************************/
/*** QUEST SYSTEM ***/
/*********************************************************/
void SendQuestGiverStatus(QuestGiverStatus questStatus, ObjectGuid npcGUID) const;
void SendQuestGiverQuestListMessage(Object* questgiver);
void SendQuestQueryResponse(Quest const* quest) const;
void SendQuestGiverQuestDetails(Quest const* quest, ObjectGuid npcGUID, bool autoLaunched, bool displayPopup);
void SendQuestGiverOfferReward(Quest const* quest, ObjectGuid npcGUID, bool autoLaunched);
void SendQuestGiverRequestItems(Quest const* quest, ObjectGuid npcGUID, bool canComplete, bool autoLaunched);
private:
GossipMenu _gossipMenu;
QuestMenu _questMenu;
WorldSession* _session;
InteractionData _interactionData;
};
#endif