Core: Updated to 10.0.2
Port From (https://github.com/TrinityCore/TrinityCore/commit/e98e1283ea0034baf6be9aa2ffb386eb5582801b)
This commit is contained in:
@@ -106,7 +106,7 @@ namespace Game.Entities
|
||||
DeleteFromDB(trans);
|
||||
|
||||
StringBuilder items = new();
|
||||
for (var i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (var i = 0; i < m_corpseData.Items.GetSize(); ++i)
|
||||
items.Append($"{m_corpseData.Items[i]} ");
|
||||
|
||||
byte index = 0;
|
||||
@@ -187,8 +187,9 @@ namespace Game.Entities
|
||||
SetObjectScale(1.0f);
|
||||
SetDisplayId(field.Read<uint>(5));
|
||||
StringArray items = new(field.Read<string>(6), ' ');
|
||||
for (uint index = 0; index < EquipmentSlot.End; ++index)
|
||||
SetItem(index, uint.Parse(items[(int)index]));
|
||||
if (items.Length == m_corpseData.Items.GetSize())
|
||||
for (uint index = 0; index < m_corpseData.Items.GetSize(); ++index)
|
||||
SetItem(index, uint.Parse(items[(int)index]));
|
||||
|
||||
SetRace(field.Read<byte>(7));
|
||||
SetClass(field.Read<byte>(8));
|
||||
|
||||
@@ -30,47 +30,58 @@ namespace Game.Misc
|
||||
{
|
||||
public class GossipMenu
|
||||
{
|
||||
public uint AddMenuItem(int menuItemId, GossipOptionNpc optionNpc, string message, uint sender, uint action, string boxMessage, uint boxMoney, bool coded = false)
|
||||
public uint AddMenuItem(int gossipOptionId, int orderIndex, GossipOptionNpc optionNpc, string optionText, uint language,
|
||||
GossipOptionFlags flags, int? gossipNpcOptionId, bool boxCoded, uint boxMoney, string boxText, int? spellId,
|
||||
int? overrideIconId, uint sender, uint action)
|
||||
{
|
||||
Cypher.Assert(_menuItems.Count <= SharedConst.MaxGossipMenuItems);
|
||||
|
||||
// Find a free new id - script case
|
||||
if (menuItemId == -1)
|
||||
if (orderIndex == -1)
|
||||
{
|
||||
menuItemId = 0;
|
||||
orderIndex = 0;
|
||||
if (_menuId != 0)
|
||||
{
|
||||
// set baseline menuItemId as higher than whatever exists in db
|
||||
// set baseline orderIndex as higher than whatever exists in db
|
||||
var bounds = Global.ObjectMgr.GetGossipMenuItemsMapBounds(_menuId);
|
||||
var itr = bounds.MaxBy(a => a.OptionId);
|
||||
var itr = bounds.MaxBy(a => a.OrderIndex);
|
||||
if (itr != null)
|
||||
menuItemId = (int)(itr.OptionId + 1);
|
||||
orderIndex = (int)(itr.OrderIndex + 1);
|
||||
}
|
||||
|
||||
if (!_menuItems.Empty())
|
||||
{
|
||||
foreach (var item in _menuItems)
|
||||
foreach (var pair in _menuItems)
|
||||
{
|
||||
if (item.Key > menuItemId)
|
||||
if (pair.Value.OrderIndex > orderIndex)
|
||||
break;
|
||||
|
||||
menuItemId = (int)item.Key + 1;
|
||||
orderIndex = (int)pair.Value.OrderIndex + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GossipMenuItem menuItem = new();
|
||||
if (gossipOptionId == 0)
|
||||
gossipOptionId = -((int)_menuId * 100 + orderIndex);
|
||||
|
||||
GossipMenuItem menuItem = new();
|
||||
menuItem.GossipOptionID = gossipOptionId;
|
||||
menuItem.OrderIndex = (uint)orderIndex;
|
||||
menuItem.OptionNpc = optionNpc;
|
||||
menuItem.Message = message;
|
||||
menuItem.IsCoded = coded;
|
||||
menuItem.OptionText = optionText;
|
||||
menuItem.Language = language;
|
||||
menuItem.Flags = flags;
|
||||
menuItem.GossipNpcOptionID = gossipNpcOptionId;
|
||||
menuItem.BoxCoded = boxCoded;
|
||||
menuItem.BoxMoney = boxMoney;
|
||||
menuItem.BoxText = boxText;
|
||||
menuItem.SpellID = spellId;
|
||||
menuItem.OverrideIconID = overrideIconId;
|
||||
menuItem.Sender = sender;
|
||||
menuItem.Action = action;
|
||||
menuItem.BoxMessage = boxMessage;
|
||||
menuItem.BoxMoney = boxMoney;
|
||||
|
||||
_menuItems[(uint)menuItemId] = menuItem;
|
||||
return (uint)menuItemId;
|
||||
_menuItems.Add((uint)orderIndex, menuItem);
|
||||
return (uint)orderIndex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,79 +100,104 @@ namespace Game.Misc
|
||||
return;
|
||||
|
||||
/// Find the one with the given menu item id.
|
||||
var gossipMenuItems = bounds.Find(menuItem => menuItem.OptionId == menuItemId);
|
||||
var gossipMenuItems = bounds.Find(menuItem => menuItem.OrderIndex == menuItemId);
|
||||
if (gossipMenuItems == null)
|
||||
return;
|
||||
|
||||
AddMenuItem(gossipMenuItems, sender, action);
|
||||
}
|
||||
|
||||
public void AddMenuItem(GossipMenuItems menuItem, uint sender, uint action)
|
||||
{
|
||||
// Store texts for localization.
|
||||
string strOptionText, strBoxText;
|
||||
BroadcastTextRecord optionBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(gossipMenuItems.OptionBroadcastTextId);
|
||||
BroadcastTextRecord boxBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(gossipMenuItems.BoxBroadcastTextId);
|
||||
BroadcastTextRecord optionBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(menuItem.OptionBroadcastTextId);
|
||||
BroadcastTextRecord boxBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(menuItem.BoxBroadcastTextId);
|
||||
|
||||
// OptionText
|
||||
if (optionBroadcastText != null)
|
||||
strOptionText = Global.DB2Mgr.GetBroadcastTextValue(optionBroadcastText, GetLocale());
|
||||
else
|
||||
strOptionText = gossipMenuItems.OptionText;
|
||||
{
|
||||
strOptionText = menuItem.OptionText;
|
||||
|
||||
/// Find localizations from database.
|
||||
if (GetLocale() != Locale.enUS)
|
||||
{
|
||||
GossipMenuItemsLocale gossipMenuLocale = Global.ObjectMgr.GetGossipMenuItemsLocale(menuItem.MenuID, menuItem.OrderIndex);
|
||||
if (gossipMenuLocale != null)
|
||||
ObjectManager.GetLocaleString(gossipMenuLocale.OptionText, GetLocale(), ref strOptionText);
|
||||
}
|
||||
}
|
||||
|
||||
// BoxText
|
||||
if (boxBroadcastText != null)
|
||||
strBoxText = Global.DB2Mgr.GetBroadcastTextValue(boxBroadcastText, GetLocale());
|
||||
else
|
||||
strBoxText = gossipMenuItems.BoxText;
|
||||
|
||||
// Check need of localization.
|
||||
if (boxBroadcastText == null)
|
||||
{
|
||||
strBoxText = menuItem.BoxText;
|
||||
|
||||
// Find localizations from database.
|
||||
GossipMenuItemsLocale gossipMenuLocale = Global.ObjectMgr.GetGossipMenuItemsLocale(menuId, menuItemId);
|
||||
if (gossipMenuLocale != null)
|
||||
ObjectManager.GetLocaleString(gossipMenuLocale.BoxText, GetLocale(), ref strBoxText);
|
||||
if (GetLocale() != Locale.enUS)
|
||||
{
|
||||
GossipMenuItemsLocale gossipMenuLocale = Global.ObjectMgr.GetGossipMenuItemsLocale(menuItem.MenuID, menuItem.OrderIndex);
|
||||
if (gossipMenuLocale != null)
|
||||
ObjectManager.GetLocaleString(gossipMenuLocale.BoxText, GetLocale(), ref strBoxText);
|
||||
}
|
||||
}
|
||||
|
||||
// Add menu item with existing method. Menu item id -1 is also used in ADD_GOSSIP_ITEM macro.
|
||||
AddMenuItem((int)gossipMenuItems.OptionId, gossipMenuItems.OptionNpc, strOptionText, sender, action, strBoxText, gossipMenuItems.BoxMoney, gossipMenuItems.BoxCoded);
|
||||
AddGossipMenuItemData(gossipMenuItems.OptionId, gossipMenuItems.ActionMenuId, gossipMenuItems.ActionPoiId);
|
||||
AddMenuItem(menuItem.GossipOptionID, (int)menuItem.OrderIndex, menuItem.OptionNpc, strOptionText, menuItem.Language, menuItem.Flags,
|
||||
menuItem.GossipNpcOptionID, menuItem.BoxCoded, menuItem.BoxMoney, strBoxText, menuItem.SpellID, (int)menuItem.OverrideIconID, sender, action);
|
||||
AddGossipMenuItemData(menuItem.OrderIndex, menuItem.ActionMenuID, menuItem.ActionPoiID);
|
||||
}
|
||||
|
||||
public void AddGossipMenuItemData(uint menuItemId, uint gossipActionMenuId, uint gossipActionPoi)
|
||||
{
|
||||
GossipMenuItemData itemData = new();
|
||||
|
||||
itemData.GossipActionMenuId = gossipActionMenuId;
|
||||
itemData.GossipActionPoi = gossipActionPoi;
|
||||
|
||||
_menuItemData[menuItemId] = itemData;
|
||||
GossipMenuItem menuItem = _menuItems[menuItemId];
|
||||
menuItem.ActionMenuID = gossipActionMenuId;
|
||||
menuItem.ActionPoiID = gossipActionPoi;
|
||||
}
|
||||
|
||||
public uint GetMenuItemSender(uint menuItemId)
|
||||
public GossipMenuItem GetItem(int gossipOptionId)
|
||||
{
|
||||
if (_menuItems.ContainsKey(menuItemId))
|
||||
return _menuItems.LookupByKey(menuItemId).Sender;
|
||||
else
|
||||
return 0;
|
||||
return _menuItems.Values.FirstOrDefault(item => item.GossipOptionID == gossipOptionId);
|
||||
}
|
||||
|
||||
public uint GetMenuItemAction(uint menuItemId)
|
||||
GossipMenuItem GetItemByIndex(uint orderIndex)
|
||||
{
|
||||
if (_menuItems.ContainsKey(menuItemId))
|
||||
return _menuItems.LookupByKey(menuItemId).Action;
|
||||
else
|
||||
return 0;
|
||||
return _menuItems.LookupByKey(orderIndex);
|
||||
}
|
||||
|
||||
public bool IsMenuItemCoded(uint menuItemId)
|
||||
public uint GetMenuItemSender(uint orderIndex)
|
||||
{
|
||||
if (_menuItems.ContainsKey(menuItemId))
|
||||
return _menuItems.LookupByKey(menuItemId).IsCoded;
|
||||
else
|
||||
return false;
|
||||
GossipMenuItem item = GetItemByIndex(orderIndex);
|
||||
if (item != null)
|
||||
return item.Sender;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint GetMenuItemAction(uint orderIndex)
|
||||
{
|
||||
GossipMenuItem item = GetItemByIndex(orderIndex);
|
||||
if (item != null)
|
||||
return item.Action;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool IsMenuItemCoded(uint orderIndex)
|
||||
{
|
||||
GossipMenuItem item = GetItemByIndex(orderIndex);
|
||||
if (item != null)
|
||||
return item.BoxCoded;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void ClearMenu()
|
||||
{
|
||||
_menuItems.Clear();
|
||||
_menuItemData.Clear();
|
||||
}
|
||||
|
||||
public void SetMenuId(uint menu_id) { _menuId = menu_id; }
|
||||
@@ -179,23 +215,12 @@ namespace Game.Misc
|
||||
return _menuItems.Empty();
|
||||
}
|
||||
|
||||
public GossipMenuItem GetItem(uint id)
|
||||
{
|
||||
return _menuItems.LookupByKey(id);
|
||||
}
|
||||
|
||||
public GossipMenuItemData GetItemData(uint indexId)
|
||||
{
|
||||
return _menuItemData.LookupByKey(indexId);
|
||||
}
|
||||
|
||||
public Dictionary<uint, GossipMenuItem> GetMenuItems()
|
||||
public SortedDictionary<uint, GossipMenuItem> GetMenuItems()
|
||||
{
|
||||
return _menuItems;
|
||||
}
|
||||
|
||||
Dictionary<uint, GossipMenuItem> _menuItems = new();
|
||||
Dictionary<uint, GossipMenuItemData> _menuItemData = new();
|
||||
SortedDictionary<uint, GossipMenuItem> _menuItems = new();
|
||||
uint _menuId;
|
||||
Locale _locale;
|
||||
}
|
||||
@@ -245,18 +270,21 @@ namespace Game.Misc
|
||||
if (text != null)
|
||||
packet.TextID = (int)text.Data.SelectRandomElementByWeight(data => data.Probability).BroadcastTextID;
|
||||
|
||||
foreach (var pair in _gossipMenu.GetMenuItems())
|
||||
foreach (var (index, item) in _gossipMenu.GetMenuItems())
|
||||
{
|
||||
ClientGossipOptions opt = new();
|
||||
GossipMenuItem item = pair.Value;
|
||||
opt.ClientOption = (int)pair.Key;
|
||||
opt.GossipOptionID = item.GossipOptionID;
|
||||
opt.OptionNPC = item.OptionNpc;
|
||||
opt.OptionFlags = (byte)(item.IsCoded ? 1 : 0); // makes pop up box password
|
||||
opt.OptionFlags = (byte)(item.BoxCoded ? 1 : 0); // makes pop up box password
|
||||
opt.OptionCost = (int)item.BoxMoney; // money required to open menu, 2.0.3
|
||||
opt.OptionLanguage = item.Language;
|
||||
opt.Text = item.Message; // text for gossip item
|
||||
opt.Confirm = item.BoxMessage; // accept text (related to money) pop up box, 2.0.3
|
||||
opt.Flags = item.Flags;
|
||||
opt.OrderIndex = (int)item.OrderIndex;
|
||||
opt.Text = item.OptionText; // text for gossip item
|
||||
opt.Confirm = item.BoxText; // accept text (related to money) pop up box, 2.0.3
|
||||
opt.Status = GossipOptionStatus.Available;
|
||||
opt.SpellID = item.SpellID;
|
||||
opt.OverrideIconID = item.OverrideIconID;
|
||||
packet.GossipOptions.Add(opt);
|
||||
}
|
||||
|
||||
@@ -404,6 +432,14 @@ namespace Game.Misc
|
||||
packet.PortraitTurnInName = quest.PortraitTurnInName;
|
||||
|
||||
Locale locale = _session.GetSessionDbLocaleIndex();
|
||||
|
||||
packet.ConditionalDescriptionText = quest.ConditionalQuestDescription.Select(text =>
|
||||
{
|
||||
string content = text.Text[(int)Locale.enUS];
|
||||
ObjectManager.GetLocaleString(text.Text, locale, ref content);
|
||||
return new ConditionalQuestText(text.PlayerConditionId, text.QuestgiverCreatureId, content);
|
||||
}).ToList();
|
||||
|
||||
if (locale != Locale.enUS)
|
||||
{
|
||||
QuestTemplateLocale localeData = Global.ObjectMgr.GetQuestLocale(quest.Id);
|
||||
@@ -432,6 +468,7 @@ namespace Game.Misc
|
||||
packet.DisplayPopup = displayPopup;
|
||||
packet.QuestFlags[0] = (uint)(quest.Flags & (WorldConfig.GetBoolValue(WorldCfg.QuestIgnoreAutoAccept) ? ~QuestFlags.AutoAccept : ~QuestFlags.None));
|
||||
packet.QuestFlags[1] = (uint)quest.FlagsEx;
|
||||
packet.QuestFlags[2] = (uint)quest.FlagsEx2;
|
||||
packet.SuggestedPartyMembers = quest.SuggestedPlayers;
|
||||
|
||||
// RewardSpell can teach multiple spells in trigger spell effects. But not all effects must be SPELL_EFFECT_LEARN_SPELL. See example spell 33950
|
||||
@@ -488,6 +525,14 @@ namespace Game.Misc
|
||||
packet.PortraitTurnInName = quest.PortraitTurnInName;
|
||||
|
||||
Locale locale = _session.GetSessionDbLocaleIndex();
|
||||
|
||||
packet.ConditionalRewardText = quest.ConditionalOfferRewardText.Select(text =>
|
||||
{
|
||||
string content = text.Text[(int)Locale.enUS];
|
||||
ObjectManager.GetLocaleString(text.Text, locale, ref content);
|
||||
return new ConditionalQuestText(text.PlayerConditionId, text.QuestgiverCreatureId, content);
|
||||
}).ToList();
|
||||
|
||||
if (locale != Locale.enUS)
|
||||
{
|
||||
QuestTemplateLocale localeData = Global.ObjectMgr.GetQuestLocale(quest.Id);
|
||||
@@ -513,7 +558,10 @@ namespace Game.Misc
|
||||
// Is there a better way? what about game objects?
|
||||
Creature creature = ObjectAccessor.GetCreature(_session.GetPlayer(), npcGUID);
|
||||
if (creature)
|
||||
{
|
||||
packet.QuestGiverCreatureID = creature.GetEntry();
|
||||
offer.QuestGiverCreatureID = creature.GetCreatureTemplate().Entry;
|
||||
}
|
||||
|
||||
offer.QuestID = quest.Id;
|
||||
offer.AutoLaunched = autoLaunched;
|
||||
@@ -524,6 +572,7 @@ namespace Game.Misc
|
||||
|
||||
offer.QuestFlags[0] = (uint)quest.Flags;
|
||||
offer.QuestFlags[1] = (uint)quest.FlagsEx;
|
||||
offer.QuestFlags[2] = (uint)quest.FlagsEx2;
|
||||
|
||||
packet.PortraitTurnIn = quest.QuestTurnInPortrait;
|
||||
packet.PortraitGiver = quest.QuestGiverPortrait;
|
||||
@@ -553,6 +602,13 @@ namespace Game.Misc
|
||||
packet.CompletionText = quest.RequestItemsText;
|
||||
|
||||
Locale locale = _session.GetSessionDbLocaleIndex();
|
||||
packet.ConditionalCompletionText = quest.ConditionalRequestItemsText.Select(text =>
|
||||
{
|
||||
string content = text.Text[(int)Locale.enUS];
|
||||
ObjectManager.GetLocaleString(text.Text, locale, ref content);
|
||||
return new ConditionalQuestText(text.PlayerConditionId, text.QuestgiverCreatureId, content);
|
||||
}).ToList();
|
||||
|
||||
if (locale != Locale.enUS)
|
||||
{
|
||||
QuestTemplateLocale localeData = Global.ObjectMgr.GetQuestLocale(quest.Id);
|
||||
@@ -586,6 +642,7 @@ namespace Game.Misc
|
||||
|
||||
packet.QuestFlags[0] = (uint)quest.Flags;
|
||||
packet.QuestFlags[1] = (uint)quest.FlagsEx;
|
||||
packet.QuestFlags[2] = (uint)quest.FlagsEx2;
|
||||
packet.SuggestPartyMembers = quest.SuggestedPlayers;
|
||||
|
||||
// incomplete: FD
|
||||
@@ -687,20 +744,26 @@ namespace Game.Misc
|
||||
|
||||
public class GossipMenuItem
|
||||
{
|
||||
public int GossipOptionID;
|
||||
public uint OrderIndex;
|
||||
public GossipOptionNpc OptionNpc;
|
||||
public bool IsCoded;
|
||||
public string Message;
|
||||
public string OptionText;
|
||||
public uint Language;
|
||||
public GossipOptionFlags Flags;
|
||||
public int? GossipNpcOptionID;
|
||||
public bool BoxCoded;
|
||||
public uint BoxMoney;
|
||||
public string BoxText;
|
||||
public int? SpellID;
|
||||
public int? OverrideIconID;
|
||||
|
||||
// action data
|
||||
public uint ActionMenuID;
|
||||
public uint ActionPoiID;
|
||||
|
||||
// additional scripting identifiers
|
||||
public uint Sender;
|
||||
public uint Action;
|
||||
public string BoxMessage;
|
||||
public uint BoxMoney;
|
||||
public uint Language;
|
||||
}
|
||||
|
||||
public class GossipMenuItemData
|
||||
{
|
||||
public uint GossipActionMenuId; // MenuId of the gossip triggered by this action
|
||||
public uint GossipActionPoi;
|
||||
}
|
||||
|
||||
public struct NpcTextData
|
||||
@@ -721,18 +784,23 @@ namespace Game.Misc
|
||||
|
||||
public class GossipMenuItems
|
||||
{
|
||||
public uint MenuId;
|
||||
public uint OptionId;
|
||||
public uint MenuID;
|
||||
public int GossipOptionID;
|
||||
public uint OrderIndex;
|
||||
public GossipOptionNpc OptionNpc;
|
||||
public string OptionText;
|
||||
public uint OptionBroadcastTextId;
|
||||
public uint Language;
|
||||
public uint ActionMenuId;
|
||||
public uint ActionPoiId;
|
||||
public GossipOptionFlags Flags;
|
||||
public uint ActionMenuID;
|
||||
public uint ActionPoiID;
|
||||
public int? GossipNpcOptionID;
|
||||
public bool BoxCoded;
|
||||
public uint BoxMoney;
|
||||
public string BoxText;
|
||||
public uint BoxBroadcastTextId;
|
||||
public int? SpellID;
|
||||
public int? OverrideIconID;
|
||||
public List<Condition> Conditions = new();
|
||||
}
|
||||
|
||||
@@ -741,11 +809,6 @@ namespace Game.Misc
|
||||
public int FriendshipFactionID;
|
||||
}
|
||||
|
||||
public class GossipMenuItemAddon
|
||||
{
|
||||
public int? GarrTalentTreeID;
|
||||
}
|
||||
|
||||
public class PointOfInterest
|
||||
{
|
||||
public uint Id;
|
||||
|
||||
@@ -2422,8 +2422,9 @@ namespace Game.Entities
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
OpenHeartForge openHeartForge = new();
|
||||
openHeartForge.ForgeGUID = GetGUID();
|
||||
GameObjectInteraction openHeartForge = new();
|
||||
openHeartForge.ObjectGUID = GetGUID();
|
||||
openHeartForge.InteractionType = PlayerInteractionType.AzeriteForge;
|
||||
player.SendPacket(openHeartForge);
|
||||
break;
|
||||
}
|
||||
@@ -2438,9 +2439,25 @@ namespace Game.Entities
|
||||
if (!player)
|
||||
return;
|
||||
|
||||
GameObjectUILink gameObjectUILink = new();
|
||||
GameObjectInteraction gameObjectUILink = new();
|
||||
gameObjectUILink.ObjectGUID = GetGUID();
|
||||
gameObjectUILink.UILink = (int)GetGoInfo().UILink.UILinkType;
|
||||
switch (GetGoInfo().UILink.UILinkType)
|
||||
{
|
||||
case 0:
|
||||
gameObjectUILink.InteractionType = PlayerInteractionType.AdventureJournal;
|
||||
break;
|
||||
case 1:
|
||||
gameObjectUILink.InteractionType = PlayerInteractionType.ObliterumForge;
|
||||
break;
|
||||
case 2:
|
||||
gameObjectUILink.InteractionType = PlayerInteractionType.ScrappingMachine;
|
||||
break;
|
||||
case 3:
|
||||
gameObjectUILink.InteractionType = PlayerInteractionType.ItemInteraction;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
player.SendPacket(gameObjectUILink);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -231,6 +231,9 @@ namespace Game.Entities
|
||||
[FieldOffset(68)]
|
||||
public clientmodel ClientModel;
|
||||
|
||||
[FieldOffset(68)]
|
||||
public craftingTable CraftingTable;
|
||||
|
||||
[FieldOffset(68)]
|
||||
public raw Raw;
|
||||
|
||||
@@ -768,6 +771,7 @@ namespace Game.Entities
|
||||
public uint InfiniteAOI; // 10 Infinite AOI, enum { false, true, }; Default: false
|
||||
public uint NotLOSBlocking; // 11 Not LOS Blocking, enum { false, true, }; Default: false
|
||||
public uint InteractRadiusOverride; // 12 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
public uint Collisionupdatedelayafteropen; // 13 Collision update delay(ms) after open, int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
}
|
||||
|
||||
public struct button
|
||||
@@ -909,6 +913,13 @@ namespace Game.Entities
|
||||
public uint floatOnWater; // 7 floatOnWater, enum { false, true, }; Default: false
|
||||
public uint conditionID1; // 8 conditionID1, References: PlayerCondition, NoValue = 0
|
||||
public uint InteractRadiusOverride; // 9 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
public uint gossipID; // 10 gossipID, References: Gossip, NoValue = 0
|
||||
public uint spellFocusType2; // 11 spellFocusType 2, References: SpellFocusObject, NoValue = 0
|
||||
public uint spellFocusType3; // 12 spellFocusType 3, References: SpellFocusObject, NoValue = 0
|
||||
public uint spellFocusType4; // 13 spellFocusType 4, References: SpellFocusObject, NoValue = 0
|
||||
public uint Profession; // 14 Profession, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing
|
||||
public uint Profession2; // 15 Profession 2, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing
|
||||
public uint Profession3; // 16 Profession 3, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing
|
||||
}
|
||||
|
||||
public struct text
|
||||
@@ -1179,7 +1190,7 @@ namespace Game.Entities
|
||||
|
||||
public struct dungeonDifficulty
|
||||
{
|
||||
public uint InstanceType; // 0 Instance Type, enum { Not Instanced, Party Dungeon, Raid Dungeon, PVP Battlefield, Arena Battlefield, Scenario, }; Default: Party Dungeon
|
||||
public uint InstanceType; // 0 Instance Type, enum { Not Instanced, Party Dungeon, Raid Dungeon, PVP Battlefield, Arena Battlefield, Scenario, WoWLabs }; Default: Party Dungeon
|
||||
public uint DifficultyNormal; // 1 Difficulty Normal, References: animationdata, NoValue = 0
|
||||
public uint DifficultyHeroic; // 2 Difficulty Heroic, References: animationdata, NoValue = 0
|
||||
public uint DifficultyEpic; // 3 Difficulty Epic, References: animationdata, NoValue = 0
|
||||
@@ -1199,6 +1210,7 @@ namespace Game.Entities
|
||||
public int HeightOffset; // 1 Height Offset (inches), int, Min value: -100, Max value: 100, Default value: 0
|
||||
public uint SitAnimKit; // 2 Sit Anim Kit, References: AnimKit, NoValue = 0
|
||||
public uint InteractRadiusOverride; // 3 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
public uint CustomizationScope; // 4 Customization Scope, int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
}
|
||||
|
||||
public struct destructiblebuilding
|
||||
@@ -1490,6 +1502,7 @@ namespace Game.Entities
|
||||
public uint WhenAvailable; // 0 When Available, References: GameObjectDisplayInfo, NoValue = 0
|
||||
public uint open; // 1 open, References: Lock_, NoValue = 0
|
||||
public uint InteractRadiusOverride; // 2 Interact Radius Override (in hundredths), int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
public uint ExpansionLevel; // 3 Expansion Level, int, Min value: 0, Max value: 2147483647, Default value: 0
|
||||
}
|
||||
|
||||
public struct clientmodel
|
||||
@@ -1499,6 +1512,11 @@ namespace Game.Entities
|
||||
public uint InfiniteAOI; // 2 Infinite AOI, enum { false, true, }; Default: false
|
||||
public uint TrueInfiniteAOI; // 3 True Infinite AOI (programmer only!), enum { false, true, }; Default: false
|
||||
}
|
||||
|
||||
public struct craftingTable
|
||||
{
|
||||
public uint Profession; // 0 Profession, enum { First Aid, Blacksmithing, Leatherworking, Alchemy, Herbalism, Cooking, Mining, Tailoring, Engineering, Enchanting, Fishing, Skinning, Jewelcrafting, Inscription, Archaeology, }; Default: Blacksmithing
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
|
||||
@@ -147,7 +147,7 @@ namespace Game.Entities
|
||||
SetUpdateFieldValue(ref m_values.ModifyValue(m_azeriteEmpoweredItemData).ModifyValue(m_azeriteEmpoweredItemData.Selections, i), 0);
|
||||
|
||||
_bonusData = new BonusData(GetTemplate());
|
||||
foreach (uint bonusListID in (List<uint>)m_itemData.BonusListIDs)
|
||||
foreach (uint bonusListID in GetBonusListIDs())
|
||||
_bonusData.AddBonusList(bonusListID);
|
||||
}
|
||||
|
||||
|
||||
@@ -187,7 +187,7 @@ namespace Game.Entities
|
||||
|
||||
ss.Clear();
|
||||
|
||||
foreach (int bonusListID in (List<uint>)m_itemData.BonusListIDs)
|
||||
foreach (int bonusListID in GetBonusListIDs())
|
||||
ss.Append($"{bonusListID} ");
|
||||
|
||||
stmt.AddValue(++index, ss.ToString());
|
||||
@@ -802,9 +802,13 @@ namespace Game.Entities
|
||||
return m_container != null ? m_container.GetSlot() : InventorySlots.Bag0;
|
||||
}
|
||||
|
||||
public bool IsEquipped() { return !IsInBag() && m_slot < EquipmentSlot.End; }
|
||||
public bool IsEquipped()
|
||||
{
|
||||
return !IsInBag() && ((m_slot >= EquipmentSlot.Start && m_slot < EquipmentSlot.End)
|
||||
|| (m_slot >= ProfessionSlots.Start && m_slot < ProfessionSlots.End));
|
||||
}
|
||||
|
||||
public bool CanBeTraded(bool mail = false, bool trade = false)
|
||||
public bool CanBeTraded(bool mail = false, bool trade = false)
|
||||
{
|
||||
if (m_lootGenerated)
|
||||
return false;
|
||||
@@ -1603,7 +1607,13 @@ namespace Game.Entities
|
||||
-1, // INVTYPE_THROWN
|
||||
EquipmentSlot.MainHand, // INVTYPE_RANGEDRIGHT
|
||||
-1, // INVTYPE_QUIVER
|
||||
-1 // INVTYPE_RELIC
|
||||
-1, // INVTYPE_RELIC
|
||||
-1, // INVTYPE_PROFESSION_TOOL
|
||||
-1, // INVTYPE_PROFESSION_GEAR
|
||||
-1, // INVTYPE_EQUIPABLE_SPELL_OFFENSIVE
|
||||
-1, // INVTYPE_EQUIPABLE_SPELL_UTILITY
|
||||
-1, // INVTYPE_EQUIPABLE_SPELL_DEFENSIVE
|
||||
-1 // INVTYPE_EQUIPABLE_SPELL_MOBILITY
|
||||
};
|
||||
|
||||
public static bool CanTransmogrifyItemWithItem(Item item, ItemModifiedAppearanceRecord itemModifiedAppearance)
|
||||
@@ -2075,17 +2085,22 @@ namespace Game.Entities
|
||||
return 0;
|
||||
}
|
||||
|
||||
public List<uint> GetBonusListIDs() { return m_itemData.ItemBonusKey.GetValue().BonusListIDs; }
|
||||
|
||||
public void AddBonuses(uint bonusListID)
|
||||
{
|
||||
var bonusListIDs = (List<uint>)m_itemData.BonusListIDs;
|
||||
var bonusListIDs = GetBonusListIDs();
|
||||
if (bonusListIDs.Contains(bonusListID))
|
||||
return;
|
||||
|
||||
var bonuses = Global.DB2Mgr.GetItemBonusList(bonusListID);
|
||||
if (bonuses != null)
|
||||
{
|
||||
bonusListIDs.Add(bonusListID);
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.BonusListIDs), bonusListIDs);
|
||||
ItemBonusKey itemBonusKey = new();
|
||||
itemBonusKey.ItemID = GetEntry();
|
||||
itemBonusKey.BonusListIDs = GetBonusListIDs();
|
||||
itemBonusKey.BonusListIDs.Add(bonusListID);
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemBonusKey), itemBonusKey);
|
||||
foreach (ItemBonusRecord bonus in bonuses)
|
||||
_bonusData.AddBonus(bonus.BonusType, bonus.Value);
|
||||
|
||||
@@ -2098,9 +2113,12 @@ namespace Game.Entities
|
||||
if (bonusListIDs == null)
|
||||
bonusListIDs = new List<uint>();
|
||||
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.BonusListIDs), bonusListIDs);
|
||||
ItemBonusKey itemBonusKey = new();
|
||||
itemBonusKey.ItemID = GetEntry();
|
||||
itemBonusKey.BonusListIDs = bonusListIDs;
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemBonusKey), itemBonusKey);
|
||||
|
||||
foreach (uint bonusListID in (List<uint>)m_itemData.BonusListIDs)
|
||||
foreach (uint bonusListID in GetBonusListIDs())
|
||||
_bonusData.AddBonusList(bonusListID);
|
||||
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemAppearanceModID), (byte)_bonusData.AppearanceModID);
|
||||
@@ -2108,7 +2126,9 @@ namespace Game.Entities
|
||||
|
||||
public void ClearBonuses()
|
||||
{
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.BonusListIDs), new List<uint>());
|
||||
ItemBonusKey itemBonusKey = new();
|
||||
itemBonusKey.ItemID = GetEntry();
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemBonusKey), itemBonusKey);
|
||||
_bonusData = new BonusData(GetTemplate());
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_itemData).ModifyValue(m_itemData.ItemAppearanceModID), (byte)_bonusData.AppearanceModID);
|
||||
}
|
||||
@@ -2721,6 +2741,8 @@ namespace Game.Entities
|
||||
if (!pProto.GetBagFamily().HasAnyFlag(BagFamilyMask.CookingSupp))
|
||||
return false;
|
||||
return true;
|
||||
case ItemSubClassContainer.ReagentContainer:
|
||||
return pProto.IsCraftingReagent();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,29 @@ namespace Game.Entities
|
||||
T GetValue();
|
||||
}
|
||||
|
||||
public class UpdateFieldString : IUpdateField<string>
|
||||
{
|
||||
public string _value;
|
||||
public int BlockBit;
|
||||
public int Bit;
|
||||
|
||||
public UpdateFieldString(int blockBit, int bit)
|
||||
{
|
||||
BlockBit = blockBit;
|
||||
Bit = bit;
|
||||
_value = "";
|
||||
}
|
||||
|
||||
public static implicit operator string(UpdateFieldString updateField)
|
||||
{
|
||||
return updateField._value;
|
||||
}
|
||||
|
||||
public void SetValue(string value) { _value = value; }
|
||||
|
||||
public string GetValue() { return _value; }
|
||||
}
|
||||
|
||||
public class UpdateField<T> : IUpdateField<T> where T : new()
|
||||
{
|
||||
public T _value;
|
||||
@@ -380,6 +403,8 @@ namespace Game.Entities
|
||||
((IHasChangesMask)updateField._value).ClearChangesMask();
|
||||
}
|
||||
|
||||
public void ClearChangesMask(UpdateFieldString updateField) { }
|
||||
|
||||
public void ClearChangesMask<U>(OptionalUpdateField<U> updateField) where U : new()
|
||||
{
|
||||
if (typeof(IHasChangesMask).IsAssignableFrom(typeof(U)) && updateField.HasValue())
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -278,6 +278,7 @@ namespace Game.Entities
|
||||
bool HasFall = HasFallDirection || unit.m_movementInfo.jump.fallTime != 0;
|
||||
bool HasSpline = unit.IsSplineEnabled();
|
||||
bool HasInertia = unit.m_movementInfo.inertia.HasValue;
|
||||
bool HasAdvFlying = unit.m_movementInfo.advFlying.HasValue;
|
||||
|
||||
data.WritePackedGuid(GetGUID()); // MoverGUID
|
||||
|
||||
@@ -312,11 +313,17 @@ namespace Game.Entities
|
||||
|
||||
if (HasInertia)
|
||||
{
|
||||
data.WritePackedGuid(unit.m_movementInfo.inertia.Value.guid);
|
||||
data.WriteInt32(unit.m_movementInfo.inertia.Value.id);
|
||||
data.WriteXYZ(unit.m_movementInfo.inertia.Value.force);
|
||||
data.WriteUInt32(unit.m_movementInfo.inertia.Value.lifetime);
|
||||
}
|
||||
|
||||
if (HasAdvFlying)
|
||||
{
|
||||
data.WriteFloat(unit.m_movementInfo.advFlying.Value.forwardVelocity);
|
||||
data.WriteFloat(unit.m_movementInfo.advFlying.Value.upVelocity);
|
||||
}
|
||||
|
||||
if (HasFall)
|
||||
{
|
||||
data.WriteUInt32(unit.m_movementInfo.jump.fallTime); // Time
|
||||
@@ -352,6 +359,24 @@ namespace Game.Entities
|
||||
data.WriteFloat(1.0f); // MovementForcesModMagnitude
|
||||
}
|
||||
|
||||
data.WriteFloat(2.0f); // advFlyingAirFriction
|
||||
data.WriteFloat(65.0f); // advFlyingMaxVel
|
||||
data.WriteFloat(1.0f); // advFlyingLiftCoefficient
|
||||
data.WriteFloat(3.0f); // advFlyingDoubleJumpVelMod
|
||||
data.WriteFloat(10.0f); // advFlyingGlideStartMinHeight
|
||||
data.WriteFloat(100.0f); // advFlyingAddImpulseMaxSpeed
|
||||
data.WriteFloat(90.0f); // advFlyingMinBankingRate
|
||||
data.WriteFloat(140.0f); // advFlyingMaxBankingRate
|
||||
data.WriteFloat(180.0f); // advFlyingMinPitchingRateDown
|
||||
data.WriteFloat(360.0f); // advFlyingMaxPitchingRateDown
|
||||
data.WriteFloat(90.0f); // advFlyingMinPitchingRateUp
|
||||
data.WriteFloat(270.0f); // advFlyingMaxPitchingRateUp
|
||||
data.WriteFloat(30.0f); // advFlyingMinTurnVelocityThreshold
|
||||
data.WriteFloat(80.0f); // advFlyingMaxTurnVelocityThreshold
|
||||
data.WriteFloat(2.75f); // advFlyingSurfaceFriction
|
||||
data.WriteFloat(7.0f); // advFlyingOverMaxDeceleration
|
||||
data.WriteFloat(0.4f); // advFlyingLaunchSpeedCoefficient
|
||||
|
||||
data.WriteBit(HasSpline);
|
||||
data.FlushBits();
|
||||
|
||||
@@ -425,6 +450,7 @@ namespace Game.Entities
|
||||
bool hasFaceMovementDir = areaTriggerTemplate != null && areaTriggerTemplate.HasFlag(AreaTriggerFlags.HasFaceMovementDir);
|
||||
bool hasFollowsTerrain = areaTriggerTemplate != null && areaTriggerTemplate.HasFlag(AreaTriggerFlags.HasFollowsTerrain);
|
||||
bool hasUnk1 = areaTriggerTemplate != null && areaTriggerTemplate.HasFlag(AreaTriggerFlags.Unk1);
|
||||
bool hasUnk2 = false;
|
||||
bool hasTargetRollPitchYaw = areaTriggerTemplate != null && areaTriggerTemplate.HasFlag(AreaTriggerFlags.HasTargetRollPitchYaw);
|
||||
bool hasScaleCurveID = createProperties != null && createProperties.ScaleCurveId != 0;
|
||||
bool hasMorphCurveID = createProperties != null && createProperties.MorphCurveId != 0;
|
||||
@@ -435,6 +461,7 @@ namespace Game.Entities
|
||||
bool hasAreaTriggerPolygon = createProperties != null && shape.IsPolygon();
|
||||
bool hasAreaTriggerCylinder = shape.IsCylinder();
|
||||
bool hasDisk = shape.IsDisk();
|
||||
bool hasBoundedPlane = shape.IsBoudedPlane();
|
||||
bool hasAreaTriggerSpline = areaTrigger.HasSplines();
|
||||
bool hasOrbit = areaTrigger.HasOrbit();
|
||||
bool hasMovementScript = false;
|
||||
@@ -445,6 +472,7 @@ namespace Game.Entities
|
||||
data.WriteBit(hasFaceMovementDir);
|
||||
data.WriteBit(hasFollowsTerrain);
|
||||
data.WriteBit(hasUnk1);
|
||||
data.WriteBit(hasUnk2);
|
||||
data.WriteBit(hasTargetRollPitchYaw);
|
||||
data.WriteBit(hasScaleCurveID);
|
||||
data.WriteBit(hasMorphCurveID);
|
||||
@@ -455,6 +483,7 @@ namespace Game.Entities
|
||||
data.WriteBit(hasAreaTriggerPolygon);
|
||||
data.WriteBit(hasAreaTriggerCylinder);
|
||||
data.WriteBit(hasDisk);
|
||||
data.WriteBit(hasBoundedPlane);
|
||||
data.WriteBit(hasAreaTriggerSpline);
|
||||
data.WriteBit(hasOrbit);
|
||||
data.WriteBit(hasMovementScript);
|
||||
@@ -540,6 +569,17 @@ namespace Game.Entities
|
||||
data.WriteFloat(shape.DiskDatas.LocationZOffsetTarget);
|
||||
}
|
||||
|
||||
if (hasBoundedPlane)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
data.WriteFloat(shape.BoundedPlaneDatas.Extents[0]);
|
||||
data.WriteFloat(shape.BoundedPlaneDatas.Extents[1]);
|
||||
data.WriteFloat(shape.BoundedPlaneDatas.ExtentsTarget[0]);
|
||||
data.WriteFloat(shape.BoundedPlaneDatas.ExtentsTarget[1]);
|
||||
}
|
||||
}
|
||||
|
||||
//if (hasMovementScript)
|
||||
// *data << *areaTrigger.GetMovementScript(); // AreaTriggerMovementScriptInfo
|
||||
|
||||
@@ -3745,6 +3785,7 @@ namespace Game.Entities
|
||||
public Inertia? inertia;
|
||||
public JumpInfo jump;
|
||||
public float stepUpStartElevation { get; set; }
|
||||
public AdvFlying? advFlying;
|
||||
|
||||
public MovementInfo()
|
||||
{
|
||||
@@ -3810,7 +3851,7 @@ namespace Game.Entities
|
||||
}
|
||||
public struct Inertia
|
||||
{
|
||||
public ObjectGuid guid;
|
||||
public int id;
|
||||
public Position force;
|
||||
public uint lifetime;
|
||||
}
|
||||
@@ -3828,6 +3869,12 @@ namespace Game.Entities
|
||||
public float cosAngle;
|
||||
public float xyspeed;
|
||||
}
|
||||
// advflying
|
||||
public struct AdvFlying
|
||||
{
|
||||
public float forwardVelocity;
|
||||
public float upVelocity;
|
||||
}
|
||||
}
|
||||
|
||||
public class MovementForce
|
||||
|
||||
@@ -328,7 +328,7 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
List<uint> bonusListIDs = item.m_itemData.BonusListIDs;
|
||||
List<uint> bonusListIDs = item.GetBonusListIDs();
|
||||
foreach (uint bonusId in bonusListIDs)
|
||||
{
|
||||
if (bonusId != data.bonusId)
|
||||
|
||||
@@ -1363,7 +1363,7 @@ namespace Game.Entities
|
||||
eqSet.Data.AssignedSpecIndex = result.Read<int>(5);
|
||||
eqSet.state = EquipmentSetUpdateState.Unchanged;
|
||||
|
||||
for (int i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (int i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
{
|
||||
ulong guid = result.Read<uint>(6 + i);
|
||||
if (guid != 0)
|
||||
@@ -1400,7 +1400,7 @@ namespace Game.Entities
|
||||
eqSet.Data.IgnoreMask = result.Read<uint>(4);
|
||||
eqSet.state = EquipmentSetUpdateState.Unchanged;
|
||||
|
||||
for (int i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (int i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
eqSet.Data.Appearances[i] = result.Read<int>(5 + i);
|
||||
|
||||
for (int i = 0; i < eqSet.Data.Enchants.Length; ++i)
|
||||
@@ -2298,7 +2298,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(j++, eqSet.Data.IgnoreMask);
|
||||
stmt.AddValue(j++, eqSet.Data.AssignedSpecIndex);
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
stmt.AddValue(j++, eqSet.Data.Pieces[i].GetCounter());
|
||||
|
||||
stmt.AddValue(j++, GetGUID().GetCounter());
|
||||
@@ -2312,7 +2312,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(j++, eqSet.Data.SetIcon);
|
||||
stmt.AddValue(j++, eqSet.Data.IgnoreMask);
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
stmt.AddValue(j++, eqSet.Data.Appearances[i]);
|
||||
|
||||
for (int i = 0; i < eqSet.Data.Enchants.Length; ++i)
|
||||
@@ -2338,7 +2338,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(j++, eqSet.Data.IgnoreMask);
|
||||
stmt.AddValue(j++, eqSet.Data.AssignedSpecIndex);
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
stmt.AddValue(j++, eqSet.Data.Pieces[i].GetCounter());
|
||||
}
|
||||
else
|
||||
@@ -2351,7 +2351,7 @@ namespace Game.Entities
|
||||
stmt.AddValue(j++, eqSet.Data.SetIcon);
|
||||
stmt.AddValue(j++, eqSet.Data.IgnoreMask);
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
stmt.AddValue(j++, eqSet.Data.Appearances[i]);
|
||||
|
||||
for (int i = 0; i < eqSet.Data.Enchants.Length; ++i)
|
||||
@@ -2680,15 +2680,6 @@ namespace Game.Entities
|
||||
|
||||
InitDisplayIds();
|
||||
|
||||
// cleanup inventory related item value fields (its will be filled correctly in _LoadInventory)
|
||||
for (byte slot = EquipmentSlot.Start; slot < EquipmentSlot.End; ++slot)
|
||||
{
|
||||
SetInvSlot(slot, ObjectGuid.Empty);
|
||||
SetVisibleItemSlot(slot, null);
|
||||
|
||||
m_items[slot] = null;
|
||||
}
|
||||
|
||||
//Need to call it to initialize m_team (m_team can be calculated from race)
|
||||
//Other way is to saves m_team into characters table.
|
||||
SetFactionForRace(GetRace());
|
||||
@@ -2982,6 +2973,8 @@ namespace Game.Entities
|
||||
long now = GameTime.GetGameTime();
|
||||
long logoutTime = logout_time;
|
||||
|
||||
SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.LogoutTime), logoutTime);
|
||||
|
||||
// since last logout (in seconds)
|
||||
uint time_diff = (uint)(now - logoutTime);
|
||||
|
||||
@@ -3431,7 +3424,7 @@ namespace Game.Entities
|
||||
|
||||
ss.Clear();
|
||||
// cache equipment...
|
||||
for (byte i = 0; i < InventorySlots.BagEnd; ++i)
|
||||
for (byte i = 0; i < InventorySlots.ReagentBagEnd; ++i)
|
||||
{
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (item != null)
|
||||
@@ -3577,7 +3570,7 @@ namespace Game.Entities
|
||||
|
||||
ss.Clear();
|
||||
// cache equipment...
|
||||
for (byte i = 0; i < InventorySlots.BagEnd; ++i)
|
||||
for (byte i = 0; i < InventorySlots.ReagentBagEnd; ++i)
|
||||
{
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (item != null)
|
||||
|
||||
@@ -294,6 +294,7 @@ namespace Game.Entities
|
||||
public CreatePosition createPosition;
|
||||
public CreatePosition? createPositionNPE;
|
||||
|
||||
public ItemContext itemContext;
|
||||
public List<PlayerCreateInfoItem> item = new();
|
||||
public List<uint> customSpells = new();
|
||||
public List<uint>[] castSpells = new List<uint>[(int)PlayerCreateMode.Max];
|
||||
|
||||
@@ -1219,42 +1219,41 @@ namespace Game.Entities
|
||||
|
||||
return lastItem;
|
||||
}
|
||||
bool StoreNewItemInBestSlots(uint titem_id, uint titem_amount)
|
||||
bool StoreNewItemInBestSlots(uint itemId, uint amount, ItemContext context)
|
||||
{
|
||||
Log.outDebug(LogFilter.Player, "STORAGE: Creating initial item, itemId = {0}, count = {1}", titem_id, titem_amount);
|
||||
Log.outDebug(LogFilter.Player, "STORAGE: Creating initial item, itemId = {0}, count = {1}", itemId, amount);
|
||||
|
||||
ItemContext itemContext = ItemContext.NewCharacter;
|
||||
var bonusListIDs = Global.DB2Mgr.GetDefaultItemBonusTree(titem_id, itemContext);
|
||||
var bonusListIDs = Global.DB2Mgr.GetDefaultItemBonusTree(itemId, context);
|
||||
|
||||
InventoryResult msg;
|
||||
// attempt equip by one
|
||||
while (titem_amount > 0)
|
||||
while (amount > 0)
|
||||
{
|
||||
msg = CanEquipNewItem(ItemConst.NullSlot, out ushort eDest, titem_id, false);
|
||||
msg = CanEquipNewItem(ItemConst.NullSlot, out ushort eDest, itemId, false);
|
||||
if (msg != InventoryResult.Ok)
|
||||
break;
|
||||
|
||||
Item item = EquipNewItem(eDest, titem_id, itemContext, true);
|
||||
Item item = EquipNewItem(eDest, itemId, context, true);
|
||||
item.SetBonuses(bonusListIDs);
|
||||
AutoUnequipOffhandIfNeed();
|
||||
titem_amount--;
|
||||
--amount;
|
||||
}
|
||||
|
||||
if (titem_amount == 0)
|
||||
if (amount == 0)
|
||||
return true; // equipped
|
||||
|
||||
// attempt store
|
||||
List<ItemPosCount> sDest = new();
|
||||
// store in main bag to simplify second pass (special bags can be not equipped yet at this moment)
|
||||
msg = CanStoreNewItem(InventorySlots.Bag0, ItemConst.NullSlot, sDest, titem_id, titem_amount);
|
||||
msg = CanStoreNewItem(InventorySlots.Bag0, ItemConst.NullSlot, sDest, itemId, amount);
|
||||
if (msg == InventoryResult.Ok)
|
||||
{
|
||||
StoreNewItem(sDest, titem_id, true, ItemEnchantmentManager.GenerateItemRandomBonusListId(titem_id), null, itemContext, bonusListIDs);
|
||||
StoreNewItem(sDest, itemId, true, ItemEnchantmentManager.GenerateItemRandomBonusListId(itemId), null, context, bonusListIDs);
|
||||
return true; // stored
|
||||
}
|
||||
|
||||
// item can't be added
|
||||
Log.outError(LogFilter.Player, "STORAGE: Can't equip or store initial item {0} for race {1} class {2}, error msg = {3}", titem_id, GetRace(), GetClass(), msg);
|
||||
Log.outError(LogFilter.Player, "STORAGE: Can't equip or store initial item {0} for race {1} class {2}, error msg = {3}", itemId, GetRace(), GetClass(), msg);
|
||||
return false;
|
||||
}
|
||||
public Item StoreNewItem(List<ItemPosCount> pos, uint itemId, bool update, uint randomBonusListId = 0, List<ObjectGuid> allowedLooters = null, ItemContext context = 0, List<uint> bonusListIDs = null, bool addToCollection = true)
|
||||
@@ -1878,7 +1877,7 @@ namespace Game.Entities
|
||||
pItem.RemoveItemFlag2(ItemFieldFlags2.Equipped);
|
||||
|
||||
// remove item dependent auras and casts (only weapon and armor slots)
|
||||
if (slot < EquipmentSlot.End)
|
||||
if (slot < ProfessionSlots.End)
|
||||
{
|
||||
// update expertise
|
||||
if (slot == EquipmentSlot.MainHand)
|
||||
@@ -2789,10 +2788,18 @@ namespace Game.Entities
|
||||
if (slot < EquipmentSlot.End)
|
||||
return true;
|
||||
|
||||
// profession equipment
|
||||
if (slot >= ProfessionSlots.Start && slot < ProfessionSlots.End)
|
||||
return true;
|
||||
|
||||
// bag equip slots
|
||||
if (slot >= InventorySlots.BagStart && slot < InventorySlots.BagEnd)
|
||||
return true;
|
||||
|
||||
// reagent bag equip slots
|
||||
if (slot >= InventorySlots.ReagentBagStart && slot < InventorySlots.ReagentBagEnd)
|
||||
return true;
|
||||
|
||||
// backpack slots
|
||||
if (slot >= InventorySlots.ItemStart && slot < InventorySlots.ItemStart + GetInventorySlotCount())
|
||||
return true;
|
||||
@@ -3010,7 +3017,7 @@ namespace Game.Entities
|
||||
// if current back slot non-empty search oldest or free
|
||||
if (m_items[slot] != null)
|
||||
{
|
||||
long oldest_time = m_activePlayerData.BuybackTimestamp[0];
|
||||
ulong oldest_time = m_activePlayerData.BuybackTimestamp[0];
|
||||
uint oldest_slot = InventorySlots.BuyBackStart;
|
||||
|
||||
for (byte i = InventorySlots.BuyBackStart + 1; i < InventorySlots.BuyBackEnd; ++i)
|
||||
@@ -3022,7 +3029,7 @@ namespace Game.Entities
|
||||
break;
|
||||
}
|
||||
|
||||
long i_time = m_activePlayerData.BuybackTimestamp[i - InventorySlots.BuyBackStart];
|
||||
ulong i_time = m_activePlayerData.BuybackTimestamp[i - InventorySlots.BuyBackStart];
|
||||
if (oldest_time > i_time)
|
||||
{
|
||||
oldest_time = i_time;
|
||||
@@ -3473,7 +3480,7 @@ namespace Game.Entities
|
||||
DB.Characters.CommitTransaction(trans);
|
||||
}
|
||||
public void SetBuybackPrice(uint slot, uint price) { SetUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.BuybackPrice, (int)slot), price); }
|
||||
public void SetBuybackTimestamp(uint slot, long timestamp) { SetUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.BuybackTimestamp, (int)slot), timestamp); }
|
||||
public void SetBuybackTimestamp(uint slot, ulong timestamp) { SetUpdateFieldValue(ref m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.BuybackTimestamp, (int)slot), timestamp); }
|
||||
|
||||
public Item GetItemFromBuyBackSlot(uint slot)
|
||||
{
|
||||
@@ -4523,10 +4530,16 @@ namespace Game.Entities
|
||||
uint freeSlotCount = 0;
|
||||
|
||||
if (location.HasFlag(ItemSearchLocation.Equipment))
|
||||
{
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; ++i)
|
||||
if (GetItemByPos(InventorySlots.Bag0, i) == null)
|
||||
++freeSlotCount;
|
||||
|
||||
for (byte i = ProfessionSlots.Start; i < ProfessionSlots.End; ++i)
|
||||
if (!GetItemByPos(InventorySlots.Bag0, i))
|
||||
++freeSlotCount;
|
||||
}
|
||||
|
||||
if (location.HasFlag(ItemSearchLocation.Inventory))
|
||||
{
|
||||
int inventoryEnd = InventorySlots.ItemStart + GetInventorySlotCount();
|
||||
@@ -4565,9 +4578,20 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
if (location.HasFlag(ItemSearchLocation.ReagentBank))
|
||||
{
|
||||
for (byte i = InventorySlots.ReagentBagStart; i < InventorySlots.ReagentBagEnd; ++i)
|
||||
{
|
||||
Bag bag = GetBagByPos(i);
|
||||
if (bag != null)
|
||||
for (byte j = 0; j < bag.GetBagSize(); ++j)
|
||||
if (bag.GetItemByPos(j) == null)
|
||||
++freeSlotCount;
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ReagentEnd; ++i)
|
||||
if (GetItemByPos(InventorySlots.Bag0, i) == null)
|
||||
++freeSlotCount;
|
||||
}
|
||||
|
||||
return freeSlotCount;
|
||||
}
|
||||
@@ -4608,7 +4632,8 @@ namespace Game.Entities
|
||||
public Bag GetBagByPos(byte bag)
|
||||
{
|
||||
if ((bag >= InventorySlots.BagStart && bag < InventorySlots.BagEnd)
|
||||
|| (bag >= InventorySlots.BankBagStart && bag < InventorySlots.BankBagEnd))
|
||||
|| (bag >= InventorySlots.BankBagStart && bag < InventorySlots.BankBagEnd)
|
||||
|| (bag >= InventorySlots.ReagentBagStart && bag < InventorySlots.ReagentBagEnd))
|
||||
{
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, bag);
|
||||
if (item != null)
|
||||
@@ -4624,6 +4649,8 @@ namespace Game.Entities
|
||||
return true;
|
||||
if (bag == InventorySlots.Bag0 && (slot >= InventorySlots.BankBagStart && slot < InventorySlots.BankBagEnd))
|
||||
return true;
|
||||
if (bag == InventorySlots.Bag0 && (slot >= InventorySlots.ReagentBagStart && slot < InventorySlots.ReagentBagEnd))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
InventoryResult CanStoreItem_InBag(byte bag, List<ItemPosCount> dest, ItemTemplate pProto, ref uint count, bool merge, bool non_specialized, Item pSrcItem, byte skip_bag, byte skip_slot)
|
||||
@@ -4712,8 +4739,12 @@ namespace Game.Entities
|
||||
{
|
||||
if (bag == InventorySlots.Bag0 && (slot < EquipmentSlot.End))
|
||||
return true;
|
||||
if (bag == InventorySlots.Bag0 && (slot >= ProfessionSlots.Start && slot < ProfessionSlots.End))
|
||||
return true;
|
||||
if (bag == InventorySlots.Bag0 && (slot >= InventorySlots.BagStart && slot < InventorySlots.BagEnd))
|
||||
return true;
|
||||
if (bag == InventorySlots.Bag0 && (slot >= InventorySlots.ReagentBagStart && slot < InventorySlots.ReagentBagEnd))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
byte FindEquipSlot(Item item, uint slot, bool swap)
|
||||
@@ -5246,8 +5277,10 @@ namespace Game.Entities
|
||||
{
|
||||
AddTemporarySpell(artifactPowerRank.SpellID);
|
||||
LearnedSpells learnedSpells = new();
|
||||
LearnedSpellInfo learnedSpellInfo = new();
|
||||
learnedSpellInfo.SpellID = artifactPowerRank.SpellID;
|
||||
learnedSpells.SuppressMessaging = true;
|
||||
learnedSpells.SpellID.Add(artifactPowerRank.SpellID);
|
||||
learnedSpells.ClientLearnedSpellData.Add(learnedSpellInfo);
|
||||
SendPacket(learnedSpells);
|
||||
}
|
||||
else if (!apply)
|
||||
@@ -6314,6 +6347,14 @@ namespace Game.Entities
|
||||
if (!callback(item))
|
||||
return false;
|
||||
}
|
||||
|
||||
for (byte i = ProfessionSlots.Start; i < ProfessionSlots.End; ++i)
|
||||
{
|
||||
Item pItem = GetItemByPos(InventorySlots.Bag0, i);
|
||||
if (pItem != null)
|
||||
if (!callback(pItem))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (location.HasAnyFlag(ItemSearchLocation.Inventory))
|
||||
@@ -6379,6 +6420,21 @@ namespace Game.Entities
|
||||
|
||||
if (location.HasAnyFlag(ItemSearchLocation.ReagentBank))
|
||||
{
|
||||
for (byte i = InventorySlots.ReagentBagStart; i < InventorySlots.ReagentBagEnd; ++i)
|
||||
{
|
||||
Bag bag = GetBagByPos(i);
|
||||
if (bag != null)
|
||||
{
|
||||
for (byte j = 0; j < bag.GetBagSize(); ++j)
|
||||
{
|
||||
Item pItem = bag.GetItemByPos(j);
|
||||
if (pItem != null)
|
||||
if (!callback(pItem))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ReagentEnd; ++i)
|
||||
{
|
||||
Item item = GetItemByPos(InventorySlots.Bag0, i);
|
||||
@@ -6471,7 +6527,7 @@ namespace Game.Entities
|
||||
ForEachItem(ItemSearchLocation.Everywhere, item =>
|
||||
{
|
||||
ItemTemplate itemTemplate = item.GetTemplate();
|
||||
if (itemTemplate != null)
|
||||
if (itemTemplate != null && itemTemplate.GetInventoryType() < InventoryType.ProfessionTool)
|
||||
{
|
||||
ushort dest;
|
||||
if (item.IsEquipped())
|
||||
|
||||
@@ -3114,14 +3114,5 @@ namespace Game.Entities
|
||||
|
||||
SendPacket(displayToast);
|
||||
}
|
||||
|
||||
void SendGarrisonOpenTalentNpc(ObjectGuid guid, int garrTalentTreeId, int friendshipFactionId)
|
||||
{
|
||||
GarrisonOpenTalentNpc openTalentNpc = new();
|
||||
openTalentNpc.NpcGUID = guid;
|
||||
openTalentNpc.GarrTalentTreeID = garrTalentTreeId;
|
||||
openTalentNpc.FriendshipFactionID = friendshipFactionId;
|
||||
SendPacket(openTalentNpc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2058,10 +2058,12 @@ namespace Game.Entities
|
||||
// prevent duplicated entires in spell book, also not send if not in world (loading)
|
||||
if (learning && IsInWorld)
|
||||
{
|
||||
LearnedSpells packet = new();
|
||||
packet.SpellID.Add(spellId);
|
||||
packet.SuppressMessaging = suppressMessaging;
|
||||
SendPacket(packet);
|
||||
LearnedSpells learnedSpells = new();
|
||||
LearnedSpellInfo learnedSpellInfo = new();
|
||||
learnedSpellInfo.SpellID = spellId;
|
||||
learnedSpells.SuppressMessaging = suppressMessaging;
|
||||
learnedSpells.ClientLearnedSpellData.Add(learnedSpellInfo);
|
||||
SendPacket(learnedSpells);
|
||||
}
|
||||
|
||||
// learn all disabled higher ranks and required spells (recursive)
|
||||
@@ -3046,8 +3048,10 @@ namespace Game.Entities
|
||||
void SendSupercededSpell(uint oldSpell, uint newSpell)
|
||||
{
|
||||
SupercededSpells supercededSpells = new();
|
||||
supercededSpells.SpellID.Add(newSpell);
|
||||
supercededSpells.Superceded.Add(oldSpell);
|
||||
LearnedSpellInfo learnedSpellInfo = new();
|
||||
learnedSpellInfo.SpellID = newSpell;
|
||||
learnedSpellInfo.Superceded = (int)oldSpell;
|
||||
supercededSpells.ClientLearnedSpellData.Add(learnedSpellInfo);
|
||||
SendPacket(supercededSpells);
|
||||
}
|
||||
|
||||
|
||||
@@ -698,6 +698,11 @@ namespace Game.Entities
|
||||
if (HasPvpTalent(talentID, GetActiveTalentGroup()))
|
||||
return TalentLearnResult.FailedUnknown;
|
||||
|
||||
PlayerConditionRecord playerCondition = CliDB.PlayerConditionStorage.LookupByKey(talentInfo.PlayerConditionID);
|
||||
if (playerCondition != null)
|
||||
if (!ConditionManager.IsPlayerMeetingCondition(this, playerCondition))
|
||||
return TalentLearnResult.FailedCantDoThatRightNow;
|
||||
|
||||
PvpTalentRecord talent = CliDB.PvpTalentStorage.LookupByKey(GetPvpTalentMap(GetActiveTalentGroup())[slot]);
|
||||
if (talent != null)
|
||||
{
|
||||
|
||||
@@ -296,7 +296,7 @@ namespace Game.Entities
|
||||
|
||||
// original items
|
||||
foreach (PlayerCreateInfoItem initialItem in info.item)
|
||||
StoreNewItemInBestSlots(initialItem.item_id, initialItem.item_amount);
|
||||
StoreNewItemInBestSlots(initialItem.item_id, initialItem.item_amount, info.itemContext);
|
||||
|
||||
// bags and main-hand weapon must equipped at this moment
|
||||
// now second pass for not equipped (offhand weapon/shield if it attempt equipped before main-hand weapon)
|
||||
@@ -685,7 +685,7 @@ namespace Game.Entities
|
||||
|
||||
if (target == this)
|
||||
{
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < InventorySlots.BankBagEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
@@ -693,23 +693,7 @@ namespace Game.Entities
|
||||
m_items[i].DestroyForPlayer(target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.BagStart; i < InventorySlots.BagEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
|
||||
m_items[i].DestroyForPlayer(target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ReagentEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
|
||||
m_items[i].DestroyForPlayer(target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ChildEquipmentStart; i < InventorySlots.ChildEquipmentEnd; ++i)
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ChildEquipmentEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
@@ -2329,7 +2313,7 @@ namespace Game.Entities
|
||||
{
|
||||
switch (gossipMenuItem.OptionNpc)
|
||||
{
|
||||
case GossipOptionNpc.TaxiNode:
|
||||
case GossipOptionNpc.Taxinode:
|
||||
if (GetSession().SendLearnNewTaxiNode(creature))
|
||||
return;
|
||||
break;
|
||||
@@ -2337,7 +2321,7 @@ namespace Game.Entities
|
||||
if (!IsDead())
|
||||
canTalk = false;
|
||||
break;
|
||||
case GossipOptionNpc.BattleMaster:
|
||||
case GossipOptionNpc.Battlemaster:
|
||||
if (!creature.CanInteractWithBattleMaster(this, false))
|
||||
canTalk = false;
|
||||
break;
|
||||
@@ -2347,7 +2331,7 @@ namespace Game.Entities
|
||||
if (!creature.CanResetTalents(this))
|
||||
canTalk = false;
|
||||
break;
|
||||
case GossipOptionNpc.StableMaster:
|
||||
case GossipOptionNpc.Stablemaster:
|
||||
case GossipOptionNpc.PetSpecializationMaster:
|
||||
if (GetClass() != Class.Hunter)
|
||||
canTalk = false;
|
||||
@@ -2376,32 +2360,32 @@ namespace Game.Entities
|
||||
canTalk = false; // Deprecated
|
||||
break;
|
||||
case GossipOptionNpc.GuildBanker:
|
||||
case GossipOptionNpc.SpellClick:
|
||||
case GossipOptionNpc.WorldPVPQueue:
|
||||
case GossipOptionNpc.Spellclick:
|
||||
case GossipOptionNpc.WorldPvPQueue:
|
||||
case GossipOptionNpc.LFGDungeon:
|
||||
case GossipOptionNpc.ArtifactRespec:
|
||||
case GossipOptionNpc.QueueScenario:
|
||||
case GossipOptionNpc.GarrisonArchitect:
|
||||
case GossipOptionNpc.GarrisonMission:
|
||||
case GossipOptionNpc.GarrisonMissionNpc:
|
||||
case GossipOptionNpc.ShipmentCrafter:
|
||||
case GossipOptionNpc.GarrisonTradeskill:
|
||||
case GossipOptionNpc.GarrisonTradeskillNpc:
|
||||
case GossipOptionNpc.GarrisonRecruitment:
|
||||
case GossipOptionNpc.AdventureMap:
|
||||
case GossipOptionNpc.GarrisonTalent:
|
||||
case GossipOptionNpc.ContributionCollector:
|
||||
case GossipOptionNpc.IslandsMission:
|
||||
case GossipOptionNpc.IslandsMissionNpc:
|
||||
case GossipOptionNpc.UIItemInteraction:
|
||||
case GossipOptionNpc.WorldMap:
|
||||
case GossipOptionNpc.Soulbind:
|
||||
case GossipOptionNpc.ChromieTime:
|
||||
case GossipOptionNpc.CovenantPreview:
|
||||
case GossipOptionNpc.ChromieTimeNpc:
|
||||
case GossipOptionNpc.CovenantPreviewNpc:
|
||||
case GossipOptionNpc.RuneforgeLegendaryCrafting:
|
||||
case GossipOptionNpc.NewPlayerGuide:
|
||||
case GossipOptionNpc.RuneforgeLegendaryUpgrade:
|
||||
case GossipOptionNpc.CovenantRenown:
|
||||
case GossipOptionNpc.CovenantRenownNpc:
|
||||
break; // NYI
|
||||
default:
|
||||
Log.outError(LogFilter.Sql, $"Creature entry {creature.GetEntry()} has an unknown gossip option icon {gossipMenuItem.OptionNpc} for menu {gossipMenuItem.MenuId}.");
|
||||
Log.outError(LogFilter.Sql, $"Creature entry {creature.GetEntry()} has an unknown gossip option icon {gossipMenuItem.OptionNpc} for menu {gossipMenuItem.MenuID}.");
|
||||
canTalk = false;
|
||||
break;
|
||||
}
|
||||
@@ -2421,45 +2405,7 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
if (canTalk)
|
||||
{
|
||||
string strOptionText;
|
||||
string strBoxText;
|
||||
BroadcastTextRecord optionBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(gossipMenuItem.OptionBroadcastTextId);
|
||||
BroadcastTextRecord boxBroadcastText = CliDB.BroadcastTextStorage.LookupByKey(gossipMenuItem.BoxBroadcastTextId);
|
||||
Locale locale = GetSession().GetSessionDbLocaleIndex();
|
||||
|
||||
if (optionBroadcastText != null)
|
||||
strOptionText = Global.DB2Mgr.GetBroadcastTextValue(optionBroadcastText, locale, GetGender());
|
||||
else
|
||||
strOptionText = gossipMenuItem.OptionText;
|
||||
|
||||
if (boxBroadcastText != null)
|
||||
strBoxText = Global.DB2Mgr.GetBroadcastTextValue(boxBroadcastText, locale, GetGender());
|
||||
else
|
||||
strBoxText = gossipMenuItem.BoxText;
|
||||
|
||||
if (locale != Locale.enUS)
|
||||
{
|
||||
if (optionBroadcastText == null)
|
||||
{
|
||||
// Find localizations from database.
|
||||
GossipMenuItemsLocale gossipMenuLocale = Global.ObjectMgr.GetGossipMenuItemsLocale(menuId, gossipMenuItem.OptionId);
|
||||
if (gossipMenuLocale != null)
|
||||
ObjectManager.GetLocaleString(gossipMenuLocale.OptionText, locale, ref strOptionText);
|
||||
}
|
||||
|
||||
if (boxBroadcastText == null)
|
||||
{
|
||||
// Find localizations from database.
|
||||
GossipMenuItemsLocale gossipMenuLocale = Global.ObjectMgr.GetGossipMenuItemsLocale(menuId, gossipMenuItem.OptionId);
|
||||
if (gossipMenuLocale != null)
|
||||
ObjectManager.GetLocaleString(gossipMenuLocale.BoxText, locale, ref strBoxText);
|
||||
}
|
||||
}
|
||||
|
||||
menu.GetGossipMenu().AddMenuItem((int)gossipMenuItem.OptionId, gossipMenuItem.OptionNpc, strOptionText, 0, (uint)gossipMenuItem.OptionNpc, strBoxText, gossipMenuItem.BoxMoney, gossipMenuItem.BoxCoded);
|
||||
menu.GetGossipMenu().AddGossipMenuItemData(gossipMenuItem.OptionId, gossipMenuItem.ActionMenuId, gossipMenuItem.ActionPoiId);
|
||||
}
|
||||
menu.GetGossipMenu().AddMenuItem(gossipMenuItem, gossipMenuItem.MenuID, gossipMenuItem.OrderIndex);
|
||||
}
|
||||
}
|
||||
public void SendPreparedGossip(WorldObject source)
|
||||
@@ -2486,7 +2432,7 @@ namespace Game.Entities
|
||||
|
||||
PlayerTalkClass.SendGossipMenu(textId, source.GetGUID());
|
||||
}
|
||||
public void OnGossipSelect(WorldObject source, uint gossipListId, uint menuId)
|
||||
public void OnGossipSelect(WorldObject source, int gossipOptionId, uint menuId)
|
||||
{
|
||||
GossipMenu gossipMenu = PlayerTalkClass.GetGossipMenu();
|
||||
|
||||
@@ -2494,7 +2440,7 @@ namespace Game.Entities
|
||||
if (menuId != gossipMenu.GetMenuId())
|
||||
return;
|
||||
|
||||
GossipMenuItem item = gossipMenu.GetItem(gossipListId);
|
||||
GossipMenuItem item = gossipMenu.GetItem(gossipOptionId);
|
||||
if (item == null)
|
||||
return;
|
||||
|
||||
@@ -2510,10 +2456,6 @@ namespace Game.Entities
|
||||
}
|
||||
}
|
||||
|
||||
GossipMenuItemData menuItemData = gossipMenu.GetItemData(gossipListId);
|
||||
if (menuItemData == null)
|
||||
return;
|
||||
|
||||
long cost = item.BoxMoney;
|
||||
if (!HasEnoughMoney(cost))
|
||||
{
|
||||
@@ -2522,51 +2464,37 @@ namespace Game.Entities
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.ActionPoiID != 0)
|
||||
PlayerTalkClass.SendPointOfInterest(item.ActionPoiID);
|
||||
|
||||
if (item.ActionMenuID != 0)
|
||||
{
|
||||
PrepareGossipMenu(source, item.ActionMenuID);
|
||||
SendPreparedGossip(source);
|
||||
}
|
||||
|
||||
// types that have their dedicated open opcode dont send WorldPackets::NPC::GossipOptionNPCInteraction
|
||||
bool handled = true;
|
||||
switch (gossipOptionNpc)
|
||||
{
|
||||
case GossipOptionNpc.None:
|
||||
{
|
||||
if (menuItemData.GossipActionPoi != 0)
|
||||
PlayerTalkClass.SendPointOfInterest(menuItemData.GossipActionPoi);
|
||||
|
||||
if (menuItemData.GossipActionMenuId != 0)
|
||||
{
|
||||
PrepareGossipMenu(source, menuItemData.GossipActionMenuId);
|
||||
SendPreparedGossip(source);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GossipOptionNpc.Vendor:
|
||||
GetSession().SendListInventory(guid);
|
||||
break;
|
||||
case GossipOptionNpc.TaxiNode:
|
||||
case GossipOptionNpc.Taxinode:
|
||||
GetSession().SendTaxiMenu(source.ToCreature());
|
||||
break;
|
||||
case GossipOptionNpc.Trainer:
|
||||
GetSession().SendTrainerList(source.ToCreature(), Global.ObjectMgr.GetCreatureTrainerForGossipOption(source.GetEntry(), menuId, gossipListId));
|
||||
GetSession().SendTrainerList(source.ToCreature(), Global.ObjectMgr.GetCreatureTrainerForGossipOption(source.GetEntry(), menuId, (uint)gossipOptionId));
|
||||
break;
|
||||
case GossipOptionNpc.SpiritHealer:
|
||||
if (IsDead())
|
||||
source.ToCreature().CastSpell(source.ToCreature(), 17251, new CastSpellExtraArgs(TriggerCastFlags.FullMask)
|
||||
.SetOriginalCaster(GetGUID()));
|
||||
break;
|
||||
case GossipOptionNpc.Binder:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
SetBindPoint(guid);
|
||||
break;
|
||||
case GossipOptionNpc.Banker:
|
||||
GetSession().SendShowBank(guid);
|
||||
source.CastSpell(source.ToCreature(), 17251, new CastSpellExtraArgs(TriggerCastFlags.FullMask).SetOriginalCaster(GetGUID()));
|
||||
handled = false;
|
||||
break;
|
||||
case GossipOptionNpc.PetitionVendor:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
GetSession().SendPetitionShowList(guid);
|
||||
break;
|
||||
case GossipOptionNpc.TabardVendor:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
GetSession().SendTabardVendorActivate(guid);
|
||||
break;
|
||||
case GossipOptionNpc.BattleMaster:
|
||||
case GossipOptionNpc.Battlemaster:
|
||||
{
|
||||
BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(source.GetEntry());
|
||||
|
||||
@@ -2586,13 +2514,25 @@ namespace Game.Entities
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
SendRespecWipeConfirm(guid, WorldConfig.GetBoolValue(WorldCfg.NoResetTalentCost) ? 0 : GetNextResetTalentsCost(), SpecResetType.Talents);
|
||||
break;
|
||||
case GossipOptionNpc.StableMaster:
|
||||
case GossipOptionNpc.Stablemaster:
|
||||
GetSession().SendStablePet(guid);
|
||||
break;
|
||||
case GossipOptionNpc.PetSpecializationMaster:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
SendRespecWipeConfirm(guid, WorldConfig.GetBoolValue(WorldCfg.NoResetTalentCost) ? 0 : GetNextResetTalentsCost(), SpecResetType.PetTalents);
|
||||
break;
|
||||
case GossipOptionNpc.GuildBanker:
|
||||
Guild guild = GetGuild();
|
||||
if (guild != null)
|
||||
guild.SendBankList(GetSession(), 0, true);
|
||||
else
|
||||
Guild.SendCommandResult(GetSession(), GuildCommandType.ViewTab, GuildCommandError.PlayerNotInGuild);
|
||||
break;
|
||||
case GossipOptionNpc.Spellclick:
|
||||
Unit sourceUnit = source.ToUnit();
|
||||
if (sourceUnit != null)
|
||||
sourceUnit.HandleSpellClick(this);
|
||||
break;
|
||||
case GossipOptionNpc.DisableXPGain:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
CastSpell(null, PlayerConst.SpellExperienceEliminated, true);
|
||||
@@ -2603,9 +2543,6 @@ namespace Game.Entities
|
||||
RemoveAurasDueToSpell(PlayerConst.SpellExperienceEliminated);
|
||||
RemovePlayerFlag(PlayerFlags.NoXPGain);
|
||||
break;
|
||||
case GossipOptionNpc.Mailbox:
|
||||
GetSession().SendShowMailBox(guid);
|
||||
break;
|
||||
case GossipOptionNpc.SpecializationMaster:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
SendRespecWipeConfirm(guid, 0, SpecResetType.Specialization);
|
||||
@@ -2614,22 +2551,74 @@ namespace Game.Entities
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
SendRespecWipeConfirm(guid, 0, SpecResetType.Glyphs);
|
||||
break;
|
||||
case GossipOptionNpc.GarrisonTalent:
|
||||
case GossipOptionNpc.GarrisonTradeskillNpc: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.GarrisonRecruitment: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.ChromieTimeNpc: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.RuneforgeLegendaryCrafting: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.RuneforgeLegendaryUpgrade: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.ProfessionsCraftingOrder: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.ProfessionsCustomerOrder: // NYI
|
||||
break;
|
||||
case GossipOptionNpc.BarbersChoice: // NYI - unknown if needs sending
|
||||
default:
|
||||
handled = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handled)
|
||||
{
|
||||
if (item.GossipNpcOptionID.HasValue)
|
||||
{
|
||||
GossipMenuAddon addon = Global.ObjectMgr.GetGossipMenuAddon(menuId);
|
||||
GossipMenuItemAddon itemAddon = Global.ObjectMgr.GetGossipMenuItemAddon(menuId, gossipListId);
|
||||
SendGarrisonOpenTalentNpc(guid, itemAddon != null ? itemAddon.GarrTalentTreeID.GetValueOrDefault(0) : 0, addon != null ? addon.FriendshipFactionID : 0);
|
||||
break;
|
||||
|
||||
GossipOptionNPCInteraction npcInteraction = new();
|
||||
npcInteraction.GossipGUID = source.GetGUID();
|
||||
npcInteraction.GossipNpcOptionID = item.GossipNpcOptionID.Value;
|
||||
if (addon != null && addon.FriendshipFactionID != 0)
|
||||
npcInteraction.FriendshipFactionID = addon.FriendshipFactionID;
|
||||
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
else
|
||||
{
|
||||
PlayerInteractionType[] GossipOptionNpcToInteractionType =
|
||||
{
|
||||
PlayerInteractionType.None, PlayerInteractionType.Vendor, PlayerInteractionType.TaxiNode,
|
||||
PlayerInteractionType.Trainer, PlayerInteractionType.SpiritHealer, PlayerInteractionType.Binder,
|
||||
PlayerInteractionType.Banker, PlayerInteractionType.PetitionVendor, PlayerInteractionType.TabardVendor,
|
||||
PlayerInteractionType.BattleMaster, PlayerInteractionType.Auctioneer, PlayerInteractionType.TalentMaster,
|
||||
PlayerInteractionType.StableMaster, PlayerInteractionType.None, PlayerInteractionType.GuildBanker,
|
||||
PlayerInteractionType.None, PlayerInteractionType.None, PlayerInteractionType.None,
|
||||
PlayerInteractionType.MailInfo, PlayerInteractionType.None, PlayerInteractionType.LFGDungeon,
|
||||
PlayerInteractionType.ArtifactForge, PlayerInteractionType.None, PlayerInteractionType.SpecializationMaster,
|
||||
PlayerInteractionType.None, PlayerInteractionType.None, PlayerInteractionType.GarrArchitect,
|
||||
PlayerInteractionType.GarrMission, PlayerInteractionType.ShipmentCrafter, PlayerInteractionType.GarrTradeskill,
|
||||
PlayerInteractionType.GarrRecruitment, PlayerInteractionType.AdventureMap, PlayerInteractionType.GarrTalent,
|
||||
PlayerInteractionType.ContributionCollector, PlayerInteractionType.Transmogrifier, PlayerInteractionType.AzeriteRespec,
|
||||
PlayerInteractionType.IslandQueue, PlayerInteractionType.ItemInteraction, PlayerInteractionType.WorldMap,
|
||||
PlayerInteractionType.Soulbind, PlayerInteractionType.ChromieTime, PlayerInteractionType.CovenantPreview,
|
||||
PlayerInteractionType.LegendaryCrafting, PlayerInteractionType.NewPlayerGuide, PlayerInteractionType.LegendaryCrafting,
|
||||
PlayerInteractionType.Renown, PlayerInteractionType.BlackMarketAuctioneer, PlayerInteractionType.PerksProgramVendor,
|
||||
PlayerInteractionType.ProfessionsCraftingOrder, PlayerInteractionType.Professions, PlayerInteractionType.ProfessionsCustomerOrder,
|
||||
PlayerInteractionType.TraitSystem, PlayerInteractionType.BarbersChoice, PlayerInteractionType.MajorFactionRenown
|
||||
};
|
||||
|
||||
PlayerInteractionType interactionType = GossipOptionNpcToInteractionType[(int)gossipOptionNpc];
|
||||
if (interactionType != PlayerInteractionType.None)
|
||||
{
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = source.GetGUID();
|
||||
npcInteraction.InteractionType = interactionType;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
}
|
||||
case GossipOptionNpc.Transmogrify:
|
||||
GetSession().SendOpenTransmogrifier(guid);
|
||||
break;
|
||||
case GossipOptionNpc.AzeriteRespec:
|
||||
PlayerTalkClass.SendCloseGossip();
|
||||
GetSession().SendAzeriteRespecNPC(guid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ModifyMoney(-cost);
|
||||
@@ -2916,8 +2905,11 @@ namespace Game.Entities
|
||||
}
|
||||
public void SetBindPoint(ObjectGuid guid)
|
||||
{
|
||||
BinderConfirm packet = new(guid);
|
||||
SendPacket(packet);
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.Binder;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
public void SendBindPointUpdate()
|
||||
{
|
||||
@@ -4021,7 +4013,7 @@ namespace Game.Entities
|
||||
corpse.SetDisplayId(GetNativeDisplayId());
|
||||
corpse.SetFactionTemplate(CliDB.ChrRacesStorage.LookupByKey(GetRace()).FactionID);
|
||||
|
||||
for (byte i = 0; i < EquipmentSlot.End; i++)
|
||||
for (byte i = EquipmentSlot.Start; i < EquipmentSlot.End; i++)
|
||||
{
|
||||
if (m_items[i] != null)
|
||||
{
|
||||
@@ -6240,7 +6232,6 @@ namespace Game.Entities
|
||||
packet.Reason = victim ? PlayerLogXPReason.Kill : PlayerLogXPReason.NoKill;
|
||||
packet.Amount = (int)xp;
|
||||
packet.GroupBonus = group_rate;
|
||||
packet.ReferAFriendBonusType = (byte)(recruitAFriend ? 1 : 0);
|
||||
SendPacket(packet);
|
||||
|
||||
uint nextLvlXP = GetXPForNextLevel();
|
||||
@@ -7238,7 +7229,7 @@ namespace Game.Entities
|
||||
{
|
||||
if (target == this)
|
||||
{
|
||||
for (byte i = 0; i < EquipmentSlot.End; ++i)
|
||||
for (byte i = EquipmentSlot.Start; i < InventorySlots.BankBagEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
@@ -7246,23 +7237,7 @@ namespace Game.Entities
|
||||
m_items[i].BuildCreateUpdateBlockForPlayer(data, target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.BagStart; i < InventorySlots.BankBagEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
|
||||
m_items[i].BuildCreateUpdateBlockForPlayer(data, target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ReagentEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
|
||||
m_items[i].BuildCreateUpdateBlockForPlayer(data, target);
|
||||
}
|
||||
|
||||
for (byte i = InventorySlots.ChildEquipmentStart; i < InventorySlots.ChildEquipmentEnd; ++i)
|
||||
for (byte i = InventorySlots.ReagentStart; i < InventorySlots.ChildEquipmentEnd; ++i)
|
||||
{
|
||||
if (m_items[i] == null)
|
||||
continue;
|
||||
@@ -7392,9 +7367,18 @@ namespace Game.Entities
|
||||
}
|
||||
|
||||
//Helpers
|
||||
public void AddGossipItem(GossipOptionNpc icon, string message, uint sender, uint action) { PlayerTalkClass.GetGossipMenu().AddMenuItem(-1, icon, message, sender, action, "", 0); }
|
||||
public void AddGossipItem(uint menuId, uint menuItemId, uint sender, uint action) { PlayerTalkClass.GetGossipMenu().AddMenuItem(menuId, menuItemId, sender, action); }
|
||||
public void ADD_GOSSIP_ITEM_EXTENDED(GossipOptionNpc icon, string message, uint sender, uint action, string boxmessage, uint boxmoney, bool coded) { PlayerTalkClass.GetGossipMenu().AddMenuItem(-1, icon, message, sender, action, boxmessage, boxmoney, coded); }
|
||||
public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action)
|
||||
{
|
||||
PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, false, 0, "", null, null, sender, action);
|
||||
}
|
||||
public void AddGossipItem(GossipOptionNpc optionNpc, string text, uint sender, uint action, string popupText, uint popupMoney, bool coded)
|
||||
{
|
||||
PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, coded, popupMoney, popupText, null, null, sender, action);
|
||||
}
|
||||
public void AddGossipItem(uint gossipMenuID, uint gossipMenuItemID, uint sender, uint action)
|
||||
{
|
||||
PlayerTalkClass.GetGossipMenu().AddMenuItem(gossipMenuID, gossipMenuItemID, sender, action);
|
||||
}
|
||||
|
||||
// This fuction Sends the current menu to show to client, a - NPCTEXTID(uint32), b - npc guid(uint64)
|
||||
public void SendGossipMenu(uint titleId, ObjectGuid objGUID) { PlayerTalkClass.SendGossipMenu(titleId, objGUID); }
|
||||
|
||||
@@ -1634,7 +1634,9 @@ namespace Game.Entities
|
||||
0.9830f, // Warlock
|
||||
0.9830f, // Monk
|
||||
0.9720f, // Druid
|
||||
0.9830f // Demon Hunter
|
||||
0.9830f, // Demon Hunter
|
||||
0.9880f, // Evoker
|
||||
1.0f, // Adventurer
|
||||
};
|
||||
|
||||
// 1 1 k cx
|
||||
@@ -1670,7 +1672,9 @@ namespace Game.Entities
|
||||
0.0f, // Warlock
|
||||
90.6425f, // Monk
|
||||
0.0f, // Druid
|
||||
65.631440f // Demon Hunter
|
||||
65.631440f, // Demon Hunter
|
||||
0.0f, // Evoker
|
||||
0.0f, // Adventurer
|
||||
};
|
||||
|
||||
public void UpdateParryPercentage()
|
||||
@@ -1708,7 +1712,9 @@ namespace Game.Entities
|
||||
150.375940f, // Warlock
|
||||
145.560408f, // Monk
|
||||
116.890707f, // Druid
|
||||
145.560408f // Demon Hunter
|
||||
145.560408f, // Demon Hunter
|
||||
145.560408f, // Evoker
|
||||
0.0f, // Adventurer
|
||||
};
|
||||
|
||||
public void UpdateDodgePercentage()
|
||||
|
||||
@@ -301,6 +301,11 @@ namespace Game.Entities
|
||||
{
|
||||
return aurEff.GetCasterGUID() == caster.GetGUID() && aurEff.IsAffectingSpell(spellProto);
|
||||
});
|
||||
|
||||
TakenTotalMod *= GetTotalAuraMultiplier(AuraType.ModDamageTakenFromCasterByLabel, aurEff =>
|
||||
{
|
||||
return aurEff.GetCasterGUID() == caster.GetGUID() && spellProto.HasLabel((uint)aurEff.GetMiscValue());
|
||||
});
|
||||
}
|
||||
|
||||
if (damagetype == DamageEffectType.DOT)
|
||||
|
||||
Reference in New Issue
Block a user