Core/Players: PlayerChoice improvements
Port From (https://github.com/TrinityCore/TrinityCore/commit/e59059e1bd2f67691e2da0105771b0cb55b123a4)
This commit is contained in:
@@ -8,6 +8,7 @@ using Game.DataStorage;
|
|||||||
using Game.Entities;
|
using Game.Entities;
|
||||||
using Game.Networking.Packets;
|
using Game.Networking.Packets;
|
||||||
using Game.Spells;
|
using Game.Spells;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
@@ -205,16 +206,31 @@ namespace Game.Misc
|
|||||||
|
|
||||||
public class InteractionData
|
public class InteractionData
|
||||||
{
|
{
|
||||||
|
public ObjectGuid SourceGuid;
|
||||||
|
public bool IsLaunchedByQuest;
|
||||||
|
|
||||||
|
ushort _playerChoiceResponseIdentifierGenerator = 0; // not reset between interactions
|
||||||
|
uint trainerId;
|
||||||
|
PlayerChoiceData playerChoiceData;
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
SourceGuid.Clear();
|
SourceGuid.Clear();
|
||||||
TrainerId = 0;
|
IsLaunchedByQuest = false;
|
||||||
|
trainerId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObjectGuid SourceGuid;
|
public uint? GetTrainerId() { return trainerId; }
|
||||||
public uint TrainerId;
|
public void SetTrainerId(uint _trainerId) { trainerId = _trainerId; }
|
||||||
public uint PlayerChoiceId;
|
|
||||||
public bool IsLaunchedByQuest;
|
public PlayerChoiceData GetPlayerChoice() { return playerChoiceData; }
|
||||||
|
public void SetPlayerChoice(uint choiceId) { playerChoiceData = new PlayerChoiceData(choiceId); }
|
||||||
|
|
||||||
|
public ushort AddPlayerChoiceResponse(uint responseId)
|
||||||
|
{
|
||||||
|
playerChoiceData.AddResponse(responseId, ++_playerChoiceResponseIdentifierGenerator);
|
||||||
|
return _playerChoiceResponseIdentifierGenerator;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PlayerMenu
|
public class PlayerMenu
|
||||||
@@ -835,4 +851,40 @@ namespace Game.Misc
|
|||||||
public uint TextId;
|
public uint TextId;
|
||||||
public ConditionsReference Conditions;
|
public ConditionsReference Conditions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PlayerChoiceData
|
||||||
|
{
|
||||||
|
uint _choiceId;
|
||||||
|
List<Response> _responses = new();
|
||||||
|
DateTime? _expireTime;
|
||||||
|
|
||||||
|
public PlayerChoiceData(uint choiceId)
|
||||||
|
{
|
||||||
|
_choiceId = choiceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint? FindIdByClientIdentifier(ushort clientIdentifier)
|
||||||
|
{
|
||||||
|
var itr = _responses.Find(p => p.ClientIdentifier == clientIdentifier);
|
||||||
|
return itr != null ? itr.Id : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddResponse(uint id, ushort clientIdentifier)
|
||||||
|
{
|
||||||
|
_responses.Add(new Response(id, clientIdentifier));
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint GetChoiceId() { return _choiceId; }
|
||||||
|
public void SetChoiceId(uint choiceId) { _choiceId = choiceId; }
|
||||||
|
|
||||||
|
public DateTime? GetExpireTime() { return _expireTime; }
|
||||||
|
public void SetExpireTime(DateTime expireTime) { _expireTime = expireTime; }
|
||||||
|
|
||||||
|
|
||||||
|
public class Response(uint id, ushort clientIdentifier)
|
||||||
|
{
|
||||||
|
public uint Id = id;
|
||||||
|
public ushort ClientIdentifier = clientIdentifier;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4954,22 +4954,28 @@ namespace Game.Entities
|
|||||||
|
|
||||||
PlayerTalkClass.GetInteractionData().Reset();
|
PlayerTalkClass.GetInteractionData().Reset();
|
||||||
PlayerTalkClass.GetInteractionData().SourceGuid = sender;
|
PlayerTalkClass.GetInteractionData().SourceGuid = sender;
|
||||||
PlayerTalkClass.GetInteractionData().PlayerChoiceId = (uint)choiceId;
|
PlayerTalkClass.GetInteractionData().SetPlayerChoice((uint)choiceId);
|
||||||
|
|
||||||
DisplayPlayerChoice displayPlayerChoice = new();
|
DisplayPlayerChoice displayPlayerChoice = new();
|
||||||
displayPlayerChoice.SenderGUID = sender;
|
displayPlayerChoice.SenderGUID = sender;
|
||||||
displayPlayerChoice.ChoiceID = choiceId;
|
displayPlayerChoice.ChoiceID = choiceId;
|
||||||
displayPlayerChoice.UiTextureKitID = playerChoice.UiTextureKitId;
|
displayPlayerChoice.UiTextureKitID = playerChoice.UiTextureKitId;
|
||||||
displayPlayerChoice.SoundKitID = playerChoice.SoundKitId;
|
displayPlayerChoice.SoundKitID = playerChoice.SoundKitId;
|
||||||
|
displayPlayerChoice.CloseUISoundKitID = playerChoice.CloseSoundKitId;
|
||||||
|
if (playerChoice.Duration > TimeSpan.Zero)
|
||||||
|
displayPlayerChoice.ExpireTime = (GameTime.GetSystemTime() + playerChoice.Duration).ToFileTime();
|
||||||
|
|
||||||
displayPlayerChoice.Question = playerChoice.Question;
|
displayPlayerChoice.Question = playerChoice.Question;
|
||||||
if (playerChoiceLocale != null)
|
if (playerChoiceLocale != null)
|
||||||
ObjectManager.GetLocaleString(playerChoiceLocale.Question, locale, ref displayPlayerChoice.Question);
|
ObjectManager.GetLocaleString(playerChoiceLocale.Question, locale, ref displayPlayerChoice.Question);
|
||||||
|
|
||||||
displayPlayerChoice.InfiniteRange = false;
|
displayPlayerChoice.InfiniteRange = playerChoice.InfiniteRange;
|
||||||
displayPlayerChoice.HideWarboardHeader = playerChoice.HideWarboardHeader;
|
displayPlayerChoice.HideWarboardHeader = playerChoice.HideWarboardHeader;
|
||||||
displayPlayerChoice.KeepOpenAfterChoice = playerChoice.KeepOpenAfterChoice;
|
displayPlayerChoice.KeepOpenAfterChoice = playerChoice.KeepOpenAfterChoice;
|
||||||
|
displayPlayerChoice.ShowChoicesAsList = playerChoice.ShowChoicesAsList;
|
||||||
|
displayPlayerChoice.ForceDontShowChoicesAsList = playerChoice.ForceDontShowChoicesAsList;
|
||||||
|
|
||||||
for (var i = 0; i < playerChoice.Responses.Count; ++i)
|
for (var i = 0; i < playerChoice.Responses.Count && (playerChoice.MaxResponses == 0 || displayPlayerChoice.Responses.Count < playerChoice.MaxResponses); ++i)
|
||||||
{
|
{
|
||||||
PlayerChoiceResponse playerChoiceResponseTemplate = playerChoice.Responses[i];
|
PlayerChoiceResponse playerChoiceResponseTemplate = playerChoice.Responses[i];
|
||||||
if (!Global.ConditionMgr.IsObjectMeetingPlayerChoiceResponseConditions((uint)choiceId, playerChoiceResponseTemplate.ResponseId, this))
|
if (!Global.ConditionMgr.IsObjectMeetingPlayerChoiceResponseConditions((uint)choiceId, playerChoiceResponseTemplate.ResponseId, this))
|
||||||
@@ -4977,9 +4983,9 @@ namespace Game.Entities
|
|||||||
|
|
||||||
var playerChoiceResponse = new Networking.Packets.PlayerChoiceResponse();
|
var playerChoiceResponse = new Networking.Packets.PlayerChoiceResponse();
|
||||||
playerChoiceResponse.ResponseID = playerChoiceResponseTemplate.ResponseId;
|
playerChoiceResponse.ResponseID = playerChoiceResponseTemplate.ResponseId;
|
||||||
playerChoiceResponse.ResponseIdentifier = playerChoiceResponseTemplate.ResponseIdentifier;
|
playerChoiceResponse.ResponseIdentifier = PlayerTalkClass.GetInteractionData().AddPlayerChoiceResponse((uint)playerChoiceResponseTemplate.ResponseId);
|
||||||
playerChoiceResponse.ChoiceArtFileID = playerChoiceResponseTemplate.ChoiceArtFileId;
|
playerChoiceResponse.ChoiceArtFileID = playerChoiceResponseTemplate.ChoiceArtFileId;
|
||||||
playerChoiceResponse.Flags = playerChoiceResponseTemplate.Flags;
|
playerChoiceResponse.Flags = (int)playerChoiceResponseTemplate.Flags;
|
||||||
playerChoiceResponse.WidgetSetID = playerChoiceResponseTemplate.WidgetSetID;
|
playerChoiceResponse.WidgetSetID = playerChoiceResponseTemplate.WidgetSetID;
|
||||||
playerChoiceResponse.UiTextureAtlasElementID = playerChoiceResponseTemplate.UiTextureAtlasElementID;
|
playerChoiceResponse.UiTextureAtlasElementID = playerChoiceResponseTemplate.UiTextureAtlasElementID;
|
||||||
playerChoiceResponse.SoundKitID = playerChoiceResponseTemplate.SoundKitID;
|
playerChoiceResponse.SoundKitID = playerChoiceResponseTemplate.SoundKitID;
|
||||||
@@ -5017,51 +5023,32 @@ namespace Game.Entities
|
|||||||
reward.Money = playerChoiceResponseTemplate.Reward.Money;
|
reward.Money = playerChoiceResponseTemplate.Reward.Money;
|
||||||
reward.Xp = playerChoiceResponseTemplate.Reward.Xp;
|
reward.Xp = playerChoiceResponseTemplate.Reward.Xp;
|
||||||
|
|
||||||
foreach (var item in playerChoiceResponseTemplate.Reward.Items)
|
void fillRewardItems<T>(List<T> src, List<Networking.Packets.PlayerChoiceResponseRewardEntry> dest)
|
||||||
{
|
{
|
||||||
var rewardEntry = new Networking.Packets.PlayerChoiceResponseRewardEntry();
|
for (var j = 0; j < src.Count; ++j)
|
||||||
rewardEntry.Item.ItemID = item.Id;
|
|
||||||
rewardEntry.Quantity = item.Quantity;
|
|
||||||
if (!item.BonusListIDs.Empty())
|
|
||||||
{
|
{
|
||||||
rewardEntry.Item.ItemBonus = new();
|
dynamic rewardEntryTemplate = src[j];
|
||||||
rewardEntry.Item.ItemBonus.BonusListIDs = item.BonusListIDs;
|
Networking.Packets.PlayerChoiceResponseRewardEntry rewardEntry = new();
|
||||||
|
rewardEntry.Item.ItemID = rewardEntryTemplate.Id;
|
||||||
|
rewardEntry.Quantity = rewardEntryTemplate.Quantity;
|
||||||
|
if (rewardEntryTemplate is PlayerChoiceResponseRewardItem)
|
||||||
|
{
|
||||||
|
if (!rewardEntryTemplate.BonusListIDs.empty())
|
||||||
|
{
|
||||||
|
ItemBonuses itemBonuses = new();
|
||||||
|
itemBonuses.BonusListIDs = rewardEntryTemplate.BonusListIDs;
|
||||||
|
rewardEntry.Item.ItemBonus = itemBonuses;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.Add(rewardEntry);
|
||||||
}
|
}
|
||||||
reward.Items.Add(rewardEntry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var currency in playerChoiceResponseTemplate.Reward.Currency)
|
fillRewardItems(playerChoiceResponseTemplate.Reward.Items, playerChoiceResponse.Reward.Items);
|
||||||
{
|
fillRewardItems(playerChoiceResponseTemplate.Reward.Currency, playerChoiceResponse.Reward.Currencies);
|
||||||
var rewardEntry = new Networking.Packets.PlayerChoiceResponseRewardEntry();
|
fillRewardItems(playerChoiceResponseTemplate.Reward.Faction, playerChoiceResponse.Reward.Factions);
|
||||||
rewardEntry.Item.ItemID = currency.Id;
|
fillRewardItems(playerChoiceResponseTemplate.Reward.ItemChoices, playerChoiceResponse.Reward.ItemChoices);
|
||||||
rewardEntry.Quantity = currency.Quantity;
|
|
||||||
reward.Items.Add(rewardEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var faction in playerChoiceResponseTemplate.Reward.Faction)
|
|
||||||
{
|
|
||||||
var rewardEntry = new Networking.Packets.PlayerChoiceResponseRewardEntry();
|
|
||||||
rewardEntry.Item.ItemID = faction.Id;
|
|
||||||
rewardEntry.Quantity = faction.Quantity;
|
|
||||||
reward.Items.Add(rewardEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PlayerChoiceResponseRewardItem item in playerChoiceResponseTemplate.Reward.ItemChoices)
|
|
||||||
{
|
|
||||||
var rewardEntry = new Networking.Packets.PlayerChoiceResponseRewardEntry();
|
|
||||||
rewardEntry.Item.ItemID = item.Id;
|
|
||||||
rewardEntry.Quantity = item.Quantity;
|
|
||||||
if (!item.BonusListIDs.Empty())
|
|
||||||
{
|
|
||||||
rewardEntry.Item.ItemBonus = new();
|
|
||||||
rewardEntry.Item.ItemBonus.BonusListIDs = item.BonusListIDs;
|
|
||||||
}
|
|
||||||
|
|
||||||
reward.ItemChoices.Add(rewardEntry);
|
|
||||||
}
|
|
||||||
|
|
||||||
playerChoiceResponse.Reward = reward;
|
|
||||||
displayPlayerChoice.Responses[i] = playerChoiceResponse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
playerChoiceResponse.RewardQuestID = playerChoiceResponseTemplate.RewardQuestID;
|
playerChoiceResponse.RewardQuestID = playerChoiceResponseTemplate.RewardQuestID;
|
||||||
|
|||||||
@@ -10152,7 +10152,10 @@ namespace Game
|
|||||||
uint oldMSTime = Time.GetMSTime();
|
uint oldMSTime = Time.GetMSTime();
|
||||||
_playerChoices.Clear();
|
_playerChoices.Clear();
|
||||||
|
|
||||||
SQLResult choiceResult = DB.World.Query("SELECT ChoiceId, UiTextureKitId, SoundKitId, CloseSoundKitId, Duration, Question, PendingChoiceText, HideWarboardHeader, KeepOpenAfterChoice FROM playerchoice");
|
// 0 1 2 3 4 5 6
|
||||||
|
SQLResult choiceResult = DB.World.Query("SELECT ChoiceId, UiTextureKitId, SoundKitId, CloseSoundKitId, Duration, Question, PendingChoiceText, " +
|
||||||
|
//7 8 9 10 11 12 13
|
||||||
|
"InfiniteRange, HideWarboardHeader, KeepOpenAfterChoice, ShowChoicesAsList, ForceDontShowChoicesAsList, MaxResponses, ScriptName FROM playerchoice");
|
||||||
if (choiceResult.IsEmpty())
|
if (choiceResult.IsEmpty())
|
||||||
{
|
{
|
||||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 player choices. DB table `playerchoice` is empty.");
|
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 player choices. DB table `playerchoice` is empty.");
|
||||||
@@ -10174,18 +10177,26 @@ namespace Game
|
|||||||
choice.UiTextureKitId = choiceResult.Read<int>(1);
|
choice.UiTextureKitId = choiceResult.Read<int>(1);
|
||||||
choice.SoundKitId = choiceResult.Read<uint>(2);
|
choice.SoundKitId = choiceResult.Read<uint>(2);
|
||||||
choice.CloseSoundKitId = choiceResult.Read<uint>(3);
|
choice.CloseSoundKitId = choiceResult.Read<uint>(3);
|
||||||
choice.Duration = choiceResult.Read<long>(4);
|
choice.Duration = TimeSpan.FromSeconds(choiceResult.Read<long>(4));
|
||||||
choice.Question = choiceResult.Read<string>(5);
|
choice.Question = choiceResult.Read<string>(5);
|
||||||
choice.PendingChoiceText = choiceResult.Read<string>(6);
|
choice.PendingChoiceText = choiceResult.Read<string>(6);
|
||||||
choice.HideWarboardHeader = choiceResult.Read<bool>(7);
|
choice.InfiniteRange = choiceResult.Read<bool>(7);
|
||||||
choice.KeepOpenAfterChoice = choiceResult.Read<bool>(8);
|
choice.HideWarboardHeader = choiceResult.Read<bool>(8);
|
||||||
|
choice.KeepOpenAfterChoice = choiceResult.Read<bool>(9);
|
||||||
|
choice.ShowChoicesAsList = choiceResult.Read<bool>(10);
|
||||||
|
choice.ForceDontShowChoicesAsList = choiceResult.Read<bool>(11);
|
||||||
|
|
||||||
|
if (!choiceResult.IsNull(12))
|
||||||
|
choice.MaxResponses = choiceResult.Read<uint>(12);
|
||||||
|
|
||||||
|
choice.ScriptId = GetScriptId(choiceResult.Read<string>(13));
|
||||||
|
|
||||||
_playerChoices[choice.ChoiceId] = choice;
|
_playerChoices[choice.ChoiceId] = choice;
|
||||||
|
|
||||||
} while (choiceResult.NextRow());
|
} while (choiceResult.NextRow());
|
||||||
|
|
||||||
// 0 1 2 3 4 5
|
// 0 1 2 3 4 5
|
||||||
SQLResult responses = DB.World.Query("SELECT ChoiceId, ResponseId, ResponseIdentifier, ChoiceArtFileId, Flags, WidgetSetID, " +
|
SQLResult responses = DB.World.Query("SELECT ChoiceId, ResponseId, NULL, ChoiceArtFileId, Flags, WidgetSetID, " +
|
||||||
//6 7 8 9 10 11 12 13 14 15 16
|
//6 7 8 9 10 11 12 13 14 15 16
|
||||||
"UiTextureAtlasElementID, SoundKitID, GroupID, UiTextureKitID, Answer, Header, SubHeader, ButtonTooltip, Description, Confirmation, RewardQuestID " +
|
"UiTextureAtlasElementID, SoundKitID, GroupID, UiTextureKitID, Answer, Header, SubHeader, ButtonTooltip, Description, Confirmation, RewardQuestID " +
|
||||||
"FROM playerchoice_response ORDER BY `Index` ASC");
|
"FROM playerchoice_response ORDER BY `Index` ASC");
|
||||||
@@ -10206,9 +10217,8 @@ namespace Game
|
|||||||
PlayerChoiceResponse response = new();
|
PlayerChoiceResponse response = new();
|
||||||
|
|
||||||
response.ResponseId = responseId;
|
response.ResponseId = responseId;
|
||||||
response.ResponseIdentifier = responses.Read<ushort>(2);
|
|
||||||
response.ChoiceArtFileId = responses.Read<int>(3);
|
response.ChoiceArtFileId = responses.Read<int>(3);
|
||||||
response.Flags = responses.Read<int>(4);
|
response.Flags = (PlayerChoiceResponseFlags)responses.Read<int>(4);
|
||||||
response.WidgetSetID = responses.Read<uint>(5);
|
response.WidgetSetID = responses.Read<uint>(5);
|
||||||
response.UiTextureAtlasElementID = responses.Read<uint>(6);
|
response.UiTextureAtlasElementID = responses.Read<uint>(6);
|
||||||
response.SoundKitID = responses.Read<uint>(7);
|
response.SoundKitID = responses.Read<uint>(7);
|
||||||
@@ -12665,104 +12675,6 @@ namespace Game
|
|||||||
public StringArray Confirmation = new((int)Locale.Total);
|
public StringArray Confirmation = new((int)Locale.Total);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PlayerChoiceResponseRewardItem
|
|
||||||
{
|
|
||||||
public PlayerChoiceResponseRewardItem() { }
|
|
||||||
public PlayerChoiceResponseRewardItem(uint id, List<uint> bonusListIDs, int quantity)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
BonusListIDs = bonusListIDs;
|
|
||||||
Quantity = quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Id;
|
|
||||||
public List<uint> BonusListIDs = new();
|
|
||||||
public int Quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlayerChoiceResponseRewardEntry
|
|
||||||
{
|
|
||||||
public PlayerChoiceResponseRewardEntry(uint id, int quantity)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Quantity = quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint Id;
|
|
||||||
public int Quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlayerChoiceResponseReward
|
|
||||||
{
|
|
||||||
public int TitleId;
|
|
||||||
public int PackageId;
|
|
||||||
public int SkillLineId;
|
|
||||||
public uint SkillPointCount;
|
|
||||||
public uint ArenaPointCount;
|
|
||||||
public uint HonorPointCount;
|
|
||||||
public ulong Money;
|
|
||||||
public uint Xp;
|
|
||||||
|
|
||||||
public List<PlayerChoiceResponseRewardItem> Items = new();
|
|
||||||
public List<PlayerChoiceResponseRewardEntry> Currency = new();
|
|
||||||
public List<PlayerChoiceResponseRewardEntry> Faction = new();
|
|
||||||
public List<PlayerChoiceResponseRewardItem> ItemChoices = new();
|
|
||||||
}
|
|
||||||
|
|
||||||
public struct PlayerChoiceResponseMawPower
|
|
||||||
{
|
|
||||||
public int TypeArtFileID;
|
|
||||||
public int? Rarity;
|
|
||||||
public int SpellID;
|
|
||||||
public int MaxStacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlayerChoiceResponse
|
|
||||||
{
|
|
||||||
public int ResponseId;
|
|
||||||
public ushort ResponseIdentifier;
|
|
||||||
public int ChoiceArtFileId;
|
|
||||||
public int Flags;
|
|
||||||
public uint WidgetSetID;
|
|
||||||
public uint UiTextureAtlasElementID;
|
|
||||||
public uint SoundKitID;
|
|
||||||
public byte GroupID;
|
|
||||||
public int UiTextureKitID;
|
|
||||||
public string Answer;
|
|
||||||
public string Header;
|
|
||||||
public string SubHeader;
|
|
||||||
public string ButtonTooltip;
|
|
||||||
public string Description;
|
|
||||||
public string Confirmation;
|
|
||||||
public PlayerChoiceResponseReward Reward;
|
|
||||||
public uint? RewardQuestID;
|
|
||||||
public PlayerChoiceResponseMawPower? MawPower;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlayerChoice
|
|
||||||
{
|
|
||||||
public int ChoiceId;
|
|
||||||
public int UiTextureKitId;
|
|
||||||
public uint SoundKitId;
|
|
||||||
public uint CloseSoundKitId;
|
|
||||||
public long Duration;
|
|
||||||
public string Question;
|
|
||||||
public string PendingChoiceText;
|
|
||||||
public List<PlayerChoiceResponse> Responses = new();
|
|
||||||
public bool HideWarboardHeader;
|
|
||||||
public bool KeepOpenAfterChoice;
|
|
||||||
|
|
||||||
public PlayerChoiceResponse GetResponse(int responseId)
|
|
||||||
{
|
|
||||||
return Responses.Find(playerChoiceResponse => playerChoiceResponse.ResponseId == responseId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PlayerChoiceResponse GetResponseByIdentifier(int responseIdentifier)
|
|
||||||
{
|
|
||||||
return Responses.Find(playerChoiceResponse => playerChoiceResponse.ResponseIdentifier == responseIdentifier);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ClassAvailability
|
public class ClassAvailability
|
||||||
{
|
{
|
||||||
public byte ClassID;
|
public byte ClassID;
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
// Copyright (c) CypherCore <http://github.com/CypherCore> All rights reserved.
|
||||||
|
// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Game
|
||||||
|
{
|
||||||
|
public class PlayerChoiceResponseRewardItem
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public List<uint> BonusListIDs = new();
|
||||||
|
public int Quantity;
|
||||||
|
|
||||||
|
public PlayerChoiceResponseRewardItem() { }
|
||||||
|
public PlayerChoiceResponseRewardItem(uint id, List<uint> bonusListIDs, int quantity)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
BonusListIDs = bonusListIDs;
|
||||||
|
Quantity = quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerChoiceResponseRewardEntry
|
||||||
|
{
|
||||||
|
public uint Id;
|
||||||
|
public int Quantity;
|
||||||
|
|
||||||
|
public PlayerChoiceResponseRewardEntry(uint id, int quantity)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Quantity = quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerChoiceResponseReward
|
||||||
|
{
|
||||||
|
public int TitleId;
|
||||||
|
public int PackageId;
|
||||||
|
public int SkillLineId;
|
||||||
|
public uint SkillPointCount;
|
||||||
|
public uint ArenaPointCount;
|
||||||
|
public uint HonorPointCount;
|
||||||
|
public ulong Money;
|
||||||
|
public uint Xp;
|
||||||
|
|
||||||
|
public List<PlayerChoiceResponseRewardItem> Items = new();
|
||||||
|
public List<PlayerChoiceResponseRewardEntry> Currency = new();
|
||||||
|
public List<PlayerChoiceResponseRewardEntry> Faction = new();
|
||||||
|
public List<PlayerChoiceResponseRewardItem> ItemChoices = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct PlayerChoiceResponseMawPower
|
||||||
|
{
|
||||||
|
public int TypeArtFileID;
|
||||||
|
public int? Rarity;
|
||||||
|
public int SpellID;
|
||||||
|
public int MaxStacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum PlayerChoiceResponseFlags
|
||||||
|
{
|
||||||
|
None = 0x000,
|
||||||
|
DisabledButton = 0x001, // Disables single button
|
||||||
|
DesaturateArt = 0x002,
|
||||||
|
DisabledOption = 0x004, // Disables the entire group of options
|
||||||
|
ConsolidateWidgets = 0x020,
|
||||||
|
ShowCheckmark = 0x040,
|
||||||
|
HideButtonShowText = 0x080,
|
||||||
|
Selected = 0x100,
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerChoiceResponse
|
||||||
|
{
|
||||||
|
public int ResponseId;
|
||||||
|
public int ChoiceArtFileId;
|
||||||
|
public PlayerChoiceResponseFlags Flags;
|
||||||
|
public uint WidgetSetID;
|
||||||
|
public uint UiTextureAtlasElementID;
|
||||||
|
public uint SoundKitID;
|
||||||
|
public byte GroupID;
|
||||||
|
public int UiTextureKitID;
|
||||||
|
public string Answer;
|
||||||
|
public string Header;
|
||||||
|
public string SubHeader;
|
||||||
|
public string ButtonTooltip;
|
||||||
|
public string Description;
|
||||||
|
public string Confirmation;
|
||||||
|
public PlayerChoiceResponseReward Reward;
|
||||||
|
public uint? RewardQuestID;
|
||||||
|
public PlayerChoiceResponseMawPower? MawPower;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class PlayerChoice
|
||||||
|
{
|
||||||
|
public int ChoiceId;
|
||||||
|
public int UiTextureKitId;
|
||||||
|
public uint SoundKitId;
|
||||||
|
public uint CloseSoundKitId;
|
||||||
|
public TimeSpan Duration;
|
||||||
|
public string Question;
|
||||||
|
public string PendingChoiceText;
|
||||||
|
public List<PlayerChoiceResponse> Responses = new();
|
||||||
|
public bool InfiniteRange;
|
||||||
|
public bool HideWarboardHeader;
|
||||||
|
public bool KeepOpenAfterChoice;
|
||||||
|
public bool ShowChoicesAsList;
|
||||||
|
public bool ForceDontShowChoicesAsList;
|
||||||
|
|
||||||
|
public uint MaxResponses;
|
||||||
|
|
||||||
|
public uint ScriptId;
|
||||||
|
|
||||||
|
public PlayerChoiceResponse GetResponse(int responseId)
|
||||||
|
{
|
||||||
|
return Responses.Find(playerChoiceResponse => playerChoiceResponse.ResponseId == responseId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ namespace Game
|
|||||||
|
|
||||||
_player.PlayerTalkClass.GetInteractionData().Reset();
|
_player.PlayerTalkClass.GetInteractionData().Reset();
|
||||||
_player.PlayerTalkClass.GetInteractionData().SourceGuid = npc.GetGUID();
|
_player.PlayerTalkClass.GetInteractionData().SourceGuid = npc.GetGUID();
|
||||||
_player.PlayerTalkClass.GetInteractionData().TrainerId = trainerId;
|
_player.PlayerTalkClass.GetInteractionData().SetTrainerId(trainerId);
|
||||||
trainer.SendSpells(npc, _player, GetSessionDbLocaleIndex());
|
trainer.SendSpells(npc, _player, GetSessionDbLocaleIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ namespace Game
|
|||||||
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid != packet.TrainerGUID)
|
if (_player.PlayerTalkClass.GetInteractionData().SourceGuid != packet.TrainerGUID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_player.PlayerTalkClass.GetInteractionData().TrainerId != packet.TrainerID)
|
if (_player.PlayerTalkClass.GetInteractionData().GetTrainerId() != packet.TrainerID)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// check present spell in trainer spell list
|
// check present spell in trainer spell list
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using Game.Networking.Packets;
|
|||||||
using Game.DataStorage;
|
using Game.DataStorage;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System;
|
||||||
|
using Game.Misc;
|
||||||
|
|
||||||
namespace Game
|
namespace Game
|
||||||
{
|
{
|
||||||
@@ -738,9 +739,29 @@ namespace Game
|
|||||||
[WorldPacketHandler(ClientOpcodes.ChoiceResponse)]
|
[WorldPacketHandler(ClientOpcodes.ChoiceResponse)]
|
||||||
void HandlePlayerChoiceResponse(ChoiceResponse choiceResponse)
|
void HandlePlayerChoiceResponse(ChoiceResponse choiceResponse)
|
||||||
{
|
{
|
||||||
if (_player.PlayerTalkClass.GetInteractionData().PlayerChoiceId != choiceResponse.ChoiceID)
|
PlayerChoiceData playerChoiceData = _player.PlayerTalkClass.GetInteractionData().GetPlayerChoice();
|
||||||
|
if (playerChoiceData == null)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to respond to invalid player choice {choiceResponse.ChoiceID} (allowed {_player.PlayerTalkClass.GetInteractionData().PlayerChoiceId}) (possible packet-hacking detected)");
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to respond to invalid player choice {choiceResponse.ChoiceID} (none allowed)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerChoiceData.GetChoiceId() != choiceResponse.ChoiceID)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to respond to invalid player choice {choiceResponse.ChoiceID} ({playerChoiceData.GetChoiceId()} allowed)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerChoiceData.GetExpireTime().HasValue && playerChoiceData.GetExpireTime() < GameTime.GetSystemTime())
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to respond to expired player choice {choiceResponse.ChoiceID})");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint? responseId = playerChoiceData.FindIdByClientIdentifier((ushort)choiceResponse.ResponseIdentifier);
|
||||||
|
if (!responseId.HasValue)
|
||||||
|
{
|
||||||
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to select invalid player choice response identifier {choiceResponse.ResponseIdentifier}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,52 +769,21 @@ namespace Game
|
|||||||
if (playerChoice == null)
|
if (playerChoice == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
PlayerChoiceResponse playerChoiceResponse = playerChoice.GetResponseByIdentifier(choiceResponse.ResponseIdentifier);
|
PlayerChoiceResponse playerChoiceResponse = playerChoice.GetResponse((ushort)responseId);
|
||||||
if (playerChoiceResponse == null)
|
if (playerChoiceResponse == null)
|
||||||
{
|
{
|
||||||
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to select invalid player choice response {choiceResponse.ResponseIdentifier} (possible packet-hacking detected)");
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to select invalid player choice response {responseId}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Global.ScriptMgr.OnPlayerChoiceResponse(GetPlayer(), (uint)choiceResponse.ChoiceID, (uint)choiceResponse.ResponseIdentifier);
|
if (playerChoiceResponse.Flags.HasFlag(PlayerChoiceResponseFlags.DisabledButton | PlayerChoiceResponseFlags.DisabledOption | PlayerChoiceResponseFlags.HideButtonShowText))
|
||||||
|
|
||||||
if (playerChoiceResponse.Reward != null)
|
|
||||||
{
|
{
|
||||||
var reward = playerChoiceResponse.Reward;
|
Log.outError(LogFilter.Player, $"Error in CMSG_CHOICE_RESPONSE: {GetPlayerInfo()} tried to select disabled player choice response {responseId}");
|
||||||
if (reward.TitleId != 0)
|
return;
|
||||||
_player.SetTitle(CliDB.CharTitlesStorage.LookupByKey(reward.TitleId), false);
|
|
||||||
|
|
||||||
if (reward.PackageId != 0)
|
|
||||||
_player.RewardQuestPackage((uint)reward.PackageId, ItemContext.None);
|
|
||||||
|
|
||||||
if (reward.SkillLineId != 0 && _player.HasSkill((SkillType)reward.SkillLineId))
|
|
||||||
_player.UpdateSkillPro((uint)reward.SkillLineId, 1000, reward.SkillPointCount);
|
|
||||||
|
|
||||||
if (reward.HonorPointCount != 0)
|
|
||||||
_player.AddHonorXP(reward.HonorPointCount);
|
|
||||||
|
|
||||||
if (reward.Money != 0)
|
|
||||||
_player.ModifyMoney((long)reward.Money, false);
|
|
||||||
|
|
||||||
if (reward.Xp != 0)
|
|
||||||
_player.GiveXP(reward.Xp, null, 0.0f);
|
|
||||||
|
|
||||||
foreach (PlayerChoiceResponseRewardItem item in reward.Items)
|
|
||||||
{
|
|
||||||
List<ItemPosCount> dest = new();
|
|
||||||
if (_player.CanStoreNewItem(ItemConst.NullBag, ItemConst.NullSlot, dest, item.Id, (uint)item.Quantity) == InventoryResult.Ok)
|
|
||||||
{
|
|
||||||
Item newItem = _player.StoreNewItem(dest, item.Id, true, ItemEnchantmentManager.GenerateItemRandomBonusListId(item.Id), null, ItemContext.QuestReward, item.BonusListIDs);
|
|
||||||
_player.SendNewItem(newItem, (uint)item.Quantity, true, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (PlayerChoiceResponseRewardEntry currency in reward.Currency)
|
|
||||||
_player.ModifyCurrency(currency.Id, currency.Quantity);
|
|
||||||
|
|
||||||
foreach (PlayerChoiceResponseRewardEntry faction in reward.Faction)
|
|
||||||
_player.GetReputationMgr().ModifyReputation(CliDB.FactionStorage.LookupByKey(faction.Id), faction.Quantity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Global.ScriptMgr.OnPlayerChoiceResponse(Global.ObjAccessor.GetWorldObject(_player, _player.PlayerTalkClass.GetInteractionData().SourceGuid), _player,
|
||||||
|
playerChoice, playerChoiceResponse, (ushort)choiceResponse.ResponseIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
[WorldPacketHandler(ClientOpcodes.UiMapQuestLinesRequest)]
|
[WorldPacketHandler(ClientOpcodes.UiMapQuestLinesRequest)]
|
||||||
|
|||||||
@@ -912,14 +912,14 @@ namespace Game.Networking.Packets
|
|||||||
_worldPacket.WriteUInt32(SoundKitID);
|
_worldPacket.WriteUInt32(SoundKitID);
|
||||||
_worldPacket.WriteUInt32(CloseUISoundKitID);
|
_worldPacket.WriteUInt32(CloseUISoundKitID);
|
||||||
_worldPacket.WriteUInt8(NumRerolls);
|
_worldPacket.WriteUInt8(NumRerolls);
|
||||||
_worldPacket.WriteInt64(Duration);
|
_worldPacket.WriteInt64(ExpireTime);
|
||||||
_worldPacket.WriteBits(Question.GetByteCount(), 8);
|
_worldPacket.WriteBits(Question.GetByteCount(), 8);
|
||||||
_worldPacket.WriteBits(PendingChoiceText.GetByteCount(), 8);
|
_worldPacket.WriteBits(PendingChoiceText.GetByteCount(), 8);
|
||||||
_worldPacket.WriteBit(InfiniteRange);
|
_worldPacket.WriteBit(InfiniteRange);
|
||||||
_worldPacket.WriteBit(HideWarboardHeader);
|
_worldPacket.WriteBit(HideWarboardHeader);
|
||||||
_worldPacket.WriteBit(KeepOpenAfterChoice);
|
_worldPacket.WriteBit(KeepOpenAfterChoice);
|
||||||
_worldPacket.WriteBit(Unknown_1115_1);
|
_worldPacket.WriteBit(ShowChoicesAsList);
|
||||||
_worldPacket.WriteBit(Unknown_1115_2);
|
_worldPacket.WriteBit(ForceDontShowChoicesAsList);
|
||||||
_worldPacket.FlushBits();
|
_worldPacket.FlushBits();
|
||||||
|
|
||||||
foreach (PlayerChoiceResponse response in Responses)
|
foreach (PlayerChoiceResponse response in Responses)
|
||||||
@@ -935,15 +935,15 @@ namespace Game.Networking.Packets
|
|||||||
public uint SoundKitID;
|
public uint SoundKitID;
|
||||||
public uint CloseUISoundKitID;
|
public uint CloseUISoundKitID;
|
||||||
public byte NumRerolls;
|
public byte NumRerolls;
|
||||||
public long Duration;
|
public long ExpireTime;
|
||||||
public string Question;
|
public string Question;
|
||||||
public string PendingChoiceText;
|
public string PendingChoiceText;
|
||||||
public List<PlayerChoiceResponse> Responses = new();
|
public List<PlayerChoiceResponse> Responses = new();
|
||||||
public bool InfiniteRange;
|
public bool InfiniteRange;
|
||||||
public bool HideWarboardHeader;
|
public bool HideWarboardHeader;
|
||||||
public bool KeepOpenAfterChoice;
|
public bool KeepOpenAfterChoice;
|
||||||
public bool Unknown_1115_1;
|
public bool ShowChoicesAsList;
|
||||||
public bool Unknown_1115_2;
|
public bool ForceDontShowChoicesAsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChoiceResponse : ClientPacket
|
class ChoiceResponse : ClientPacket
|
||||||
@@ -1502,7 +1502,7 @@ namespace Game.Networking.Packets
|
|||||||
public int Unused901_1;
|
public int Unused901_1;
|
||||||
public int TypeArtFileID;
|
public int TypeArtFileID;
|
||||||
public int? Rarity;
|
public int? Rarity;
|
||||||
public int Unused901_2;
|
public int BorderUiTextureAtlasMemberID;
|
||||||
public int SpellID;
|
public int SpellID;
|
||||||
public int MaxStacks;
|
public int MaxStacks;
|
||||||
|
|
||||||
@@ -1510,7 +1510,7 @@ namespace Game.Networking.Packets
|
|||||||
{
|
{
|
||||||
data.WriteInt32(Unused901_1);
|
data.WriteInt32(Unused901_1);
|
||||||
data.WriteInt32(TypeArtFileID);
|
data.WriteInt32(TypeArtFileID);
|
||||||
data.WriteInt32(Unused901_2);
|
data.WriteInt32(BorderUiTextureAtlasMemberID);
|
||||||
data.WriteInt32(SpellID);
|
data.WriteInt32(SpellID);
|
||||||
data.WriteInt32(MaxStacks);
|
data.WriteInt32(MaxStacks);
|
||||||
data.WriteBit(Rarity.HasValue);
|
data.WriteBit(Rarity.HasValue);
|
||||||
|
|||||||
@@ -703,9 +703,6 @@ namespace Game.Scripting
|
|||||||
|
|
||||||
// Called when a player completes a movie
|
// Called when a player completes a movie
|
||||||
public virtual void OnMovieComplete(Player player, uint movieId) { }
|
public virtual void OnMovieComplete(Player player, uint movieId) { }
|
||||||
|
|
||||||
// Called when a player choose a response from a PlayerChoice
|
|
||||||
public virtual void OnPlayerChoiceResponse(Player player, uint choiceId, uint responseId) { }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AccountScript : ScriptObject
|
public class AccountScript : ScriptObject
|
||||||
@@ -892,4 +889,16 @@ namespace Game.Scripting
|
|||||||
// Called when a game event is triggered
|
// Called when a game event is triggered
|
||||||
public virtual void OnTrigger(WorldObject obj, WorldObject invoker, uint eventId) { }
|
public virtual void OnTrigger(WorldObject obj, WorldObject invoker, uint eventId) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PlayerChoiceScript : ScriptObject
|
||||||
|
{
|
||||||
|
public PlayerChoiceScript(string name) : base(name)
|
||||||
|
{
|
||||||
|
Global.ScriptMgr.AddScript(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool IsDatabaseBound() { return true; }
|
||||||
|
|
||||||
|
public virtual void OnResponse(WorldObject obj, Player player, PlayerChoice choice, PlayerChoiceResponse response, ushort clientIdentifier) { }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -915,9 +915,12 @@ namespace Game.Scripting
|
|||||||
{
|
{
|
||||||
ForEach<PlayerScript>(p => p.OnMovieComplete(player, movieId));
|
ForEach<PlayerScript>(p => p.OnMovieComplete(player, movieId));
|
||||||
}
|
}
|
||||||
public void OnPlayerChoiceResponse(Player player, uint choiceId, uint responseId)
|
public void OnPlayerChoiceResponse(WorldObject obj, Player player, PlayerChoice choice, PlayerChoiceResponse response, ushort clientIdentifier)
|
||||||
{
|
{
|
||||||
ForEach<PlayerScript>(p => p.OnPlayerChoiceResponse(player, choiceId, responseId));
|
Cypher.Assert(choice != null);
|
||||||
|
Cypher.Assert(response != null);
|
||||||
|
|
||||||
|
ForEach<PlayerChoiceScript>(p => p.OnResponse(obj, player, choice, response, clientIdentifier));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account
|
// Account
|
||||||
|
|||||||
Reference in New Issue
Block a user