Core: Updated to 10.0.2
Port From (https://github.com/TrinityCore/TrinityCore/commit/e98e1283ea0034baf6be9aa2ffb386eb5582801b)
This commit is contained in:
@@ -2758,7 +2758,7 @@ namespace Game.Achievements
|
||||
|
||||
bool bagScanReachedEnd = referencePlayer.ForEachItem(ItemSearchLocation.Everywhere, item =>
|
||||
{
|
||||
bool hasBonus = item.m_itemData.BonusListIDs._value.Any(bonusListID => bonusListIDs.Contains(bonusListID));
|
||||
bool hasBonus = item.GetBonusListIDs().Any(bonusListID => bonusListIDs.Contains(bonusListID));
|
||||
return !hasBonus;
|
||||
});
|
||||
|
||||
@@ -2880,7 +2880,7 @@ namespace Game.Achievements
|
||||
if (pvpTier == null)
|
||||
return false;
|
||||
|
||||
if (pvpTier.BracketID >= referencePlayer.m_activePlayerData.PvpInfo.GetSize())
|
||||
if (pvpTier.BracketID >= referencePlayer.m_activePlayerData.PvpInfo.Size())
|
||||
return false;
|
||||
|
||||
var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[pvpTier.BracketID];
|
||||
@@ -2918,7 +2918,7 @@ namespace Game.Achievements
|
||||
}
|
||||
case ModifierTreeType.PlayerPvpTierInBracketEqualOrGreaterThan: // 239
|
||||
{
|
||||
if (secondaryAsset >= referencePlayer.m_activePlayerData.PvpInfo.GetSize())
|
||||
if (secondaryAsset >= referencePlayer.m_activePlayerData.PvpInfo.Size())
|
||||
return false;
|
||||
|
||||
var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[secondaryAsset];
|
||||
@@ -3475,7 +3475,7 @@ namespace Game.Achievements
|
||||
if (pvpTier == null)
|
||||
return false;
|
||||
|
||||
if (pvpTier.BracketID >= referencePlayer.m_activePlayerData.PvpInfo.GetSize())
|
||||
if (pvpTier.BracketID >= referencePlayer.m_activePlayerData.PvpInfo.Size())
|
||||
return false;
|
||||
|
||||
var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[pvpTier.BracketID];
|
||||
@@ -3486,7 +3486,7 @@ namespace Game.Achievements
|
||||
}
|
||||
case ModifierTreeType.PlayerBestWeeklyWinPvpTierInBracketEqualOrGreaterThan: // 325
|
||||
{
|
||||
if (secondaryAsset >= referencePlayer.m_activePlayerData.PvpInfo.GetSize())
|
||||
if (secondaryAsset >= referencePlayer.m_activePlayerData.PvpInfo.Size())
|
||||
return false;
|
||||
|
||||
var pvpInfo = referencePlayer.m_activePlayerData.PvpInfo[secondaryAsset];
|
||||
@@ -3518,6 +3518,109 @@ namespace Game.Achievements
|
||||
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerAuraWithLabelStackCountEqualOrGreaterThan: // 335
|
||||
{
|
||||
uint count = 0;
|
||||
referencePlayer.HasAura(aura =>
|
||||
{
|
||||
if (aura.GetSpellInfo().HasLabel((uint)secondaryAsset))
|
||||
count += aura.GetStackAmount();
|
||||
return false;
|
||||
});
|
||||
if (count < reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerAuraWithLabelStackCountEqual: // 336
|
||||
{
|
||||
uint count = 0;
|
||||
referencePlayer.HasAura(aura =>
|
||||
{
|
||||
if (aura.GetSpellInfo().HasLabel((uint)secondaryAsset))
|
||||
count += aura.GetStackAmount();
|
||||
return false;
|
||||
});
|
||||
if (count != reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerAuraWithLabelStackCountEqualOrLessThan: // 337
|
||||
{
|
||||
uint count = 0;
|
||||
referencePlayer.HasAura(aura =>
|
||||
{
|
||||
if (aura.GetSpellInfo().HasLabel((uint)secondaryAsset))
|
||||
count += aura.GetStackAmount();
|
||||
return false;
|
||||
});
|
||||
if (count > reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerIsInCrossFactionGroup: // 338
|
||||
{
|
||||
var group = referencePlayer.GetGroup();
|
||||
if (!group.GetGroupFlags().HasFlag(GroupFlags.CrossFaction))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerHasTraitNodeEntryInActiveConfig: // 340
|
||||
{
|
||||
bool hasTraitNodeEntry()
|
||||
{
|
||||
foreach (var traitConfig in referencePlayer.m_activePlayerData.TraitConfigs)
|
||||
{
|
||||
if ((TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat)
|
||||
{
|
||||
if (referencePlayer.m_activePlayerData.ActiveCombatTraitConfigID != traitConfig.ID
|
||||
|| !((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.ActiveForSpec))
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var traitEntry in traitConfig.Entries)
|
||||
if (traitEntry.TraitNodeEntryID == reqValue)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (!hasTraitNodeEntry())
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerHasTraitNodeEntryInActiveConfigRankGreaterOrEqualThan: // 341
|
||||
{
|
||||
var traitNodeEntryRank = new Func<short?>(() =>
|
||||
{
|
||||
foreach (var traitConfig in referencePlayer.m_activePlayerData.TraitConfigs)
|
||||
{
|
||||
if ((TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat)
|
||||
{
|
||||
if (referencePlayer.m_activePlayerData.ActiveCombatTraitConfigID != traitConfig.ID
|
||||
|| !((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.ActiveForSpec))
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var traitEntry in traitConfig.Entries)
|
||||
if (traitEntry.TraitNodeEntryID == secondaryAsset)
|
||||
return (short)traitEntry.Rank;
|
||||
}
|
||||
return null;
|
||||
})();
|
||||
if (!traitNodeEntryRank.HasValue || traitNodeEntryRank < reqValue)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
case ModifierTreeType.PlayerDaysSinceLogout: // 344
|
||||
if (GameTime.GetGameTime() - referencePlayer.m_playerData.LogoutTime < reqValue * Time.Day)
|
||||
return false;
|
||||
break;
|
||||
case ModifierTreeType.PlayerCanUseItem: // 351
|
||||
{
|
||||
ItemTemplate itemTemplate = Global.ObjectMgr.GetItemTemplate(reqValue);
|
||||
if (itemTemplate == null || referencePlayer.CanUseItem(itemTemplate) != InventoryResult.Ok)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Game
|
||||
public string BuildItemAuctionMailSubject(AuctionMailType type, AuctionPosting auction)
|
||||
{
|
||||
return BuildAuctionMailSubject(auction.Items[0].GetEntry(), type, auction.Id, auction.GetTotalItemCount(),
|
||||
auction.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId), auction.Items[0].GetContext(), auction.Items[0].m_itemData.BonusListIDs);
|
||||
auction.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId), auction.Items[0].GetContext(), auction.Items[0].GetBonusListIDs());
|
||||
}
|
||||
|
||||
public string BuildCommodityAuctionMailSubject(AuctionMailType type, uint itemId, uint itemCount)
|
||||
@@ -1998,7 +1998,7 @@ namespace Game
|
||||
public class SubclassFilter
|
||||
{
|
||||
public FilterType SubclassMask;
|
||||
public uint[] InvTypes = new uint[ItemConst.MaxItemSubclassTotal];
|
||||
public ulong[] InvTypes = new ulong[ItemConst.MaxItemSubclassTotal];
|
||||
}
|
||||
|
||||
public enum FilterType : uint
|
||||
|
||||
@@ -860,12 +860,12 @@ namespace Game.BattleGrounds
|
||||
|
||||
public ushort GetMinPlayersPerTeam()
|
||||
{
|
||||
return BattlemasterEntry.MinPlayers;
|
||||
return (ushort)BattlemasterEntry.MinPlayers;
|
||||
}
|
||||
|
||||
public ushort GetMaxPlayersPerTeam()
|
||||
{
|
||||
return BattlemasterEntry.MaxPlayers;
|
||||
return (ushort)BattlemasterEntry.MaxPlayers;
|
||||
}
|
||||
|
||||
public byte GetMinLevel()
|
||||
|
||||
@@ -656,7 +656,7 @@ namespace Game
|
||||
var pMenuItemBounds = Global.ObjectMgr.GetGossipMenuItemsMapBounds(cond.SourceGroup);
|
||||
foreach (var gossipMenuItem in pMenuItemBounds)
|
||||
{
|
||||
if (gossipMenuItem.MenuId == cond.SourceGroup && gossipMenuItem.OptionId == cond.SourceEntry)
|
||||
if (gossipMenuItem.MenuID == cond.SourceGroup && gossipMenuItem.OrderIndex == cond.SourceEntry)
|
||||
{
|
||||
gossipMenuItem.Conditions.Add(cond);
|
||||
return true;
|
||||
@@ -2442,6 +2442,45 @@ namespace Game
|
||||
if (condition.CovenantID != 0 && player.m_playerData.CovenantID != condition.CovenantID)
|
||||
return false;
|
||||
|
||||
if (condition.TraitNodeEntryID.Any(traitNodeEntryId => traitNodeEntryId != 0))
|
||||
{
|
||||
var getTraitNodeEntryRank = ushort? (int traitNodeEntryId) =>
|
||||
{
|
||||
foreach (var traitConfig in player.m_activePlayerData.TraitConfigs)
|
||||
{
|
||||
if ((TraitConfigType)(int)traitConfig.Type == TraitConfigType.Combat)
|
||||
{
|
||||
if (player.m_activePlayerData.ActiveCombatTraitConfigID != traitConfig.ID
|
||||
|| !((TraitCombatConfigFlags)(int)traitConfig.CombatConfigFlags).HasFlag(TraitCombatConfigFlags.ActiveForSpec))
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var traitEntry in traitConfig.Entries)
|
||||
if (traitEntry.TraitNodeEntryID == traitNodeEntryId)
|
||||
return (ushort)traitEntry.Rank;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
results = new bool[condition.TraitNodeEntryID.Length];
|
||||
Array.Fill(results, true);
|
||||
for (var i = 0; i < condition.TraitNodeEntryID.Count(); ++i)
|
||||
{
|
||||
if (condition.TraitNodeEntryID[i] == 0)
|
||||
continue;
|
||||
|
||||
var rank = getTraitNodeEntryRank(condition.TraitNodeEntryID[i]);
|
||||
if (!rank.HasValue)
|
||||
results[i] = false;
|
||||
else if (condition.TraitNodeEntryMinRank[i] != 0 && rank < condition.TraitNodeEntryMinRank[i])
|
||||
results[i] = false;
|
||||
else if (condition.TraitNodeEntryMaxRank[i] != 0 && rank > condition.TraitNodeEntryMaxRank[i])
|
||||
results[i] = false;
|
||||
}
|
||||
|
||||
if (!PlayerConditionLogic(condition.TraitNodeEntryLogic, results))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -164,6 +164,7 @@ namespace Game.DataStorage
|
||||
GlyphBindableSpellStorage = ReadDB2<GlyphBindableSpellRecord>("GlyphBindableSpell.db2", HotfixStatements.SEL_GLYPH_BINDABLE_SPELL);
|
||||
GlyphPropertiesStorage = ReadDB2<GlyphPropertiesRecord>("GlyphProperties.db2", HotfixStatements.SEL_GLYPH_PROPERTIES);
|
||||
GlyphRequiredSpecStorage = ReadDB2<GlyphRequiredSpecRecord>("GlyphRequiredSpec.db2", HotfixStatements.SEL_GLYPH_REQUIRED_SPEC);
|
||||
GossipNPCOptionStorage = ReadDB2<GossipNPCOptionRecord>("GossipNPCOption.db2", HotfixStatements.SEL_GOSSIP_NPC_OPTION);
|
||||
GuildColorBackgroundStorage = ReadDB2<GuildColorBackgroundRecord>("GuildColorBackground.db2", HotfixStatements.SEL_GUILD_COLOR_BACKGROUND);
|
||||
GuildColorBorderStorage = ReadDB2<GuildColorBorderRecord>("GuildColorBorder.db2", HotfixStatements.SEL_GUILD_COLOR_BORDER);
|
||||
GuildColorEmblemStorage = ReadDB2<GuildColorEmblemRecord>("GuildColorEmblem.db2", HotfixStatements.SEL_GUILD_COLOR_EMBLEM);
|
||||
@@ -401,13 +402,13 @@ namespace Game.DataStorage
|
||||
}
|
||||
|
||||
// Check loaded DB2 files proper version
|
||||
if (!AreaTableStorage.ContainsKey(14083) || // last area added in 9.2.7 (45114)
|
||||
!CharTitlesStorage.ContainsKey(727) || // last char title added in 9.2.7 (45114)
|
||||
!GemPropertiesStorage.ContainsKey(3922) || // last gem property added in 9.2.7 (45114)
|
||||
!ItemStorage.ContainsKey(199202) || // last item added in 9.2.7 (45114)
|
||||
!ItemExtendedCostStorage.ContainsKey(7316) || // last item extended cost added in 9.2.7 (45114)
|
||||
!MapStorage.ContainsKey(2559) || // last map added in 9.2.7 (45114)
|
||||
!SpellNameStorage.ContainsKey(387936)) // last spell added in 9.2.7 (45114)
|
||||
if (!CliDB.AreaTableStorage.ContainsKey(14618) || // last area added in 10.0.2 (46741)
|
||||
!CliDB.CharTitlesStorage.ContainsKey(749) || // last char title added in 10.0.2 (46741)
|
||||
!CliDB.GemPropertiesStorage.ContainsKey(4028) || // last gem property added in 10.0.2 (46741)
|
||||
!CliDB.ItemStorage.ContainsKey(202712) || // last item added in 10.0.2 (46741)
|
||||
!CliDB.ItemExtendedCostStorage.ContainsKey(7862) || // last item extended cost added in 10.0.2 (46741)
|
||||
!CliDB.MapStorage.ContainsKey(2582) || // last map added in 10.0.2 (46741)
|
||||
!CliDB.SpellNameStorage.ContainsKey(399311)) // last spell added in 10.0.2 (46741)
|
||||
{
|
||||
Log.outError(LogFilter.Misc, "You have _outdated_ DB2 files. Please extract correct versions from current using client.");
|
||||
Global.WorldMgr.ShutdownServ(10, ShutdownMask.Force, ShutdownExitCode.Error);
|
||||
@@ -562,6 +563,7 @@ namespace Game.DataStorage
|
||||
public static DB6Storage<GlyphBindableSpellRecord> GlyphBindableSpellStorage;
|
||||
public static DB6Storage<GlyphPropertiesRecord> GlyphPropertiesStorage;
|
||||
public static DB6Storage<GlyphRequiredSpecRecord> GlyphRequiredSpecStorage;
|
||||
public static DB6Storage<GossipNPCOptionRecord> GossipNPCOptionStorage;
|
||||
public static DB6Storage<GuildColorBackgroundRecord> GuildColorBackgroundStorage;
|
||||
public static DB6Storage<GuildColorBorderRecord> GuildColorBorderStorage;
|
||||
public static DB6Storage<GuildColorEmblemRecord> GuildColorEmblemStorage;
|
||||
@@ -799,6 +801,10 @@ namespace Game.DataStorage
|
||||
return row.Druid;
|
||||
case Class.DemonHunter:
|
||||
return row.DemonHunter;
|
||||
case Class.Evoker:
|
||||
return row.Evoker;
|
||||
case Class.Adventurer:
|
||||
return row.Adventurer;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -834,6 +840,10 @@ namespace Game.DataStorage
|
||||
return row.Druid;
|
||||
case (int)Class.DemonHunter:
|
||||
return row.DemonHunter;
|
||||
case (int)Class.Evoker:
|
||||
return row.Evoker;
|
||||
case (int)Class.Adventurer:
|
||||
return row.Adventurer;
|
||||
case -1:
|
||||
case -7:
|
||||
return row.Item;
|
||||
@@ -851,6 +861,8 @@ namespace Game.DataStorage
|
||||
return row.DamageReplaceStat;
|
||||
case -9:
|
||||
return row.DamageSecondary;
|
||||
case -10:
|
||||
return row.ManaConsumable;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@ namespace Game.DataStorage
|
||||
if (battlemaster.MaxPlayers < battlemaster.MinPlayers)
|
||||
{
|
||||
Log.outError(LogFilter.ServerLoading, $"Battlemaster ({battlemaster.Id}) contains bad values for MinPlayers ({battlemaster.MinPlayers}) and MaxPlayers ({battlemaster.MaxPlayers}). Swapping values.");
|
||||
MathFunctions.Swap(ref battlemaster.MaxPlayers, ref battlemaster.MinPlayers);
|
||||
sbyte minPlayers = battlemaster.MinPlayers;
|
||||
battlemaster.MinPlayers = (sbyte)battlemaster.MaxPlayers;
|
||||
battlemaster.MaxPlayers = minPlayers;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,16 +198,16 @@ namespace Game.DataStorage
|
||||
ChrModelRecord model = ChrModelStorage.LookupByKey(raceModel.ChrModelID);
|
||||
if (model != null)
|
||||
{
|
||||
_chrModelsByRaceAndGender[Tuple.Create((byte)raceModel.ChrRacesID, (byte)model.Sex)] = model;
|
||||
_chrModelsByRaceAndGender[Tuple.Create((byte)raceModel.ChrRacesID, (byte)raceModel.Sex)] = model;
|
||||
|
||||
var customizationOptionsForModel = customizationOptionsByModel.LookupByKey(model.Id);
|
||||
if (customizationOptionsForModel != null)
|
||||
{
|
||||
_chrCustomizationOptionsByRaceAndGender.AddRange(Tuple.Create((byte)raceModel.ChrRacesID, (byte)model.Sex), customizationOptionsForModel);
|
||||
_chrCustomizationOptionsByRaceAndGender.AddRange(Tuple.Create((byte)raceModel.ChrRacesID, (byte)raceModel.Sex), customizationOptionsForModel);
|
||||
|
||||
uint parentRace = parentRaces.LookupByKey(raceModel.ChrRacesID);
|
||||
if (parentRace != 0)
|
||||
_chrCustomizationOptionsByRaceAndGender.AddRange(Tuple.Create((byte)parentRace, (byte)model.Sex), customizationOptionsForModel);
|
||||
_chrCustomizationOptionsByRaceAndGender.AddRange(Tuple.Create((byte)parentRace, (byte)raceModel.Sex), customizationOptionsForModel);
|
||||
}
|
||||
|
||||
// link shapeshift displays to race/gender/form
|
||||
@@ -220,7 +222,7 @@ namespace Game.DataStorage
|
||||
data.Displays.Add(displayInfoByCustomizationChoice.LookupByKey(data.Choices[i].Id));
|
||||
}
|
||||
|
||||
_chrCustomizationChoicesForShapeshifts[Tuple.Create((byte)raceModel.ChrRacesID, (byte)model.Sex, shapeshiftOptionsForModel.Item2)] = data;
|
||||
_chrCustomizationChoicesForShapeshifts[Tuple.Create((byte)raceModel.ChrRacesID, (byte)raceModel.Sex, shapeshiftOptionsForModel.Item2)] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2396,7 +2398,7 @@ namespace Game.DataStorage
|
||||
Dictionary<short, uint> _itemLevelDeltaToBonusListContainer = new();
|
||||
MultiMap<uint, ItemBonusTreeNodeRecord> _itemBonusTrees = new();
|
||||
Dictionary<uint, ItemChildEquipmentRecord> _itemChildEquipment = new();
|
||||
ItemClassRecord[] _itemClassByOldEnum = new ItemClassRecord[19];
|
||||
ItemClassRecord[] _itemClassByOldEnum = new ItemClassRecord[20];
|
||||
List<uint> _itemsWithCurrencyCost = new();
|
||||
MultiMap<uint, ItemLimitCategoryConditionRecord> _itemCategoryConditions = new();
|
||||
MultiMap<uint, ItemLevelSelectorQualityRecord> _itemLevelQualitySelectorQualities = new();
|
||||
|
||||
@@ -47,6 +47,7 @@ namespace Game.DataStorage
|
||||
public sealed class BattlePetBreedQualityRecord
|
||||
{
|
||||
public uint Id;
|
||||
public int MaxQualityRoll;
|
||||
public float StateMultiplier;
|
||||
public sbyte QualityEnum;
|
||||
}
|
||||
@@ -68,7 +69,7 @@ namespace Game.DataStorage
|
||||
public uint SummonSpellID;
|
||||
public int IconFileDataID;
|
||||
public sbyte PetTypeEnum;
|
||||
public ushort Flags;
|
||||
public int Flags;
|
||||
public sbyte SourceTypeEnum;
|
||||
public int CardUIModelSceneID;
|
||||
public int LoadoutUIModelSceneID;
|
||||
@@ -96,8 +97,8 @@ namespace Game.DataStorage
|
||||
public byte MinLevel;
|
||||
public byte MaxLevel;
|
||||
public sbyte RatedPlayers;
|
||||
public byte MinPlayers;
|
||||
public byte MaxPlayers;
|
||||
public sbyte MinPlayers;
|
||||
public int MaxPlayers;
|
||||
public sbyte GroupsAllowed;
|
||||
public sbyte MaxGroupSize;
|
||||
public ushort HolidayWorldState;
|
||||
|
||||
@@ -44,8 +44,8 @@ namespace Game.DataStorage
|
||||
public uint Id;
|
||||
public long RaceMask;
|
||||
public sbyte ChrClassID;
|
||||
public sbyte Purpose;
|
||||
public sbyte Unused910;
|
||||
public int Purpose;
|
||||
public sbyte ItemContext;
|
||||
|
||||
public bool IsForNewCharacter() { return Purpose == 9; }
|
||||
}
|
||||
@@ -131,6 +131,7 @@ namespace Game.DataStorage
|
||||
public uint Id;
|
||||
public uint ChrCustomizationOptionID;
|
||||
public uint ChrCustomizationReqID;
|
||||
public int ChrCustomizationVisReqID;
|
||||
public ushort SortOrder;
|
||||
public ushort UiOrderIndex;
|
||||
public int Flags;
|
||||
@@ -159,6 +160,7 @@ namespace Game.DataStorage
|
||||
public int ChrCustomizationCondModelID;
|
||||
public int ChrCustomizationDisplayInfoID;
|
||||
public int ChrCustItemGeoModifyID;
|
||||
public int ChrCustomizationVoiceID;
|
||||
}
|
||||
|
||||
public sealed class ChrCustomizationOptionRecord
|
||||
@@ -181,9 +183,11 @@ namespace Game.DataStorage
|
||||
public sealed class ChrCustomizationReqRecord
|
||||
{
|
||||
public uint Id;
|
||||
public string ReqSource;
|
||||
public int Flags;
|
||||
public int ClassMask;
|
||||
public int AchievementID;
|
||||
public int QuestID;
|
||||
public int OverrideArchive; // -1: allow any, otherwise must match OverrideArchive cvar
|
||||
public uint ItemModifiedAppearanceID;
|
||||
|
||||
@@ -223,6 +227,8 @@ namespace Game.DataStorage
|
||||
public uint Id;
|
||||
public int ChrRacesID;
|
||||
public int ChrModelID;
|
||||
public int Sex;
|
||||
public int AllowedTransmogSlots;
|
||||
}
|
||||
|
||||
public sealed class ChrRacesRecord
|
||||
@@ -273,6 +279,7 @@ namespace Game.DataStorage
|
||||
public float AlteredFormCustomizeRotationFallback;
|
||||
public float[] Unknown910_1 = new float[3];
|
||||
public float[] Unknown910_2 = new float[3];
|
||||
public int Unknown1000;
|
||||
public sbyte BaseLanguage;
|
||||
public sbyte CreatureType;
|
||||
public sbyte MaleModelFallbackSex;
|
||||
@@ -312,7 +319,7 @@ namespace Game.DataStorage
|
||||
public uint SoundID; // Sound ID (voiceover for cinematic)
|
||||
public float OriginFacing; // Orientation in map used for basis for M2 co
|
||||
public uint FileDataID; // Model
|
||||
public int Unknown915;
|
||||
public uint ConversationID;
|
||||
}
|
||||
|
||||
public sealed class CinematicSequencesRecord
|
||||
@@ -409,7 +416,7 @@ namespace Game.DataStorage
|
||||
public sbyte Gender;
|
||||
public int DissolveOutEffectID;
|
||||
public sbyte CreatureModelMinLod;
|
||||
public int[] TextureVariationFileDataID = new int[3];
|
||||
public int[] TextureVariationFileDataID = new int[4];
|
||||
}
|
||||
|
||||
public sealed class CreatureDisplayInfoExtraRecord
|
||||
@@ -542,6 +549,8 @@ namespace Game.DataStorage
|
||||
public int XpQuestDifficulty;
|
||||
public int AwardConditionID;
|
||||
public int MaxQtyWorldStateID;
|
||||
public uint RechargingAmountPerCycle;
|
||||
public uint RechargingCycleDurationMS;
|
||||
public int[] Flags = new int[2];
|
||||
}
|
||||
|
||||
@@ -554,9 +563,9 @@ namespace Game.DataStorage
|
||||
|
||||
public sealed class CurvePointRecord
|
||||
{
|
||||
public uint Id;
|
||||
public Vector2 Pos;
|
||||
public Vector2 PreSLSquishPos;
|
||||
public uint Id;
|
||||
public ushort CurveID;
|
||||
public byte OrderIndex;
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ namespace Game.DataStorage
|
||||
public int OrderIndex;
|
||||
public int CompleteWorldStateID;
|
||||
public sbyte Bit;
|
||||
public int CreatureDisplayID;
|
||||
public int Flags;
|
||||
public int SpellIconFileID;
|
||||
public int Faction;
|
||||
|
||||
@@ -29,8 +29,10 @@ namespace Game.DataStorage
|
||||
public ushort ParentFactionID;
|
||||
public byte Expansion;
|
||||
public uint FriendshipRepID;
|
||||
public byte Flags;
|
||||
public int Flags;
|
||||
public ushort ParagonFactionID;
|
||||
public int RenownFactionID;
|
||||
public int RenownCurrencyID;
|
||||
public short[] ReputationClassMask = new short[4];
|
||||
public ushort[] ReputationFlags = new ushort[4];
|
||||
public int[] ReputationBase = new int[4];
|
||||
@@ -47,14 +49,16 @@ namespace Game.DataStorage
|
||||
|
||||
public sealed class FactionTemplateRecord
|
||||
{
|
||||
static int MAX_FACTION_RELATIONS = 8;
|
||||
|
||||
public uint Id;
|
||||
public ushort Faction;
|
||||
public ushort Flags;
|
||||
public byte FactionGroup;
|
||||
public byte FriendGroup;
|
||||
public byte EnemyGroup;
|
||||
public ushort[] Enemies = new ushort[4];
|
||||
public ushort[] Friend = new ushort[4];
|
||||
public ushort[] Enemies = new ushort[MAX_FACTION_RELATIONS];
|
||||
public ushort[] Friend = new ushort[MAX_FACTION_RELATIONS];
|
||||
|
||||
// helpers
|
||||
public bool IsFriendlyTo(FactionTemplateRecord entry)
|
||||
@@ -64,10 +68,10 @@ namespace Game.DataStorage
|
||||
|
||||
if (entry.Faction != 0)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
|
||||
if (Enemies[i] == entry.Faction)
|
||||
return false;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
|
||||
if (Friend[i] == entry.Faction)
|
||||
return true;
|
||||
}
|
||||
@@ -80,10 +84,10 @@ namespace Game.DataStorage
|
||||
|
||||
if (entry.Faction != 0)
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
|
||||
if (Enemies[i] == entry.Faction)
|
||||
return true;
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
|
||||
if (Friend[i] == entry.Faction)
|
||||
return false;
|
||||
}
|
||||
@@ -92,7 +96,7 @@ namespace Game.DataStorage
|
||||
public bool IsHostileToPlayers() { return (EnemyGroup & (byte)FactionMasks.Player) != 0; }
|
||||
public bool IsNeutralToAll()
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
for (int i = 0; i < MAX_FACTION_RELATIONS; ++i)
|
||||
if (Enemies[i] != 0)
|
||||
return false;
|
||||
return EnemyGroup == 0 && FriendGroup == 0;
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace Game.DataStorage
|
||||
public ushort UiTextureKitID;
|
||||
public int GarrTalentTreeType;
|
||||
public int PlayerConditionID;
|
||||
public sbyte FeatureTypeIndex;
|
||||
public byte FeatureTypeIndex;
|
||||
public sbyte FeatureSubtypeIndex;
|
||||
public int CurrencyID;
|
||||
}
|
||||
@@ -312,6 +312,26 @@ namespace Game.DataStorage
|
||||
public uint GlyphPropertiesID;
|
||||
}
|
||||
|
||||
public sealed class GossipNPCOptionRecord
|
||||
{
|
||||
public uint Id;
|
||||
public int GossipNpcOption;
|
||||
public int LFGDungeonsID;
|
||||
public int TrainerID;
|
||||
public int GarrFollowerTypeID;
|
||||
public int CharShipmentID;
|
||||
public int GarrTalentTreeID;
|
||||
public int UiMapID;
|
||||
public int UiItemInteractionID;
|
||||
public int Unknown_1000_8;
|
||||
public int Unknown_1000_9;
|
||||
public int CovenantID;
|
||||
public int GossipOptionID;
|
||||
public int TraitTreeID;
|
||||
public int ProfessionID;
|
||||
public int Unknown_1002_14;
|
||||
}
|
||||
|
||||
public sealed class GuildColorBackgroundRecord
|
||||
{
|
||||
public uint Id;
|
||||
|
||||
@@ -47,6 +47,8 @@ namespace Game.DataStorage
|
||||
public float DeathKnight;
|
||||
public float Monk;
|
||||
public float DemonHunter;
|
||||
public float Evoker;
|
||||
public float Adventurer;
|
||||
}
|
||||
|
||||
public sealed class GtBattlePetXPRecord
|
||||
@@ -128,6 +130,8 @@ namespace Game.DataStorage
|
||||
public float DeathKnight;
|
||||
public float Monk;
|
||||
public float DemonHunter;
|
||||
public float Evoker;
|
||||
public float Adventurer;
|
||||
public float Item;
|
||||
public float Consumable;
|
||||
public float Gem1;
|
||||
@@ -136,6 +140,7 @@ namespace Game.DataStorage
|
||||
public float Health;
|
||||
public float DamageReplaceStat;
|
||||
public float DamageSecondary;
|
||||
public float ManaConsumable;
|
||||
}
|
||||
|
||||
public sealed class GtXpRecord
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace Game.DataStorage
|
||||
public byte ItemGroupSoundsID;
|
||||
public int ContentTuningID;
|
||||
public int ModifiedCraftingReagentItemID;
|
||||
public int CraftingQualityID;
|
||||
}
|
||||
|
||||
public sealed class ItemAppearanceRecord
|
||||
@@ -215,7 +216,7 @@ namespace Game.DataStorage
|
||||
public byte ArenaBracket; // arena slot restrictions (min slot value)
|
||||
public byte Flags;
|
||||
public byte MinFactionID;
|
||||
public byte MinReputation;
|
||||
public int MinReputation;
|
||||
public byte RequiredAchievement; // required personal arena rating
|
||||
public uint[] ItemID = new uint[ItemConst.MaxItemExtCostItems]; // required item id
|
||||
public ushort[] ItemCount = new ushort[ItemConst.MaxItemExtCostItems]; // required count of 1st item
|
||||
@@ -305,7 +306,7 @@ namespace Game.DataStorage
|
||||
public byte OverallQualityID;
|
||||
public int ExpansionID;
|
||||
public ushort MinFactionID;
|
||||
public byte MinReputation;
|
||||
public int MinReputation;
|
||||
public int AllowableClass;
|
||||
public sbyte RequiredLevel;
|
||||
public ushort RequiredSkill;
|
||||
@@ -356,6 +357,7 @@ namespace Game.DataStorage
|
||||
public int[] StatPercentEditor = new int[ItemConst.MaxStats];
|
||||
public uint Stackable;
|
||||
public uint MaxCount;
|
||||
public uint MinReputation;
|
||||
public uint RequiredAbility;
|
||||
public uint SellPrice;
|
||||
public uint BuyPrice;
|
||||
@@ -395,7 +397,6 @@ namespace Game.DataStorage
|
||||
public byte DamageType;
|
||||
public sbyte[] StatModifierBonusStat = new sbyte[ItemConst.MaxStats];
|
||||
public byte ContainerSlots;
|
||||
public byte MinReputation;
|
||||
public byte RequiredPVPMedal;
|
||||
public byte RequiredPVPRank;
|
||||
public sbyte RequiredLevel;
|
||||
|
||||
@@ -65,7 +65,6 @@ namespace Game.DataStorage
|
||||
public int ButtonFileDataID;
|
||||
public int ButtonSmallFileDataID;
|
||||
public int LoreFileDataID;
|
||||
public byte OrderIndex;
|
||||
public int Flags;
|
||||
public ushort AreaID;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace Game.DataStorage
|
||||
public short WindSettingsID;
|
||||
public int ZmpFileDataID;
|
||||
public int WdtFileDataID;
|
||||
public int NavigationMaxDistance;
|
||||
public uint[] Flags = new uint[3];
|
||||
|
||||
// Helpers
|
||||
@@ -98,6 +99,7 @@ namespace Game.DataStorage
|
||||
case 1642:
|
||||
case 1643:
|
||||
case 2222:
|
||||
case 2444:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
@@ -107,7 +109,7 @@ namespace Game.DataStorage
|
||||
public bool IsDynamicDifficultyMap() { return GetFlags().HasFlag(MapFlags.DynamicDifficulty); }
|
||||
public bool IsFlexLocking() { return GetFlags().HasFlag(MapFlags.FlexibleRaidLocking); }
|
||||
public bool IsGarrison() { return GetFlags().HasFlag(MapFlags.Garrison); }
|
||||
public bool IsSplitByFaction() { return Id == 609 || Id == 2175; }
|
||||
public bool IsSplitByFaction() { return Id == 609 || Id == 2175 || Id == 2570; }
|
||||
|
||||
public MapFlags GetFlags() { return (MapFlags)Flags[0]; }
|
||||
public MapFlags2 GetFlags2() { return (MapFlags2)Flags[1]; }
|
||||
@@ -213,6 +215,7 @@ namespace Game.DataStorage
|
||||
public uint ModSpellAuraID;
|
||||
public short ReqMapID;
|
||||
public int PlayerConditionID;
|
||||
public int FlightCapabilityID;
|
||||
}
|
||||
|
||||
public sealed class MountTypeXCapabilityRecord
|
||||
|
||||
@@ -99,6 +99,7 @@ namespace Game.DataStorage
|
||||
public byte MaxPVPRank;
|
||||
public uint ContentTuningID;
|
||||
public int CovenantID;
|
||||
public uint TraitNodeEntryLogic;
|
||||
public ushort[] SkillID = new ushort[4];
|
||||
public ushort[] MinSkill = new ushort[4];
|
||||
public ushort[] MaxSkill = new ushort[4];
|
||||
@@ -123,6 +124,9 @@ namespace Game.DataStorage
|
||||
public uint[] CurrencyCount = new uint[4];
|
||||
public uint[] QuestKillMonster = new uint[6];
|
||||
public int[] MovementFlags = new int[2];
|
||||
public int[]TraitNodeEntryID = new int[4];
|
||||
public ushort[]TraitNodeEntryMinRank = new ushort[4];
|
||||
public ushort[]TraitNodeEntryMaxRank = new ushort[4];
|
||||
}
|
||||
|
||||
public sealed class PowerDisplayRecord
|
||||
@@ -141,12 +145,12 @@ namespace Game.DataStorage
|
||||
public string CostGlobalStringTag;
|
||||
public uint Id;
|
||||
public PowerType PowerTypeEnum;
|
||||
public sbyte MinPower;
|
||||
public short MaxBasePower;
|
||||
public sbyte CenterPower;
|
||||
public sbyte DefaultPower;
|
||||
public sbyte DisplayModifier;
|
||||
public short RegenInterruptTimeMS;
|
||||
public int MinPower;
|
||||
public int MaxBasePower;
|
||||
public int CenterPower;
|
||||
public int DefaultPower;
|
||||
public int DisplayModifier;
|
||||
public int RegenInterruptTimeMS;
|
||||
public float RegenPeace;
|
||||
public float RegenCombat;
|
||||
public short Flags;
|
||||
@@ -197,6 +201,7 @@ namespace Game.DataStorage
|
||||
public int ActionBarSpellID;
|
||||
public int PvpTalentCategoryID;
|
||||
public int LevelRequired;
|
||||
public int PlayerConditionID;
|
||||
}
|
||||
|
||||
public sealed class PvpTalentCategoryRecord
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Game.DataStorage
|
||||
public LocalizedString InfoName;
|
||||
public sbyte Type;
|
||||
public int Modifiers;
|
||||
public ushort Profession;
|
||||
public int Profession;
|
||||
}
|
||||
|
||||
public sealed class QuestLineXQuestRecord
|
||||
@@ -69,6 +69,7 @@ namespace Game.DataStorage
|
||||
{
|
||||
public uint Id;
|
||||
public ushort UniqueBitFlag;
|
||||
public int UiQuestDetailsTheme;
|
||||
}
|
||||
|
||||
public sealed class QuestXPRecord
|
||||
|
||||
@@ -97,6 +97,8 @@ namespace Game.DataStorage
|
||||
public int ParentTierIndex;
|
||||
public ushort Flags;
|
||||
public int SpellBookSpellID;
|
||||
public int ExpansionNameSharedStringID;
|
||||
public int HordeExpansionNameSharedStringID;
|
||||
|
||||
public SkillLineFlags GetFlags() => (SkillLineFlags)Flags;
|
||||
}
|
||||
@@ -104,6 +106,8 @@ namespace Game.DataStorage
|
||||
public sealed class SkillLineAbilityRecord
|
||||
{
|
||||
public long RaceMask;
|
||||
public string AbilityVerb;
|
||||
public string AbilityAllVerb;
|
||||
public uint Id;
|
||||
public ushort SkillLine;
|
||||
public uint Spell;
|
||||
@@ -146,7 +150,7 @@ namespace Game.DataStorage
|
||||
public uint Id;
|
||||
public uint SoundType;
|
||||
public float VolumeFloat;
|
||||
public ushort Flags;
|
||||
public int Flags;
|
||||
public float MinDistance;
|
||||
public float DistanceCutoff;
|
||||
public byte EAXDef;
|
||||
@@ -159,6 +163,7 @@ namespace Game.DataStorage
|
||||
public float PitchAdjust;
|
||||
public ushort BusOverwriteID;
|
||||
public byte MaxInstances;
|
||||
public uint SoundMixGroupID;
|
||||
}
|
||||
|
||||
public sealed class SpecializationSpellsRecord
|
||||
@@ -194,15 +199,19 @@ namespace Game.DataStorage
|
||||
public sealed class SpellAuraRestrictionsRecord
|
||||
{
|
||||
public uint Id;
|
||||
public byte DifficultyID;
|
||||
public byte CasterAuraState;
|
||||
public byte TargetAuraState;
|
||||
public byte ExcludeCasterAuraState;
|
||||
public byte ExcludeTargetAuraState;
|
||||
public uint DifficultyID;
|
||||
public int CasterAuraState;
|
||||
public int TargetAuraState;
|
||||
public int ExcludeCasterAuraState;
|
||||
public int ExcludeTargetAuraState;
|
||||
public uint CasterAuraSpell;
|
||||
public uint TargetAuraSpell;
|
||||
public uint ExcludeCasterAuraSpell;
|
||||
public uint ExcludeTargetAuraSpell;
|
||||
public int CasterAuraType;
|
||||
public int TargetAuraType;
|
||||
public int ExcludeCasterAuraType;
|
||||
public int ExcludeTargetAuraType;
|
||||
public uint SpellID;
|
||||
}
|
||||
|
||||
@@ -219,7 +228,7 @@ namespace Game.DataStorage
|
||||
public uint SpellID;
|
||||
public byte FacingCasterFlags;
|
||||
public ushort MinFactionID;
|
||||
public sbyte MinReputation;
|
||||
public int MinReputation;
|
||||
public ushort RequiredAreasID;
|
||||
public byte RequiredAuraVision;
|
||||
public ushort RequiresSpellFocus;
|
||||
@@ -266,6 +275,7 @@ namespace Game.DataStorage
|
||||
public uint CategoryRecoveryTime;
|
||||
public uint RecoveryTime;
|
||||
public uint StartRecoveryTime;
|
||||
public uint AuraSpellID;
|
||||
public uint SpellID;
|
||||
}
|
||||
|
||||
@@ -340,6 +350,7 @@ namespace Game.DataStorage
|
||||
public uint Id;
|
||||
public string Name;
|
||||
public string HordeName;
|
||||
public int Duration;
|
||||
public uint[] EffectArg = new uint[ItemConst.MaxItemEnchantmentEffects];
|
||||
public float[] EffectScalingPoints = new float[ItemConst.MaxItemEnchantmentEffects];
|
||||
public uint IconFileDataID;
|
||||
@@ -439,6 +450,7 @@ namespace Game.DataStorage
|
||||
public int AltPowerBarID;
|
||||
public float PowerCostPct;
|
||||
public float PowerCostMaxPct;
|
||||
public float OptionalCostPct;
|
||||
public float PowerPctPerSecond;
|
||||
public PowerType PowerType;
|
||||
public uint RequiredAuraSpellID;
|
||||
@@ -495,6 +507,8 @@ namespace Game.DataStorage
|
||||
public uint SpellID;
|
||||
public int[] Reagent = new int[SpellConst.MaxReagents];
|
||||
public ushort[] ReagentCount = new ushort[SpellConst.MaxReagents];
|
||||
public short[] ReagentRecraftCount = new short[SpellConst.MaxReagents];
|
||||
public byte[] ReagentSource = new byte[SpellConst.MaxReagents];
|
||||
}
|
||||
|
||||
public sealed class SpellReagentsCurrencyRecord
|
||||
@@ -638,6 +652,7 @@ namespace Game.DataStorage
|
||||
public byte DifficultyID;
|
||||
public uint SpellVisualID;
|
||||
public float Probability;
|
||||
public int Flags;
|
||||
public int Priority;
|
||||
public int SpellIconFileID;
|
||||
public int ActiveIconFileID;
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Game.DataStorage
|
||||
public int ParentUiMapID;
|
||||
public int OrderIndex;
|
||||
public int ChildUiMapID;
|
||||
public int PlayerConditionID;
|
||||
public int OverrideHighlightFileDataID;
|
||||
public int OverrideHighlightAtlasID;
|
||||
public int Flags;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -380,6 +380,8 @@ namespace Game
|
||||
if (!result.IsEmpty())
|
||||
{
|
||||
Dictionary<byte, Dictionary<byte, Tuple<byte, byte>>> temp = new();
|
||||
byte[] minRequirementForClass = new byte[(int)Class.Max];
|
||||
Array.Fill(minRequirementForClass, (byte)Expansion.Max);
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
@@ -418,6 +420,7 @@ namespace Game
|
||||
temp[raceID] = new Dictionary<byte, Tuple<byte, byte>>();
|
||||
|
||||
temp[raceID][classID] = Tuple.Create(activeExpansionLevel, accountExpansionLevel);
|
||||
minRequirementForClass[classID] = Math.Min(minRequirementForClass[classID], activeExpansionLevel);
|
||||
|
||||
++count;
|
||||
}
|
||||
@@ -434,6 +437,7 @@ namespace Game
|
||||
classAvailability.ClassID = class_.Key;
|
||||
classAvailability.ActiveExpansionLevel = class_.Value.Item1;
|
||||
classAvailability.AccountExpansionLevel = class_.Value.Item2;
|
||||
classAvailability.MinActiveExpansionLevel = minRequirementForClass[class_.Key];
|
||||
|
||||
raceClassAvailability.Classes.Add(classAvailability);
|
||||
}
|
||||
@@ -530,6 +534,15 @@ namespace Game
|
||||
|
||||
return classAvailability;
|
||||
}
|
||||
public ClassAvailability GetClassExpansionRequirementFallback(byte classId)
|
||||
{
|
||||
foreach (RaceClassAvailability raceClassAvailability in _classExpansionRequirementStorage)
|
||||
foreach (ClassAvailability classAvailability in raceClassAvailability.Classes)
|
||||
if (classAvailability.ClassID == classId)
|
||||
return classAvailability;
|
||||
|
||||
return null;
|
||||
}
|
||||
public PlayerChoice GetPlayerChoice(int choiceId)
|
||||
{
|
||||
return _playerChoices.LookupByKey(choiceId);
|
||||
@@ -578,9 +591,10 @@ namespace Game
|
||||
|
||||
gossipMenuItemsStorage.Clear();
|
||||
|
||||
// 0 1 2 3 4 5 6 7 8 9 10 11
|
||||
SQLResult result = DB.World.Query("SELECT MenuID, OptionID, OptionNpc, OptionText, OptionBroadcastTextID, Language, ActionMenuID, ActionPoiID, BoxCoded, BoxMoney, BoxText, BoxBroadcastTextID " +
|
||||
"FROM gossip_menu_option ORDER BY MenuID, OptionID");
|
||||
// 0 1 2 3 4 5 6 7 8 9 10
|
||||
SQLResult result = DB.World.Query("SELECT MenuID, GossipOptionID, OptionID, OptionNpc, OptionText, OptionBroadcastTextID, Language, Flags, ActionMenuID, ActionPoiID, GossipNpcOptionID, " +
|
||||
//11 12 13 14 15 16
|
||||
"BoxCoded, BoxMoney, BoxText, BoxBroadcastTextID, SpellID, OverrideIconID FROM gossip_menu_option ORDER BY MenuID, OptionID");
|
||||
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
@@ -588,26 +602,40 @@ namespace Game
|
||||
return;
|
||||
}
|
||||
|
||||
Dictionary<int, uint> optionToNpcOption = new();
|
||||
foreach (var (_, npcOption) in CliDB.GossipNPCOptionStorage)
|
||||
optionToNpcOption[npcOption.GossipOptionID] = npcOption.Id;
|
||||
|
||||
do
|
||||
{
|
||||
GossipMenuItems gMenuItem = new();
|
||||
|
||||
gMenuItem.MenuId = result.Read<uint>(0);
|
||||
gMenuItem.OptionId = result.Read<uint>(1);
|
||||
gMenuItem.OptionNpc = (GossipOptionNpc)result.Read<byte>(2);
|
||||
gMenuItem.OptionText = result.Read<string>(3);
|
||||
gMenuItem.OptionBroadcastTextId = result.Read<uint>(4);
|
||||
gMenuItem.Language = result.Read<uint>(5);
|
||||
gMenuItem.ActionMenuId = result.Read<uint>(6);
|
||||
gMenuItem.ActionPoiId = result.Read<uint>(7);
|
||||
gMenuItem.BoxCoded = result.Read<bool>(8);
|
||||
gMenuItem.BoxMoney = result.Read<uint>(9);
|
||||
gMenuItem.BoxText = result.Read<string>(10);
|
||||
gMenuItem.BoxBroadcastTextId = result.Read<uint>(11);
|
||||
gMenuItem.MenuID = result.Read<uint>(0);
|
||||
gMenuItem.GossipOptionID = result.Read<int>(1);
|
||||
gMenuItem.OrderIndex = result.Read<uint>(2);
|
||||
gMenuItem.OptionNpc = (GossipOptionNpc)result.Read<byte>(3);
|
||||
gMenuItem.OptionText = result.Read<string>(4);
|
||||
gMenuItem.OptionBroadcastTextId = result.Read<uint>(5);
|
||||
gMenuItem.Language = result.Read<uint>(6);
|
||||
gMenuItem.Flags = (GossipOptionFlags)result.Read<int>(7);
|
||||
gMenuItem.ActionMenuID = result.Read<uint>(8);
|
||||
gMenuItem.ActionPoiID = result.Read<uint>(9);
|
||||
if (!result.IsNull(10))
|
||||
gMenuItem.GossipNpcOptionID = result.Read<int>(10);
|
||||
|
||||
gMenuItem.BoxCoded = result.Read<bool>(11);
|
||||
gMenuItem.BoxMoney = result.Read<uint>(12);
|
||||
gMenuItem.BoxText = result.Read<string>(13);
|
||||
gMenuItem.BoxBroadcastTextId = result.Read<uint>(14);
|
||||
if (!result.IsNull(15))
|
||||
gMenuItem.SpellID = result.Read<int>(15);
|
||||
|
||||
if (!result.IsNull(16))
|
||||
gMenuItem.OverrideIconID = result.Read<int>(16);
|
||||
|
||||
if (gMenuItem.OptionNpc >= GossipOptionNpc.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuId}, id {gMenuItem.OptionId} has unknown NPC option id {gMenuItem.OptionNpc}. Replacing with GossipOptionNpc.None");
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} has unknown NPC option id {gMenuItem.OptionNpc}. Replacing with GossipOptionNpc.None");
|
||||
gMenuItem.OptionNpc = GossipOptionNpc.None;
|
||||
}
|
||||
|
||||
@@ -615,47 +643,71 @@ namespace Game
|
||||
{
|
||||
if (!CliDB.BroadcastTextStorage.ContainsKey(gMenuItem.OptionBroadcastTextId))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for MenuId {gMenuItem.MenuId}, OptionIndex {gMenuItem.OptionId} has non-existing or incompatible OptionBroadcastTextId {gMenuItem.OptionBroadcastTextId}, ignoring.");
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for MenuId {gMenuItem.MenuID}, OptionIndex {gMenuItem.OrderIndex} has non-existing or incompatible OptionBroadcastTextId {gMenuItem.OptionBroadcastTextId}, ignoring.");
|
||||
gMenuItem.OptionBroadcastTextId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gMenuItem.Language != 0 && !CliDB.LanguagesStorage.ContainsKey(gMenuItem.Language))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuId}, id {gMenuItem.OptionId} use non-existing Language {gMenuItem.Language}, ignoring");
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} use non-existing Language {gMenuItem.Language}, ignoring");
|
||||
gMenuItem.Language = 0;
|
||||
}
|
||||
|
||||
if (gMenuItem.ActionMenuId != 0 && gMenuItem.OptionNpc != GossipOptionNpc.None)
|
||||
if (gMenuItem.ActionMenuID != 0 && gMenuItem.OptionNpc != GossipOptionNpc.None)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuId}, id {gMenuItem.OptionId} can not use ActionMenuID for GossipOptionNpc different from GossipOptionNpc.None, ignoring");
|
||||
gMenuItem.ActionMenuId = 0;
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} can not use ActionMenuID for GossipOptionNpc different from GossipOptionNpc.None, ignoring");
|
||||
gMenuItem.ActionMenuID = 0;
|
||||
}
|
||||
|
||||
if (gMenuItem.ActionPoiId != 0)
|
||||
if (gMenuItem.ActionPoiID != 0)
|
||||
{
|
||||
if (gMenuItem.OptionNpc != GossipOptionNpc.None)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuId}, id {gMenuItem.OptionId} can not use ActionPoiID for GossipOptionNpc different from GossipOptionNpc.None, ignoring");
|
||||
gMenuItem.ActionPoiId = 0;
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} can not use ActionPoiID for GossipOptionNpc different from GossipOptionNpc.None, ignoring");
|
||||
gMenuItem.ActionPoiID = 0;
|
||||
}
|
||||
else if (GetPointOfInterest(gMenuItem.ActionPoiId) == null)
|
||||
else if (GetPointOfInterest(gMenuItem.ActionPoiID) == null)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuId}, id {gMenuItem.OptionId} use non-existing ActionPoiID {gMenuItem.ActionPoiId}, ignoring");
|
||||
gMenuItem.ActionPoiId = 0;
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} use non-existing ActionPoiID {gMenuItem.ActionPoiID}, ignoring");
|
||||
gMenuItem.ActionPoiID = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (gMenuItem.GossipNpcOptionID.HasValue)
|
||||
{
|
||||
if (!CliDB.GossipNPCOptionStorage.ContainsKey(gMenuItem.GossipNpcOptionID.Value))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} use non-existing GossipNPCOption {gMenuItem.GossipNpcOptionID}, ignoring");
|
||||
gMenuItem.GossipNpcOptionID = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uint npcOptionId = optionToNpcOption.LookupByKey(gMenuItem.GossipOptionID);
|
||||
if (npcOptionId != 0)
|
||||
gMenuItem.GossipNpcOptionID = (int)npcOptionId;
|
||||
}
|
||||
|
||||
if (gMenuItem.BoxBroadcastTextId != 0)
|
||||
{
|
||||
if (!CliDB.BroadcastTextStorage.ContainsKey(gMenuItem.BoxBroadcastTextId))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for MenuId {gMenuItem.MenuId}, OptionIndex {gMenuItem.OptionId} has non-existing or incompatible BoxBroadcastTextId {gMenuItem.BoxBroadcastTextId}, ignoring.");
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for MenuId {gMenuItem.MenuID}, OptionIndex {gMenuItem.OrderIndex} has non-existing or incompatible BoxBroadcastTextId {gMenuItem.BoxBroadcastTextId}, ignoring.");
|
||||
gMenuItem.BoxBroadcastTextId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gossipMenuItemsStorage.Add(gMenuItem.MenuId, gMenuItem);
|
||||
if (gMenuItem.SpellID.HasValue)
|
||||
{
|
||||
if (!Global.SpellMgr.HasSpellInfo((uint)gMenuItem.SpellID.Value, Difficulty.None))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `gossip_menu_option` for menu {gMenuItem.MenuID}, id {gMenuItem.OrderIndex} use non-existing Spell {gMenuItem.SpellID}, ignoring");
|
||||
gMenuItem.SpellID = null;
|
||||
}
|
||||
}
|
||||
|
||||
gossipMenuItemsStorage.Add(gMenuItem.MenuID, gMenuItem);
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, $"Loaded {gossipMenuItemsStorage.Count} gossip_menu_option entries in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
|
||||
@@ -700,42 +752,6 @@ namespace Game
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, $"Loaded {_gossipMenuAddonStorage.Count} gossip_menu_addon IDs in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
|
||||
}
|
||||
public void LoadGossipMenuItemAddon()
|
||||
{
|
||||
uint oldMSTime = Time.GetMSTime();
|
||||
|
||||
_gossipMenuItemAddonStorage.Clear();
|
||||
|
||||
// 0 1 2
|
||||
SQLResult result = DB.World.Query("SELECT MenuID, OptionId, GarrTalentTreeID FROM gossip_menu_option_addon");
|
||||
if (result.IsEmpty())
|
||||
{
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loaded 0 gossip_menu_option_addon IDs. DB table `gossip_menu_option_addon` is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
uint menuId = result.Read<uint>(0);
|
||||
uint optionId = result.Read<uint>(1);
|
||||
GossipMenuItemAddon addon = new();
|
||||
if (!result.IsNull(2))
|
||||
{
|
||||
addon.GarrTalentTreeID = result.Read<int>(2);
|
||||
|
||||
if (!CliDB.GarrTalentTreeStorage.ContainsKey(addon.GarrTalentTreeID.Value))
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table gossip_menu_option_addon: MenuID {menuId} OptionID {optionId} is using non-existing GarrTalentTree {addon.GarrTalentTreeID.Value}");
|
||||
addon.GarrTalentTreeID = null;
|
||||
}
|
||||
}
|
||||
|
||||
_gossipMenuItemAddonStorage[Tuple.Create(menuId, optionId)] = addon;
|
||||
|
||||
} while (result.NextRow());
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, $"Loaded {_gossipMenuItemAddonStorage.Count} gossip_menu_option_addon IDs in {Time.GetMSTimeDiffToNow(oldMSTime)} ms");
|
||||
}
|
||||
|
||||
public void LoadPointsOfInterest()
|
||||
{
|
||||
@@ -791,10 +807,6 @@ namespace Game
|
||||
{
|
||||
return _gossipMenuAddonStorage.LookupByKey(menuId);
|
||||
}
|
||||
public GossipMenuItemAddon GetGossipMenuItemAddon(uint menuId, uint optionId)
|
||||
{
|
||||
return _gossipMenuItemAddonStorage.LookupByKey(Tuple.Create(menuId, optionId));
|
||||
}
|
||||
public PointOfInterest GetPointOfInterest(uint id)
|
||||
{
|
||||
return pointsOfInterestStorage.LookupByKey(id);
|
||||
@@ -3392,7 +3404,7 @@ namespace Game
|
||||
var gossipMenuItems = GetGossipMenuItemsMapBounds(gossipMenuId);
|
||||
var gossipOptionItr = gossipMenuItems.Find(entry =>
|
||||
{
|
||||
return entry.OptionId == gossipOptionIndex;
|
||||
return entry.OrderIndex == gossipOptionIndex;
|
||||
});
|
||||
|
||||
if (gossipOptionItr == null)
|
||||
@@ -4999,6 +5011,12 @@ namespace Game
|
||||
0.00f, // INVTYPE_RANGEDRIGHT
|
||||
0.00f, // INVTYPE_QUIVER
|
||||
0.00f, // INVTYPE_RELIC
|
||||
0.00f, // INVTYPE_PROFESSION_TOOL
|
||||
0.00f, // INVTYPE_PROFESSION_GEAR
|
||||
0.00f, // INVTYPE_EQUIPABLE_SPELL_OFFENSIVE
|
||||
0.00f, // INVTYPE_EQUIPABLE_SPELL_UTILITY
|
||||
0.00f, // INVTYPE_EQUIPABLE_SPELL_DEFENSIVE
|
||||
0.00f, // INVTYPE_EQUIPABLE_SPELL_MOBILITY
|
||||
};
|
||||
|
||||
static float[] weaponMultipliers = new float[]
|
||||
@@ -5944,9 +5962,6 @@ namespace Game
|
||||
//Player
|
||||
public void LoadPlayerInfo()
|
||||
{
|
||||
for (uint race = 0; race < (int)Race.Max; ++race)
|
||||
_playerInfo[race] = new PlayerInfo[(int)Class.Max];
|
||||
|
||||
var time = Time.GetMSTime();
|
||||
// Load playercreate
|
||||
{
|
||||
@@ -6059,7 +6074,7 @@ namespace Game
|
||||
Log.outError(LogFilter.Sql, $"Invalid NPE intro scene id {introSceneId} for class {currentclass} race {currentrace} pair in `playercreateinfo` table, ignoring.");
|
||||
}
|
||||
|
||||
_playerInfo[currentrace][currentclass] = info;
|
||||
_playerInfo[Tuple.Create((Race)currentrace, (Class)currentclass)] = info;
|
||||
|
||||
++count;
|
||||
} while (result.NextRow());
|
||||
@@ -6092,9 +6107,11 @@ namespace Game
|
||||
if (!characterLoadout.RaceMask.HasAnyFlag(SharedConst.GetMaskForRace(raceIndex)))
|
||||
continue;
|
||||
|
||||
PlayerInfo playerInfo = _playerInfo[(int)raceIndex][characterLoadout.ChrClassID];
|
||||
var playerInfo = _playerInfo.LookupByKey(Tuple.Create((Race)raceIndex, (Class)characterLoadout.ChrClassID));
|
||||
if (playerInfo != null)
|
||||
{
|
||||
playerInfo.itemContext = (ItemContext)characterLoadout.ItemContext;
|
||||
|
||||
foreach (ItemTemplate itemTemplate in items)
|
||||
{
|
||||
// BuyCount by default
|
||||
@@ -6200,11 +6217,11 @@ namespace Game
|
||||
{
|
||||
if (rcInfo.RaceMask == -1 || Convert.ToBoolean(SharedConst.GetMaskForRace(raceIndex) & rcInfo.RaceMask))
|
||||
{
|
||||
for (int classIndex = (int)Class.Warrior; classIndex < (int)Class.Max; ++classIndex)
|
||||
for (Class classIndex = Class.Warrior; classIndex < Class.Max; ++classIndex)
|
||||
{
|
||||
if (rcInfo.ClassMask == -1 || Convert.ToBoolean((1 << (classIndex - 1)) & rcInfo.ClassMask))
|
||||
if (rcInfo.ClassMask == -1 || Convert.ToBoolean((1 << ((int)classIndex - 1)) & rcInfo.ClassMask))
|
||||
{
|
||||
PlayerInfo info = _playerInfo[(int)raceIndex][classIndex];
|
||||
PlayerInfo info = _playerInfo.LookupByKey(Tuple.Create(raceIndex, classIndex));
|
||||
if (info != null)
|
||||
info.skills.Add(rcInfo);
|
||||
}
|
||||
@@ -6251,14 +6268,14 @@ namespace Game
|
||||
{
|
||||
if (raceMask == 0 || Convert.ToBoolean((ulong)SharedConst.GetMaskForRace(raceIndex) & raceMask))
|
||||
{
|
||||
for (int classIndex = (int)Class.Warrior; classIndex < (int)Class.Max; ++classIndex)
|
||||
for (Class classIndex = Class.Warrior; classIndex < Class.Max; ++classIndex)
|
||||
{
|
||||
if (classMask == 0 || Convert.ToBoolean((1 << (classIndex - 1)) & classMask))
|
||||
if (classMask == 0 || Convert.ToBoolean((1 << ((int)classIndex - 1)) & classMask))
|
||||
{
|
||||
PlayerInfo info = _playerInfo[(int)raceIndex][classIndex];
|
||||
if (info != null)
|
||||
PlayerInfo playerInfo = _playerInfo.LookupByKey(Tuple.Create(raceIndex, classIndex));
|
||||
if (playerInfo != null)
|
||||
{
|
||||
info.customSpells.Add(spellId);
|
||||
playerInfo.customSpells.Add(spellId);
|
||||
++count;
|
||||
}
|
||||
// We need something better here, the check is not accounting for spells used by multiple races/classes but not all of them.
|
||||
@@ -6316,11 +6333,11 @@ namespace Game
|
||||
{
|
||||
if (raceMask == 0 || Convert.ToBoolean((ulong)SharedConst.GetMaskForRace(raceIndex) & raceMask))
|
||||
{
|
||||
for (int classIndex = (int)Class.Warrior; classIndex < (int)Class.Max; ++classIndex)
|
||||
for (Class classIndex = Class.Warrior; classIndex < Class.Max; ++classIndex)
|
||||
{
|
||||
if (classMask == 0 || Convert.ToBoolean((1 << (classIndex - 1)) & classMask))
|
||||
if (classMask == 0 || Convert.ToBoolean((1 << ((int)classIndex - 1)) & classMask))
|
||||
{
|
||||
PlayerInfo info = _playerInfo[(int)raceIndex][classIndex];
|
||||
PlayerInfo info = _playerInfo.LookupByKey(Tuple.Create(raceIndex, classIndex));
|
||||
if (info != null)
|
||||
{
|
||||
info.castSpells[playerCreateMode].Add(spellId);
|
||||
@@ -6350,20 +6367,20 @@ namespace Game
|
||||
uint count = 0;
|
||||
do
|
||||
{
|
||||
uint currentrace = result.Read<uint>(0);
|
||||
if (currentrace >= (int)Race.Max)
|
||||
Race currentrace = (Race)result.Read<uint>(0);
|
||||
if (currentrace >= Race.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Wrong race {0} in `playercreateinfo_action` table, ignoring.", currentrace);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint currentclass = result.Read<uint>(1);
|
||||
if (currentclass >= (int)Class.Max)
|
||||
Class currentclass = (Class)result.Read<uint>(1);
|
||||
if (currentclass >= Class.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Wrong class {0} in `playercreateinfo_action` table, ignoring.", currentclass);
|
||||
continue;
|
||||
}
|
||||
PlayerInfo info = _playerInfo[currentrace][currentclass];
|
||||
PlayerInfo info = _playerInfo.LookupByKey(Tuple.Create(currentrace, currentclass));
|
||||
if (info != null)
|
||||
info.action.Add(new PlayerCreateInfoAction(result.Read<byte>(2), result.Read<uint>(3), result.Read<byte>(4)));
|
||||
|
||||
@@ -6381,7 +6398,6 @@ namespace Game
|
||||
for (var i = 0; i < (int)Race.Max; ++i)
|
||||
raceStatModifiers[i] = new short[(int)Stats.Max];
|
||||
|
||||
|
||||
// 0 1 2 3 4
|
||||
SQLResult result = DB.World.Query("SELECT race, str, agi, sta, inte FROM player_racestats");
|
||||
if (result.IsEmpty())
|
||||
@@ -6393,15 +6409,15 @@ namespace Game
|
||||
|
||||
do
|
||||
{
|
||||
uint currentrace = result.Read<uint>(0);
|
||||
if (currentrace >= (int)Race.Max)
|
||||
Race currentrace = (Race)result.Read<uint>(0);
|
||||
if (currentrace >= Race.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Wrong race {currentrace} in `player_racestats` table, ignoring.");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (int)Stats.Max; ++i)
|
||||
raceStatModifiers[currentrace][i] = result.Read<short>(i + 1);
|
||||
raceStatModifiers[(int)currentrace][i] = result.Read<short>(i + 1);
|
||||
|
||||
} while (result.NextRow());
|
||||
|
||||
@@ -6418,8 +6434,8 @@ namespace Game
|
||||
|
||||
do
|
||||
{
|
||||
uint currentclass = result.Read<byte>(0);
|
||||
if (currentclass >= (int)Class.Max)
|
||||
Class currentclass = (Class)result.Read<byte>(0);
|
||||
if (currentclass >= Class.Max)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Wrong class {0} in `player_classlevelstats` table, ignoring.", currentclass);
|
||||
continue;
|
||||
@@ -6438,14 +6454,14 @@ namespace Game
|
||||
|
||||
for (var race = 0; race < raceStatModifiers.Length; ++race)
|
||||
{
|
||||
var pInfo = _playerInfo[race][currentclass];
|
||||
if (pInfo == null)
|
||||
var playerInfo = _playerInfo.LookupByKey(Tuple.Create((Race)race, currentclass));
|
||||
if (playerInfo == null)
|
||||
continue;
|
||||
|
||||
if (pInfo.levelInfo[currentlevel - 1] == null)
|
||||
pInfo.levelInfo[currentlevel - 1] = new PlayerLevelInfo();
|
||||
if (playerInfo.levelInfo[currentlevel - 1] == null)
|
||||
playerInfo.levelInfo[currentlevel - 1] = new PlayerLevelInfo();
|
||||
|
||||
var levelinfo = pInfo.levelInfo[currentlevel - 1];
|
||||
var levelinfo = playerInfo.levelInfo[currentlevel - 1];
|
||||
|
||||
for (var i = 0; i < (int)Stats.Max; i++)
|
||||
levelinfo.stats[i] = (ushort)(result.Read<ushort>(i + 2) + raceStatModifiers[race][i]);
|
||||
@@ -6455,38 +6471,38 @@ namespace Game
|
||||
} while (result.NextRow());
|
||||
|
||||
// Fill gaps and check integrity
|
||||
for (uint race = 0; race < (int)Race.Max; ++race)
|
||||
for (Race race = 0; race < Race.Max; ++race)
|
||||
{
|
||||
// skip non existed races
|
||||
if (!CliDB.ChrRacesStorage.ContainsKey(race) || _playerInfo[race][0] == null)
|
||||
if (!CliDB.ChrRacesStorage.ContainsKey(race))
|
||||
continue;
|
||||
|
||||
for (uint _class = 0; _class < (int)Class.Max; ++_class)
|
||||
for (Class _class = 0; _class < Class.Max; ++_class)
|
||||
{
|
||||
// skip non existed classes
|
||||
if (CliDB.ChrClassesStorage.LookupByKey(_class) == null || _playerInfo[race][_class] == null)
|
||||
if (CliDB.ChrClassesStorage.LookupByKey(_class) == null)
|
||||
continue;
|
||||
|
||||
PlayerInfo pInfo = _playerInfo[race][_class];
|
||||
if (pInfo == null)
|
||||
var playerInfo = _playerInfo.LookupByKey(Tuple.Create(race, _class));
|
||||
if (playerInfo == null)
|
||||
continue;
|
||||
|
||||
// skip expansion races if not playing with expansion
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.BurningCrusade && (race == (int)Race.BloodElf || race == (int)Race.Draenei))
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.BurningCrusade && (race == Race.BloodElf || race == Race.Draenei))
|
||||
continue;
|
||||
|
||||
// skip expansion classes if not playing with expansion
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.WrathOfTheLichKing && _class == (int)Class.Deathknight)
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.WrathOfTheLichKing && _class == Class.Deathknight)
|
||||
continue;
|
||||
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.MistsOfPandaria && (race == (int)Race.PandarenNeutral || race == (int)Race.PandarenHorde || race == (int)Race.PandarenAlliance))
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.MistsOfPandaria && (race == Race.PandarenNeutral || race == Race.PandarenHorde || race == Race.PandarenAlliance))
|
||||
continue;
|
||||
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.Legion && _class == (int)Class.DemonHunter)
|
||||
if (WorldConfig.GetIntValue(WorldCfg.Expansion) < (int)Expansion.Legion && _class == Class.DemonHunter)
|
||||
continue;
|
||||
|
||||
// fatal error if no level 1 data
|
||||
if (pInfo.levelInfo == null || pInfo.levelInfo[0] == null)
|
||||
if (playerInfo.levelInfo == null || playerInfo.levelInfo[0].stats[0] == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Race {0} Class {1} Level 1 does not have stats data!", race, _class);
|
||||
Global.WorldMgr.StopNow();
|
||||
@@ -6496,10 +6512,10 @@ namespace Game
|
||||
// fill level gaps
|
||||
for (var level = 1; level < WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel); ++level)
|
||||
{
|
||||
if (pInfo.levelInfo[level] == null)
|
||||
if (playerInfo.levelInfo[level].stats[0] == 0)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, "Race {0} Class {1} Level {2} does not have stats data. Using stats data of level {3}.", race, _class, level + 1, level);
|
||||
pInfo.levelInfo[level] = pInfo.levelInfo[level - 1];
|
||||
playerInfo.levelInfo[level] = playerInfo.levelInfo[level - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6561,18 +6577,18 @@ namespace Game
|
||||
}
|
||||
void PlayerCreateInfoAddItemHelper(uint race, uint class_, uint itemId, int count)
|
||||
{
|
||||
if (_playerInfo[race][class_] == null)
|
||||
var playerInfo = _playerInfo.LookupByKey(Tuple.Create((Race)race, (Class)class_));
|
||||
if (playerInfo == null)
|
||||
return;
|
||||
|
||||
if (count > 0)
|
||||
_playerInfo[race][class_].item.Add(new PlayerCreateInfoItem(itemId, (uint)count));
|
||||
playerInfo.item.Add(new PlayerCreateInfoItem(itemId, (uint)count));
|
||||
else
|
||||
{
|
||||
if (count < -1)
|
||||
Log.outError(LogFilter.Sql, "Invalid count {0} specified on item {1} be removed from original player create info (use -1)!", count, itemId);
|
||||
|
||||
var items = _playerInfo[race][class_].item;
|
||||
items.RemoveAll(item => { return item.item_id == itemId; });
|
||||
playerInfo.item.RemoveAll(item => item.item_id == itemId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6584,7 +6600,7 @@ namespace Game
|
||||
if (classId >= Class.Max)
|
||||
return null;
|
||||
|
||||
var info = _playerInfo[(int)raceId][(int)classId];
|
||||
var info = _playerInfo.LookupByKey(Tuple.Create(raceId, classId));
|
||||
if (info == null)
|
||||
return null;
|
||||
|
||||
@@ -6613,7 +6629,7 @@ namespace Game
|
||||
if (level < 1 || race >= Race.Max || _class >= Class.Max)
|
||||
return null;
|
||||
|
||||
PlayerInfo pInfo = _playerInfo[(int)race][(int)_class];
|
||||
PlayerInfo pInfo = _playerInfo.LookupByKey(Tuple.Create(race, _class));
|
||||
if (pInfo == null)
|
||||
return null;
|
||||
|
||||
@@ -6626,7 +6642,7 @@ namespace Game
|
||||
PlayerLevelInfo BuildPlayerLevelInfo(Race race, Class _class, uint level)
|
||||
{
|
||||
// base data (last known level)
|
||||
var info = _playerInfo[(byte)race][(int)_class].levelInfo[WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel) - 1];
|
||||
var info = _playerInfo.LookupByKey(Tuple.Create(race, _class)).levelInfo[WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel) - 1];
|
||||
|
||||
for (int lvl = WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel) - 1; lvl < level; ++lvl)
|
||||
{
|
||||
@@ -10911,7 +10927,6 @@ namespace Game
|
||||
MultiMap<uint, GossipMenus> gossipMenusStorage = new();
|
||||
MultiMap<uint, GossipMenuItems> gossipMenuItemsStorage = new();
|
||||
Dictionary<uint, GossipMenuAddon> _gossipMenuAddonStorage = new();
|
||||
Dictionary<Tuple<uint, uint>, GossipMenuItemAddon> _gossipMenuItemAddonStorage = new();
|
||||
Dictionary<uint, PointOfInterest> pointsOfInterestStorage = new();
|
||||
|
||||
//Creature
|
||||
@@ -10946,7 +10961,7 @@ namespace Game
|
||||
Dictionary<uint, ItemTemplate> ItemTemplateStorage = new();
|
||||
|
||||
//Player
|
||||
PlayerInfo[][] _playerInfo = new PlayerInfo[(int)Race.Max][];
|
||||
Dictionary<Tuple<Race, Class>, PlayerInfo> _playerInfo = new();
|
||||
|
||||
//Faction Change
|
||||
public Dictionary<uint, uint> FactionChangeAchievements = new();
|
||||
@@ -12007,6 +12022,7 @@ namespace Game
|
||||
public byte ClassID;
|
||||
public byte ActiveExpansionLevel;
|
||||
public byte AccountExpansionLevel;
|
||||
public byte MinActiveExpansionLevel;
|
||||
}
|
||||
|
||||
public class RaceClassAvailability
|
||||
|
||||
@@ -86,6 +86,7 @@ namespace Game
|
||||
SetTimeZoneInformation packet = new();
|
||||
packet.ServerTimeTZ = "Europe/Paris";
|
||||
packet.GameTimeTZ = "Europe/Paris";
|
||||
packet.ServerRegionalTZ = "Europe/Paris";
|
||||
|
||||
SendPacket(packet);//enabled it
|
||||
}
|
||||
|
||||
@@ -246,7 +246,11 @@ namespace Game
|
||||
|
||||
public void SendAzeriteRespecNPC(ObjectGuid npc)
|
||||
{
|
||||
SendPacket(new AzeriteRespecNPC(npc));
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = npc;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.AzeriteRespec;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,10 +297,11 @@ namespace Game
|
||||
|
||||
public void SendShowBank(ObjectGuid guid)
|
||||
{
|
||||
m_currentBankerGUID = guid;
|
||||
ShowBank packet = new();
|
||||
packet.Guid = guid;
|
||||
SendPacket(packet);
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.Banker;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,11 @@ namespace Game
|
||||
|
||||
void SendBlackMarketOpenResult(ObjectGuid guid, Creature auctioneer)
|
||||
{
|
||||
BlackMarketOpenResult packet = new();
|
||||
packet.Guid = guid;
|
||||
packet.Enable = Global.BlackMarketMgr.IsEnabled();
|
||||
SendPacket(packet);
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.BlackMarketAuctioneer;
|
||||
npcInteraction.Success = Global.BlackMarketMgr.IsEnabled();
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.BlackMarketRequestItems)]
|
||||
|
||||
@@ -192,6 +192,15 @@ namespace Game
|
||||
if (req.ItemModifiedAppearanceID != 0 && !GetCollectionMgr().HasItemAppearance(req.ItemModifiedAppearanceID).PermAppearance)
|
||||
return false;
|
||||
|
||||
if (req.QuestID != 0)
|
||||
{
|
||||
if (!_player)
|
||||
return false;
|
||||
|
||||
if (!_player.IsQuestRewarded((uint)req.QuestID))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkRequiredDependentChoices)
|
||||
{
|
||||
var requiredChoices = Global.DB2Mgr.GetRequiredCustomizationChoices(req.Id);
|
||||
@@ -318,14 +327,14 @@ namespace Game
|
||||
RaceUnlockRequirement raceExpansionRequirement = Global.ObjectMgr.GetRaceUnlockRequirement(charCreate.CreateInfo.RaceId);
|
||||
if (raceExpansionRequirement == null)
|
||||
{
|
||||
Log.outError(LogFilter.Player, $"Account {GetAccountId()} tried to create character with unavailable race {charCreate.CreateInfo.RaceId}");
|
||||
SendCharCreate(ResponseCodes.AccountCreateFailed);
|
||||
Log.outError(LogFilter.Cheat, $"Account {GetAccountId()} tried to create character with unavailable race {charCreate.CreateInfo.RaceId}");
|
||||
SendCharCreate(ResponseCodes.CharCreateFailed);
|
||||
return;
|
||||
}
|
||||
|
||||
if (raceExpansionRequirement.Expansion > (byte)GetAccountExpansion())
|
||||
{
|
||||
Log.outError(LogFilter.Player, $"Expansion {GetAccountExpansion()} account:[{GetAccountId()}] tried to Create character with expansion {raceExpansionRequirement.Expansion} race ({charCreate.CreateInfo.RaceId})");
|
||||
Log.outError(LogFilter.Cheat, $"Expansion {GetAccountExpansion()} account:[{GetAccountId()}] tried to Create character with expansion {raceExpansionRequirement.Expansion} race ({charCreate.CreateInfo.RaceId})");
|
||||
SendCharCreate(ResponseCodes.CharCreateExpansion);
|
||||
return;
|
||||
}
|
||||
@@ -338,18 +347,33 @@ namespace Game
|
||||
// return;
|
||||
//}
|
||||
|
||||
// prevent character creating Expansion class without Expansion account
|
||||
ClassAvailability classExpansionRequirement = Global.ObjectMgr.GetClassExpansionRequirement(charCreate.CreateInfo.RaceId, charCreate.CreateInfo.ClassId);
|
||||
if (classExpansionRequirement == null)
|
||||
// prevent character creating Expansion race without Expansion account
|
||||
ClassAvailability raceClassExpansionRequirement = Global.ObjectMgr.GetClassExpansionRequirement(charCreate.CreateInfo.RaceId, charCreate.CreateInfo.ClassId);
|
||||
if (raceClassExpansionRequirement != null)
|
||||
{
|
||||
Log.outError(LogFilter.Player, $"Expansion {GetAccountExpansion()} account:[{GetAccountId()}] tried to Create character for race/class combination that is missing requirements in db ({charCreate.CreateInfo.RaceId}/{charCreate.CreateInfo.ClassId})");
|
||||
SendCharCreate(ResponseCodes.CharCreateExpansionClass);
|
||||
return;
|
||||
if (raceClassExpansionRequirement.ActiveExpansionLevel > (byte)GetExpansion() || raceClassExpansionRequirement.AccountExpansionLevel > (byte)GetAccountExpansion())
|
||||
{
|
||||
Log.outError(LogFilter.Cheat, $"Account:[{GetAccountId()}] tried to create character with race/class {charCreate.CreateInfo.RaceId}/{charCreate.CreateInfo.ClassId} without required expansion " +
|
||||
$"(had {GetExpansion()}/{GetAccountExpansion()}, required {raceClassExpansionRequirement.ActiveExpansionLevel}/{raceClassExpansionRequirement.AccountExpansionLevel})");
|
||||
SendCharCreate(ResponseCodes.CharCreateExpansionClass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (classExpansionRequirement.ActiveExpansionLevel > (int)GetExpansion() || classExpansionRequirement.AccountExpansionLevel > (int)GetAccountExpansion())
|
||||
else
|
||||
{
|
||||
Log.outError(LogFilter.Player, $"Account:[{GetAccountId()}] tried to create character with race/class {charCreate.CreateInfo.RaceId}/{charCreate.CreateInfo.ClassId} without required expansion(had {GetExpansion()}/{GetAccountExpansion()}, required {classExpansionRequirement.ActiveExpansionLevel}/{classExpansionRequirement.AccountExpansionLevel})");
|
||||
ClassAvailability classExpansionRequirement = Global.ObjectMgr.GetClassExpansionRequirementFallback((byte)charCreate.CreateInfo.ClassId);
|
||||
if (classExpansionRequirement != null)
|
||||
{
|
||||
if (classExpansionRequirement.MinActiveExpansionLevel > (byte)GetExpansion() || classExpansionRequirement.AccountExpansionLevel > (byte)GetAccountExpansion())
|
||||
{
|
||||
Log.outError(LogFilter.Cheat, $"Account:[{GetAccountId()}] tried to create character with race/class {charCreate.CreateInfo.RaceId}/{charCreate.CreateInfo.ClassId} without required expansion " +
|
||||
$"(had {GetExpansion()}/{GetAccountExpansion()}, required {classExpansionRequirement.ActiveExpansionLevel}/{classExpansionRequirement.AccountExpansionLevel})");
|
||||
SendCharCreate(ResponseCodes.CharCreateExpansionClass);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
Log.outError(LogFilter.Cheat, $"Expansion {GetAccountExpansion()} account:[{GetAccountId()}] tried to Create character for race/class combination that is missing requirements in db ({charCreate.CreateInfo.RaceId}/{charCreate.CreateInfo.ClassId})");
|
||||
SendCharCreate(ResponseCodes.CharCreateExpansionClass);
|
||||
return;
|
||||
}
|
||||
@@ -450,9 +474,14 @@ namespace Game
|
||||
|
||||
int demonHunterReqLevel = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingMinLevelForDemonHunter);
|
||||
bool hasDemonHunterReqLevel = demonHunterReqLevel == 0;
|
||||
uint evokerReqLevel = WorldConfig.GetUIntValue(WorldCfg.CharacterCreatingMinLevelForEvoker);
|
||||
bool hasEvokerReqLevel = (evokerReqLevel == 0);
|
||||
bool allowTwoSideAccounts = !Global.WorldMgr.IsPvPRealm() || HasPermission(RBACPermissions.TwoSideCharacterCreation);
|
||||
int skipCinematics = WorldConfig.GetIntValue(WorldCfg.SkipCinematics);
|
||||
bool checkDemonHunterReqs = createInfo.ClassId == Class.DemonHunter && !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter);
|
||||
bool checkClassLevelReqs = (createInfo.ClassId == Class.DemonHunter || createInfo.ClassId == Class.Evoker)
|
||||
&& !HasPermission(RBACPermissions.SkipCheckCharacterCreationDemonHunter);
|
||||
int evokerLimit = WorldConfig.GetIntValue(WorldCfg.CharacterCreatingEvokersPerRealm);
|
||||
bool hasEvokerLimit = evokerLimit != 0;
|
||||
|
||||
void finalizeCharacterCreation(SQLResult result1)
|
||||
{
|
||||
@@ -461,8 +490,9 @@ namespace Game
|
||||
{
|
||||
Team team = Player.TeamForRace(createInfo.RaceId);
|
||||
byte accRace = result1.Read<byte>(1);
|
||||
byte accClass = result1.Read<byte>(2);
|
||||
|
||||
if (checkDemonHunterReqs)
|
||||
if (checkClassLevelReqs)
|
||||
{
|
||||
if (!hasDemonHunterReqLevel)
|
||||
{
|
||||
@@ -470,8 +500,17 @@ namespace Game
|
||||
if (accLevel >= demonHunterReqLevel)
|
||||
hasDemonHunterReqLevel = true;
|
||||
}
|
||||
if (!hasEvokerReqLevel)
|
||||
{
|
||||
byte accLevel = result1.Read<byte>(0);
|
||||
if (accLevel >= evokerReqLevel)
|
||||
hasEvokerReqLevel = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (accClass == (byte)Class.Evoker)
|
||||
--evokerLimit;
|
||||
|
||||
// need to check team only for first character
|
||||
// @todo what to if account already has characters of both races?
|
||||
if (!allowTwoSideAccounts)
|
||||
@@ -489,17 +528,18 @@ namespace Game
|
||||
|
||||
// search same race for cinematic or same class if need
|
||||
// @todo check if cinematic already shown? (already logged in?; cinematic field)
|
||||
while ((skipCinematics == 1 && !haveSameRace) || createInfo.ClassId == Class.DemonHunter)
|
||||
while ((skipCinematics == 1 && !haveSameRace) || createInfo.ClassId == Class.DemonHunter || createInfo.ClassId == Class.Evoker)
|
||||
{
|
||||
if (!result1.NextRow())
|
||||
break;
|
||||
|
||||
accRace = result1.Read<byte>(1);
|
||||
accClass = result1.Read<byte>(2);
|
||||
|
||||
if (!haveSameRace)
|
||||
haveSameRace = createInfo.RaceId == (Race)accRace;
|
||||
|
||||
if (checkDemonHunterReqs)
|
||||
if (checkClassLevelReqs)
|
||||
{
|
||||
if (!hasDemonHunterReqLevel)
|
||||
{
|
||||
@@ -507,11 +547,33 @@ namespace Game
|
||||
if (acc_level >= demonHunterReqLevel)
|
||||
hasDemonHunterReqLevel = true;
|
||||
}
|
||||
if (!hasEvokerReqLevel)
|
||||
{
|
||||
byte accLevel = result1.Read<byte>(0);
|
||||
if (accLevel >= evokerReqLevel)
|
||||
hasEvokerReqLevel = true;
|
||||
}
|
||||
}
|
||||
if (accClass == (byte)Class.Evoker)
|
||||
--evokerLimit;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkDemonHunterReqs && !hasDemonHunterReqLevel)
|
||||
if (checkClassLevelReqs)
|
||||
{
|
||||
if (!hasDemonHunterReqLevel)
|
||||
{
|
||||
SendCharCreate(ResponseCodes.CharCreateNewPlayer);
|
||||
return;
|
||||
}
|
||||
if (!hasEvokerReqLevel)
|
||||
{
|
||||
SendCharCreate(ResponseCodes.CharCreateDracthyrLevelRequirement);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (createInfo.ClassId == Class.Evoker && hasEvokerLimit && evokerLimit < 1)
|
||||
{
|
||||
SendCharCreate(ResponseCodes.CharCreateNewPlayer);
|
||||
return;
|
||||
@@ -520,7 +582,7 @@ namespace Game
|
||||
// Check name uniqueness in the same step as saving to database
|
||||
if (Global.CharacterCacheStorage.GetCharacterCacheByName(createInfo.Name) != null)
|
||||
{
|
||||
SendCharCreate(ResponseCodes.CharCreateNameInUse);
|
||||
SendCharCreate(ResponseCodes.CharCreateDracthyrDuplicate);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -580,7 +642,7 @@ namespace Game
|
||||
|
||||
stmt = DB.Characters.GetPreparedStatement(CharStatements.SEL_CHAR_CREATE_INFO);
|
||||
stmt.AddValue(0, GetAccountId());
|
||||
stmt.AddValue(1, (skipCinematics == 1 || createInfo.ClassId == Class.DemonHunter) ? 1200 : 1); // 200 (max chars per realm) + 1000 (max deleted chars per realm)
|
||||
stmt.AddValue(1, (skipCinematics == 1 || createInfo.ClassId == Class.DemonHunter || createInfo.ClassId == Class.Evoker) ? 1200 : 1); // 200 (max chars per realm) + 1000 (max deleted chars per realm)
|
||||
queryCallback.WithCallback(finalizeCharacterCreation).SetNextQuery(DB.Characters.AsyncQuery(stmt));
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -808,8 +808,8 @@ namespace Game
|
||||
gems[i] = gem;
|
||||
gemData[i].ItemId = gem.GetEntry();
|
||||
gemData[i].Context = (byte)gem.m_itemData.Context;
|
||||
for (int b = 0; b < ((List<uint>)gem.m_itemData.BonusListIDs).Count && b < 16; ++b)
|
||||
gemData[i].BonusListIDs[b] = (ushort)((List<uint>)gem.m_itemData.BonusListIDs)[b];
|
||||
for (int b = 0; b < gem.GetBonusListIDs().Count && b < 16; ++b)
|
||||
gemData[i].BonusListIDs[b] = (ushort)gem.GetBonusListIDs()[b];
|
||||
|
||||
gemProperties[i] = CliDB.GemPropertiesStorage.LookupByKey(gem.GetTemplate().GetGemProperties());
|
||||
}
|
||||
|
||||
@@ -682,9 +682,11 @@ namespace Game
|
||||
|
||||
public void SendShowMailBox(ObjectGuid guid)
|
||||
{
|
||||
ShowMailbox packet = new();
|
||||
packet.PostmasterGUID = guid;
|
||||
SendPacket(packet);
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.MailInfo;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ using Framework.Database;
|
||||
using Game.BattleGrounds;
|
||||
using Game.DataStorage;
|
||||
using Game.Entities;
|
||||
using Game.Misc;
|
||||
using Game.Networking;
|
||||
using Game.Networking.Packets;
|
||||
using System;
|
||||
@@ -48,9 +49,11 @@ namespace Game
|
||||
|
||||
public void SendTabardVendorActivate(ObjectGuid guid)
|
||||
{
|
||||
PlayerTabardVendorActivate packet = new();
|
||||
packet.Vendor = guid;
|
||||
SendPacket(packet);
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.TabardVendor;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
|
||||
[WorldPacketHandler(ClientOpcodes.TrainerList, Processing = PacketProcessing.Inplace)]
|
||||
@@ -172,7 +175,8 @@ namespace Game
|
||||
[WorldPacketHandler(ClientOpcodes.GossipSelectOption)]
|
||||
void HandleGossipSelectOption(GossipSelectOption packet)
|
||||
{
|
||||
if (GetPlayer().PlayerTalkClass.GetGossipMenu().GetItem(packet.GossipIndex) == null)
|
||||
GossipMenuItem gossipMenuItem = _player.PlayerTalkClass.GetGossipMenu().GetItem(packet.GossipOptionID);
|
||||
if (gossipMenuItem == null)
|
||||
return;
|
||||
|
||||
// Prevent cheating on C# scripted menus
|
||||
@@ -224,26 +228,26 @@ namespace Game
|
||||
{
|
||||
if (unit != null)
|
||||
{
|
||||
if (!unit.GetAI().OnGossipSelectCode(_player, packet.GossipID, packet.GossipIndex, packet.PromotionCode))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
|
||||
if (!unit.GetAI().OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem.OrderIndex, packet.PromotionCode))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!go.GetAI().OnGossipSelectCode(_player, packet.GossipID, packet.GossipIndex, packet.PromotionCode))
|
||||
_player.OnGossipSelect(go, packet.GossipIndex, packet.GossipID);
|
||||
if (!go.GetAI().OnGossipSelectCode(_player, packet.GossipID, gossipMenuItem.OrderIndex, packet.PromotionCode))
|
||||
_player.OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unit != null)
|
||||
{
|
||||
if (!unit.GetAI().OnGossipSelect(_player, packet.GossipID, packet.GossipIndex))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipIndex, packet.GossipID);
|
||||
if (!unit.GetAI().OnGossipSelect(_player, packet.GossipID, gossipMenuItem.OrderIndex))
|
||||
GetPlayer().OnGossipSelect(unit, packet.GossipOptionID, packet.GossipID);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!go.GetAI().OnGossipSelect(_player, packet.GossipID, packet.GossipIndex))
|
||||
GetPlayer().OnGossipSelect(go, packet.GossipIndex, packet.GossipID);
|
||||
if (!go.GetAI().OnGossipSelect(_player, packet.GossipID, gossipMenuItem.OrderIndex))
|
||||
GetPlayer().OnGossipSelect(go, packet.GossipOptionID, packet.GossipID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +342,11 @@ namespace Game
|
||||
|
||||
public void SendOpenTransmogrifier(ObjectGuid guid)
|
||||
{
|
||||
SendPacket(new TransmogrifyNPC(guid));
|
||||
NPCInteractionOpenResult npcInteraction = new();
|
||||
npcInteraction.Npc = guid;
|
||||
npcInteraction.InteractionType = PlayerInteractionType.Transmogrifier;
|
||||
npcInteraction.Success = true;
|
||||
SendPacket(npcInteraction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Game
|
||||
|
||||
VoidStorageItem itemVS = new(Global.ObjectMgr.GenerateVoidStorageItemId(), item.GetEntry(), item.GetCreator(),
|
||||
item.GetItemRandomBonusListId(), item.GetModifier(ItemModifier.TimewalkerLevel), item.GetModifier(ItemModifier.ArtifactKnowledgeLevel),
|
||||
item.GetContext(), item.m_itemData.BonusListIDs);
|
||||
item.GetContext(), item.GetBonusListIDs());
|
||||
|
||||
VoidItem voidItem;
|
||||
voidItem.Guid = ObjectGuid.Create(HighGuid.Item, itemVS.ItemId);
|
||||
|
||||
@@ -370,11 +370,7 @@ namespace Game.Maps
|
||||
{
|
||||
foreach (uint mapId in transport.MapIds)
|
||||
Cypher.Assert(!CliDB.MapStorage.LookupByKey(mapId).Instanceable());
|
||||
|
||||
transport.InInstance = false;
|
||||
}
|
||||
else
|
||||
transport.InInstance = CliDB.MapStorage.LookupByKey(transport.MapIds.First()).Instanceable();
|
||||
|
||||
transport.TotalPathTime = totalTime;
|
||||
}
|
||||
@@ -424,6 +420,12 @@ namespace Game.Maps
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!tInfo.MapIds.Contains(map.GetId()))
|
||||
{
|
||||
Log.outError(LogFilter.Transport, $"Transport {entry} attempted creation on map it has no path for {map.GetId()}!");
|
||||
return null;
|
||||
}
|
||||
|
||||
Position startingPosition = tInfo.ComputePosition(0, out _, out _);
|
||||
if (startingPosition == null)
|
||||
{
|
||||
@@ -435,7 +437,6 @@ namespace Game.Maps
|
||||
Transport trans = new();
|
||||
|
||||
// ...at first waypoint
|
||||
uint mapId = tInfo.PathLegs.First().MapId;
|
||||
float x = startingPosition.GetPositionX();
|
||||
float y = startingPosition.GetPositionY();
|
||||
float z = startingPosition.GetPositionZ();
|
||||
@@ -448,16 +449,6 @@ namespace Game.Maps
|
||||
|
||||
PhasingHandler.InitDbPhaseShift(trans.GetPhaseShift(), phaseUseFlags, phaseId, phaseGroupId);
|
||||
|
||||
MapRecord mapEntry = CliDB.MapStorage.LookupByKey(mapId);
|
||||
if (mapEntry != null)
|
||||
{
|
||||
if (mapEntry.Instanceable() != tInfo.InInstance)
|
||||
{
|
||||
Log.outError(LogFilter.Transport, "Transport {0} (name: {1}) attempted creation in instance map (id: {2}) but it is not an instanced transport!", entry, trans.GetName(), mapId);
|
||||
//return null;
|
||||
}
|
||||
}
|
||||
|
||||
// use preset map for instances (need to know which instance)
|
||||
trans.SetMap(map);
|
||||
if (instanceMap != null)
|
||||
@@ -536,7 +527,6 @@ namespace Game.Maps
|
||||
public List<TransportPathEvent> Events = new();
|
||||
|
||||
public HashSet<uint> MapIds = new();
|
||||
public bool InInstance;
|
||||
|
||||
public Position ComputePosition(uint time, out TransportMovementState moveState, out int legIndex)
|
||||
{
|
||||
|
||||
@@ -784,12 +784,12 @@ namespace Game.Networking.Packets
|
||||
public struct AuctionListFilterSubClass
|
||||
{
|
||||
public int ItemSubclass;
|
||||
public uint InvTypeMask;
|
||||
public ulong InvTypeMask;
|
||||
|
||||
public AuctionListFilterSubClass(WorldPacket data)
|
||||
{
|
||||
InvTypeMask = data.ReadUInt64();
|
||||
ItemSubclass = data.ReadInt32();
|
||||
InvTypeMask = data.ReadUInt32();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -138,6 +138,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt8(classAvailability.ClassID);
|
||||
_worldPacket.WriteUInt8(classAvailability.ActiveExpansionLevel);
|
||||
_worldPacket.WriteUInt8(classAvailability.AccountExpansionLevel);
|
||||
_worldPacket.WriteUInt8(classAvailability.MinActiveExpansionLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,7 +167,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt16(SuccessInfo.NumPlayersAlliance.Value);
|
||||
|
||||
if(SuccessInfo.ExpansionTrialExpiration.HasValue)
|
||||
_worldPacket.WriteInt32(SuccessInfo.ExpansionTrialExpiration.Value);
|
||||
_worldPacket.WriteInt64(SuccessInfo.ExpansionTrialExpiration.Value);
|
||||
|
||||
foreach (VirtualRealmInfo virtualRealm in SuccessInfo.VirtualRealms)
|
||||
virtualRealm.Write(_worldPacket);
|
||||
@@ -220,7 +221,7 @@ namespace Game.Networking.Packets
|
||||
public bool ForceCharacterTemplate; // forces the client to always use a character template when creating a new character. @see Templates. @todo implement
|
||||
public ushort? NumPlayersHorde; // number of horde players in this realm. @todo implement
|
||||
public ushort? NumPlayersAlliance; // number of alliance players in this realm. @todo implement
|
||||
public int? ExpansionTrialExpiration; // expansion trial expiration unix timestamp
|
||||
public long? ExpansionTrialExpiration; // expansion trial expiration unix timestamp
|
||||
|
||||
public struct GameTime
|
||||
{
|
||||
|
||||
@@ -34,25 +34,6 @@ namespace Game.Networking.Packets
|
||||
public ulong XP;
|
||||
}
|
||||
|
||||
class OpenHeartForge : ServerPacket
|
||||
{
|
||||
public OpenHeartForge() : base(ServerOpcodes.OpenHeartForge) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(ForgeGUID);
|
||||
}
|
||||
|
||||
public ObjectGuid ForgeGUID;
|
||||
}
|
||||
|
||||
class CloseHeartForge : ServerPacket
|
||||
{
|
||||
public CloseHeartForge() : base(ServerOpcodes.CloseHeartForge) { }
|
||||
|
||||
public override void Write() { }
|
||||
}
|
||||
|
||||
class AzeriteEssenceUnlockMilestone : ClientPacket
|
||||
{
|
||||
public AzeriteEssenceUnlockMilestone(WorldPacket packet) : base(packet) { }
|
||||
@@ -141,19 +122,4 @@ namespace Game.Networking.Packets
|
||||
|
||||
public bool IsHeartEquipped;
|
||||
}
|
||||
|
||||
class AzeriteRespecNPC : ServerPacket
|
||||
{
|
||||
public AzeriteRespecNPC(ObjectGuid npcGuid) : base(ServerOpcodes.AzeriteRespecNpc)
|
||||
{
|
||||
NpcGUID = npcGuid;
|
||||
}
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(NpcGUID);
|
||||
}
|
||||
|
||||
public ObjectGuid NpcGUID;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -573,12 +573,15 @@ namespace Game.Networking.Packets
|
||||
public int Unused2;
|
||||
public int WeeklyPlayed;
|
||||
public int WeeklyWon;
|
||||
public int RoundsSeasonPlayed;
|
||||
public int RoundsSeasonWon;
|
||||
public int RoundsWeeklyPlayed;
|
||||
public int RoundsWeeklyWon;
|
||||
public int BestWeeklyRating;
|
||||
public int LastWeeksBestRating;
|
||||
public int BestSeasonRating;
|
||||
public int PvpTierID;
|
||||
public int Unused3;
|
||||
public int WeeklyBestWinPvpTierID;
|
||||
public int Unused4;
|
||||
public int Rank;
|
||||
public bool Disqualified;
|
||||
@@ -593,12 +596,15 @@ namespace Game.Networking.Packets
|
||||
data.WriteInt32(Unused2);
|
||||
data.WriteInt32(WeeklyPlayed);
|
||||
data.WriteInt32(WeeklyWon);
|
||||
data.WriteInt32(RoundsSeasonPlayed);
|
||||
data.WriteInt32(RoundsSeasonWon);
|
||||
data.WriteInt32(RoundsWeeklyPlayed);
|
||||
data.WriteInt32(RoundsWeeklyWon);
|
||||
data.WriteInt32(BestWeeklyRating);
|
||||
data.WriteInt32(LastWeeksBestRating);
|
||||
data.WriteInt32(BestSeasonRating);
|
||||
data.WriteInt32(PvpTierID);
|
||||
data.WriteInt32(Unused3);
|
||||
data.WriteInt32(WeeklyBestWinPvpTierID);
|
||||
data.WriteInt32(Unused4);
|
||||
data.WriteInt32(Rank);
|
||||
data.WriteBit(Disqualified);
|
||||
|
||||
@@ -33,21 +33,6 @@ namespace Game.Networking.Packets
|
||||
public ObjectGuid Guid;
|
||||
}
|
||||
|
||||
class BlackMarketOpenResult : ServerPacket
|
||||
{
|
||||
public BlackMarketOpenResult() : base(ServerOpcodes.BlackMarketOpenResult) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket .WritePackedGuid(Guid);
|
||||
_worldPacket.WriteBit(Enable);
|
||||
_worldPacket.FlushBits();
|
||||
}
|
||||
|
||||
public ObjectGuid Guid;
|
||||
public bool Enable = true;
|
||||
}
|
||||
|
||||
class BlackMarketRequestItems : ClientPacket
|
||||
{
|
||||
public BlackMarketRequestItems(WorldPacket packet) : base(packet) { }
|
||||
|
||||
@@ -44,12 +44,14 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(IsNewPlayerRestrictionSkipped);
|
||||
_worldPacket.WriteBit(IsNewPlayerRestricted);
|
||||
_worldPacket.WriteBit(IsNewPlayer);
|
||||
_worldPacket.WriteBit(IsTrialAccountRestricted);
|
||||
_worldPacket.WriteBit(DisabledClassesMask.HasValue);
|
||||
_worldPacket.WriteBit(IsAlliedRacesCreationAllowed);
|
||||
_worldPacket.WriteInt32(Characters.Count);
|
||||
_worldPacket.WriteInt32(MaxCharacterLevel);
|
||||
_worldPacket.WriteInt32(RaceUnlockData.Count);
|
||||
_worldPacket.WriteInt32(UnlockedConditionalAppearances.Count);
|
||||
_worldPacket.WriteInt32(RaceLimitDisables.Count);
|
||||
|
||||
if (DisabledClassesMask.HasValue)
|
||||
_worldPacket.WriteUInt32(DisabledClassesMask.Value);
|
||||
@@ -57,6 +59,9 @@ namespace Game.Networking.Packets
|
||||
foreach (UnlockedConditionalAppearance unlockedConditionalAppearance in UnlockedConditionalAppearances)
|
||||
unlockedConditionalAppearance.Write(_worldPacket);
|
||||
|
||||
foreach (RaceLimitDisableInfo raceLimitDisableInfo in RaceLimitDisables)
|
||||
raceLimitDisableInfo.Write(_worldPacket);
|
||||
|
||||
foreach (CharacterInfo charInfo in Characters)
|
||||
charInfo.Write(_worldPacket);
|
||||
|
||||
@@ -69,6 +74,7 @@ namespace Game.Networking.Packets
|
||||
public bool IsNewPlayerRestrictionSkipped; // allows client to skip new player restrictions
|
||||
public bool IsNewPlayerRestricted; // forbids using level boost and class trials
|
||||
public bool IsNewPlayer; // forbids hero classes and allied races
|
||||
public bool IsTrialAccountRestricted;
|
||||
public bool IsAlliedRacesCreationAllowed;
|
||||
|
||||
public int MaxCharacterLevel = 1;
|
||||
@@ -77,6 +83,7 @@ namespace Game.Networking.Packets
|
||||
public List<CharacterInfo> Characters = new(); // all characters on the list
|
||||
public List<RaceUnlock> RaceUnlockData = new(); //
|
||||
public List<UnlockedConditionalAppearance> UnlockedConditionalAppearances = new();
|
||||
public List<RaceLimitDisableInfo> RaceLimitDisables = new();
|
||||
|
||||
public class CharacterInfo
|
||||
{
|
||||
@@ -147,11 +154,11 @@ namespace Game.Networking.Packets
|
||||
|
||||
var spec = Global.DB2Mgr.GetChrSpecializationByIndex(ClassId, fields.Read<byte>(21));
|
||||
if (spec != null)
|
||||
SpecID = (ushort)spec.Id;
|
||||
SpecID = (short)spec.Id;
|
||||
|
||||
LastLoginVersion = fields.Read<uint>(22);
|
||||
LastLoginVersion = fields.Read<int>(22);
|
||||
|
||||
for (byte slot = 0; slot < InventorySlots.BagEnd; ++slot)
|
||||
for (byte slot = 0; slot < InventorySlots.ReagentBagEnd; ++slot)
|
||||
{
|
||||
VisualItems[slot].InvType = (byte)equipment.NextUInt32();
|
||||
VisualItems[slot].DisplayId = equipment.NextUInt32();
|
||||
@@ -190,9 +197,9 @@ namespace Game.Networking.Packets
|
||||
visualItem.Write(data);
|
||||
|
||||
data.WriteInt64(LastPlayedTime);
|
||||
data.WriteUInt16(SpecID);
|
||||
data.WriteUInt32(Unknown703);
|
||||
data.WriteUInt32(LastLoginVersion);
|
||||
data.WriteInt16(SpecID);
|
||||
data.WriteInt32(Unknown703);
|
||||
data.WriteInt32(LastLoginVersion);
|
||||
data.WriteUInt32(Flags4);
|
||||
data.WriteInt32(MailSenders.Count);
|
||||
data.WriteInt32(MailSenderTypes.Count);
|
||||
@@ -244,16 +251,16 @@ namespace Game.Networking.Packets
|
||||
public bool FirstLogin;
|
||||
public byte unkWod61x;
|
||||
public long LastPlayedTime;
|
||||
public ushort SpecID;
|
||||
public uint Unknown703;
|
||||
public uint LastLoginVersion;
|
||||
public short SpecID;
|
||||
public int Unknown703;
|
||||
public int LastLoginVersion;
|
||||
public uint OverrideSelectScreenFileDataID;
|
||||
public uint PetCreatureDisplayId;
|
||||
public uint PetExperienceLevel;
|
||||
public uint PetCreatureFamilyId;
|
||||
public bool BoostInProgress; // @todo
|
||||
public uint[] ProfessionIds = new uint[2]; // @todo
|
||||
public VisualItemInfo[] VisualItems = new VisualItemInfo[InventorySlots.BagEnd];
|
||||
public VisualItemInfo[] VisualItems = new VisualItemInfo[InventorySlots.ReagentBagEnd];
|
||||
public List<string> MailSenders = new();
|
||||
public List<uint> MailSenderTypes = new();
|
||||
|
||||
@@ -311,6 +318,24 @@ namespace Game.Networking.Packets
|
||||
public int AchievementID;
|
||||
public int Unused;
|
||||
}
|
||||
|
||||
public struct RaceLimitDisableInfo
|
||||
{
|
||||
enum blah
|
||||
{
|
||||
Server,
|
||||
Level
|
||||
}
|
||||
|
||||
public int RaceID;
|
||||
public int BlockReason;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(RaceID);
|
||||
data.WriteInt32(BlockReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CheckCharacterNameAvailability : ClientPacket
|
||||
@@ -500,6 +525,7 @@ namespace Game.Networking.Packets
|
||||
RaceOrFactionChangeInfo.Guid = _worldPacket.ReadPackedGuid();
|
||||
RaceOrFactionChangeInfo.SexID = (Gender)_worldPacket.ReadUInt8();
|
||||
RaceOrFactionChangeInfo.RaceID = (Race)_worldPacket.ReadUInt8();
|
||||
RaceOrFactionChangeInfo.InitialRaceID = (Race)_worldPacket.ReadUInt8();
|
||||
var customizationCount = _worldPacket.ReadUInt32();
|
||||
RaceOrFactionChangeInfo.Name = _worldPacket.ReadString(nameLength);
|
||||
|
||||
@@ -851,6 +877,7 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
var customizationCount = _worldPacket.ReadUInt32();
|
||||
NewSex = _worldPacket.ReadUInt8();
|
||||
CustomizedRace = _worldPacket.ReadInt32();
|
||||
|
||||
for (var i = 0; i < customizationCount; ++i)
|
||||
{
|
||||
@@ -866,6 +893,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
public byte NewSex;
|
||||
public Array<ChrCustomizationChoice> Customizations = new(50);
|
||||
public int CustomizedRace;
|
||||
}
|
||||
|
||||
public class BarberShopResult : ServerPacket
|
||||
@@ -902,7 +930,6 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt8((byte)Reason);
|
||||
_worldPacket.WriteInt32(Amount);
|
||||
_worldPacket.WriteFloat(GroupBonus);
|
||||
_worldPacket.WriteUInt8(ReferAFriendBonusType);
|
||||
}
|
||||
|
||||
public ObjectGuid Victim;
|
||||
@@ -910,7 +937,6 @@ namespace Game.Networking.Packets
|
||||
public PlayerLogXPReason Reason;
|
||||
public int Amount;
|
||||
public float GroupBonus;
|
||||
public byte ReferAFriendBonusType; // 1 - 300% of normal XP; 2 - 150% of normal XP
|
||||
}
|
||||
|
||||
class TitleEarned : ServerPacket
|
||||
@@ -1105,6 +1131,7 @@ namespace Game.Networking.Packets
|
||||
public class CharRaceOrFactionChangeInfo
|
||||
{
|
||||
public Race RaceID = Race.None;
|
||||
public Race InitialRaceID = Race.None;
|
||||
public Gender SexID = Gender.None;
|
||||
public ObjectGuid Guid;
|
||||
public bool FactionChange;
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Game.Networking.Packets
|
||||
public override void Read()
|
||||
{
|
||||
Language = (Language)_worldPacket.ReadInt32();
|
||||
uint len = _worldPacket.ReadBits<uint>(9);
|
||||
uint len = _worldPacket.ReadBits<uint>(11);
|
||||
Text = _worldPacket.ReadString(len);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
Language = (Language)_worldPacket.ReadInt32();
|
||||
uint targetLen = _worldPacket.ReadBits<uint>(9);
|
||||
uint textLen = _worldPacket.ReadBits<uint>(9);
|
||||
uint textLen = _worldPacket.ReadBits<uint>(11);
|
||||
Target = _worldPacket.ReadString(targetLen);
|
||||
Text = _worldPacket.ReadString(textLen);
|
||||
}
|
||||
@@ -66,7 +66,7 @@ namespace Game.Networking.Packets
|
||||
Language = (Language)_worldPacket.ReadInt32();
|
||||
ChannelGUID = _worldPacket.ReadPackedGuid();
|
||||
uint targetLen = _worldPacket.ReadBits<uint>(9);
|
||||
uint textLen = _worldPacket.ReadBits<uint>(9);
|
||||
uint textLen = _worldPacket.ReadBits<uint>(11);
|
||||
Target = _worldPacket.ReadString(targetLen);
|
||||
Text = _worldPacket.ReadString(textLen);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Read()
|
||||
{
|
||||
uint len = _worldPacket.ReadBits<uint>(9);
|
||||
uint len = _worldPacket.ReadBits<uint>(11);
|
||||
Text = _worldPacket.ReadString(len);
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Read()
|
||||
{
|
||||
uint len = _worldPacket.ReadBits<uint>(9);
|
||||
uint len = _worldPacket.ReadBits<uint>(11);
|
||||
Text = _worldPacket.ReadString(len);
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Read()
|
||||
{
|
||||
uint len = _worldPacket.ReadBits<uint>(9);
|
||||
uint len = _worldPacket.ReadBits<uint>(11);
|
||||
Text = _worldPacket.ReadString(len);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Networking.Packets
|
||||
{
|
||||
struct SpellReducedReagent
|
||||
{
|
||||
public int ItemID;
|
||||
public int Quantity;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(ItemID);
|
||||
data.WriteInt32(Quantity);
|
||||
}
|
||||
}
|
||||
|
||||
class CraftingData
|
||||
{
|
||||
public int CraftingQualityID;
|
||||
public int field_4;
|
||||
public int field_8;
|
||||
public int Multicraft;
|
||||
public int field_10;
|
||||
public int field_14;
|
||||
public int CritBonusSkill;
|
||||
public float field_1C;
|
||||
public ulong field_20;
|
||||
public bool IsCrit;
|
||||
public bool field_29;
|
||||
public bool field_2A;
|
||||
public bool BonusCraft;
|
||||
public List<SpellReducedReagent> ResourcesReturned = new();
|
||||
public uint OperationID;
|
||||
public ObjectGuid ItemGUID;
|
||||
public int Quantity;
|
||||
public ItemInstance OldItem = new();
|
||||
public ItemInstance NewItem = new();
|
||||
public int EnchantID;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(CraftingQualityID);
|
||||
data.WriteInt32(field_4);
|
||||
data.WriteInt32(field_8);
|
||||
data.WriteInt32(Multicraft);
|
||||
data.WriteInt32(field_10);
|
||||
data.WriteInt32(field_14);
|
||||
data.WriteInt32(CritBonusSkill);
|
||||
data.WriteFloat(field_1C);
|
||||
data.WriteUInt64(field_20);
|
||||
data.WriteInt32(ResourcesReturned.Count);
|
||||
data.WriteUInt32(OperationID);
|
||||
data.WritePackedGuid(ItemGUID);
|
||||
data.WriteInt32(Quantity);
|
||||
data.WriteInt32(EnchantID);
|
||||
|
||||
foreach (SpellReducedReagent spellReducedReagent in ResourcesReturned)
|
||||
spellReducedReagent.Write(data);
|
||||
|
||||
data.WriteBit(IsCrit);
|
||||
data.WriteBit(field_29);
|
||||
data.WriteBit(field_2A);
|
||||
data.WriteBit(BonusCraft);
|
||||
data.FlushBits();
|
||||
|
||||
OldItem.Write(data);
|
||||
NewItem.Write(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,9 +27,11 @@ namespace Game.Networking.Packets
|
||||
public override void Read()
|
||||
{
|
||||
Guid = _worldPacket.ReadPackedGuid();
|
||||
IsSoftInteract = _worldPacket.HasBit();
|
||||
}
|
||||
|
||||
public ObjectGuid Guid;
|
||||
public bool IsSoftInteract;
|
||||
}
|
||||
|
||||
public class GameObjReportUse : ClientPacket
|
||||
@@ -39,9 +41,11 @@ namespace Game.Networking.Packets
|
||||
public override void Read()
|
||||
{
|
||||
Guid = _worldPacket.ReadPackedGuid();
|
||||
IsSoftInteract = _worldPacket.HasBit();
|
||||
}
|
||||
|
||||
public ObjectGuid Guid;
|
||||
public bool IsSoftInteract;
|
||||
}
|
||||
|
||||
class GameObjectDespawn : ServerPacket
|
||||
@@ -136,22 +140,6 @@ namespace Game.Networking.Packets
|
||||
public bool PlayAsDespawn;
|
||||
}
|
||||
|
||||
class GameObjectUILink : ServerPacket
|
||||
{
|
||||
public GameObjectUILink() : base(ServerOpcodes.GameObjectUiLink, ConnectionType.Instance) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(ObjectGUID);
|
||||
_worldPacket.WriteInt32(UILink);
|
||||
_worldPacket.WriteInt32(UIItemInteractionID);
|
||||
}
|
||||
|
||||
public ObjectGuid ObjectGUID;
|
||||
public int UILink;
|
||||
public int UIItemInteractionID;
|
||||
}
|
||||
|
||||
class GameObjectPlaySpellVisual : ServerPacket
|
||||
{
|
||||
public GameObjectPlaySpellVisual() : base(ServerOpcodes.GameObjectPlaySpellVisual) { }
|
||||
@@ -181,4 +169,29 @@ namespace Game.Networking.Packets
|
||||
public ObjectGuid ObjectGUID;
|
||||
public byte State;
|
||||
}
|
||||
|
||||
class GameObjectInteraction : ServerPacket
|
||||
{
|
||||
public ObjectGuid ObjectGUID;
|
||||
public PlayerInteractionType InteractionType;
|
||||
|
||||
public GameObjectInteraction() : base(ServerOpcodes.GameObjectInteraction) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(ObjectGUID);
|
||||
_worldPacket.WriteInt32((int)InteractionType);
|
||||
}
|
||||
}
|
||||
class GameObjectCloseInteraction : ServerPacket
|
||||
{
|
||||
public PlayerInteractionType InteractionType;
|
||||
|
||||
public GameObjectCloseInteraction() : base(ServerOpcodes.GameObjectCloseInteraction) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WriteInt32((int)InteractionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,22 +316,6 @@ namespace Game.Networking.Packets
|
||||
|
||||
public uint GarrPlotInstanceID;
|
||||
}
|
||||
|
||||
class GarrisonOpenTalentNpc : ServerPacket
|
||||
{
|
||||
public GarrisonOpenTalentNpc() : base(ServerOpcodes.GarrisonOpenTalentNpc, ConnectionType.Instance) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(NpcGUID);
|
||||
_worldPacket.WriteInt32(GarrTalentTreeID);
|
||||
_worldPacket.WriteInt32(FriendshipFactionID);
|
||||
}
|
||||
|
||||
public ObjectGuid NpcGUID;
|
||||
public int GarrTalentTreeID;
|
||||
public int FriendshipFactionID; // Always 0 except on The Deaths of Chromie Scenario
|
||||
}
|
||||
|
||||
//Structs
|
||||
public struct GarrisonPlotInfo
|
||||
|
||||
@@ -75,7 +75,9 @@ namespace Game.Networking.Packets
|
||||
GuildData.Value.Write(_worldPacket);
|
||||
|
||||
if (AzeriteLevel.HasValue)
|
||||
_worldPacket.WriteUInt32((uint)AzeriteLevel);
|
||||
_worldPacket.WriteUInt32(AzeriteLevel.Value);
|
||||
|
||||
TalentTraits.Write(_worldPacket);
|
||||
}
|
||||
|
||||
public PlayerModelDisplayInfo DisplayInfo;
|
||||
@@ -83,7 +85,7 @@ namespace Game.Networking.Packets
|
||||
public List<ushort> Talents = new();
|
||||
public Array<ushort> PvpTalents = new(PlayerConst.MaxPvpTalentSlots, 0);
|
||||
public InspectGuildData? GuildData;
|
||||
public Array<PVPBracketData> Bracket = new(6, default);
|
||||
public Array<PVPBracketData> Bracket = new(7, default);
|
||||
public uint? AzeriteLevel;
|
||||
public int ItemLevel;
|
||||
public uint LifetimeHK;
|
||||
@@ -91,6 +93,7 @@ namespace Game.Networking.Packets
|
||||
public ushort TodayHK;
|
||||
public ushort YesterdayHK;
|
||||
public byte LifetimeMaxRank;
|
||||
public TraitInspectInfo TalentTraits;
|
||||
}
|
||||
|
||||
public class QueryInspectAchievements : ClientPacket
|
||||
@@ -290,6 +293,7 @@ namespace Game.Networking.Packets
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteUInt8(Bracket);
|
||||
data.WriteInt32(Unused3);
|
||||
data.WriteInt32(Rating);
|
||||
data.WriteInt32(Rank);
|
||||
data.WriteInt32(WeeklyPlayed);
|
||||
@@ -302,6 +306,10 @@ namespace Game.Networking.Packets
|
||||
data.WriteInt32(WeeklyBestWinPvpTierID);
|
||||
data.WriteInt32(Unused1);
|
||||
data.WriteInt32(Unused2);
|
||||
data.WriteInt32(RoundsSeasonPlayed);
|
||||
data.WriteInt32(RoundsSeasonWon);
|
||||
data.WriteInt32(RoundsWeeklyPlayed);
|
||||
data.WriteInt32(RoundsWeeklyWon);
|
||||
data.WriteBit(Disqualified);
|
||||
data.FlushBits();
|
||||
}
|
||||
@@ -318,10 +326,29 @@ namespace Game.Networking.Packets
|
||||
public int WeeklyBestWinPvpTierID;
|
||||
public int Unused1;
|
||||
public int Unused2;
|
||||
public int Unused3;
|
||||
public int RoundsSeasonPlayed;
|
||||
public int RoundsSeasonWon;
|
||||
public int RoundsWeeklyPlayed;
|
||||
public int RoundsWeeklyWon;
|
||||
public byte Bracket;
|
||||
public bool Disqualified;
|
||||
}
|
||||
|
||||
public struct TraitInspectInfo
|
||||
{
|
||||
public int Level;
|
||||
public int ChrSpecializationID;
|
||||
public TraitConfig Config;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data . WriteInt32(Level);
|
||||
data . WriteInt32(ChrSpecializationID);
|
||||
Config.Write(data);
|
||||
}
|
||||
}
|
||||
|
||||
public struct AzeriteEssenceData
|
||||
{
|
||||
public uint Index;
|
||||
|
||||
@@ -20,6 +20,7 @@ using Framework.Dynamic;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Game.Networking.Packets
|
||||
{
|
||||
@@ -429,14 +430,26 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt32(BattlePetBreedQuality);
|
||||
_worldPacket.WriteInt32(BattlePetLevel);
|
||||
_worldPacket.WritePackedGuid(ItemGUID);
|
||||
_worldPacket.WriteInt32(Toasts.Count);
|
||||
foreach (UiEventToast uiEventToast in Toasts)
|
||||
uiEventToast.Write(_worldPacket);
|
||||
|
||||
_worldPacket.WriteBit(Pushed);
|
||||
_worldPacket.WriteBit(Created);
|
||||
_worldPacket.WriteBits((uint)DisplayText, 3);
|
||||
_worldPacket.WriteBit(IsBonusRoll);
|
||||
_worldPacket.WriteBit(IsEncounterLoot);
|
||||
_worldPacket.WriteBit(CraftingData != null);
|
||||
_worldPacket.WriteBit(FirstCraftOperationID.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
Item.Write(_worldPacket);
|
||||
Item.Write(_worldPacket);
|
||||
|
||||
if (FirstCraftOperationID.HasValue)
|
||||
_worldPacket.WriteUInt32(FirstCraftOperationID.Value);
|
||||
|
||||
if (CraftingData != null)
|
||||
CraftingData.Write(_worldPacket);
|
||||
}
|
||||
|
||||
public ObjectGuid PlayerGUID;
|
||||
@@ -444,7 +457,7 @@ namespace Game.Networking.Packets
|
||||
public int SlotInBag;
|
||||
public ItemInstance Item;
|
||||
public int QuestLogItemID;// Item ID used for updating quest progress
|
||||
// only set if different than real ID (similar to CreatureTemplate.KillCredit)
|
||||
// only set if different than real ID (similar to CreatureTemplate.KillCredit)
|
||||
public uint Quantity;
|
||||
public uint QuantityInInventory;
|
||||
public int DungeonEncounterID;
|
||||
@@ -453,6 +466,9 @@ namespace Game.Networking.Packets
|
||||
public uint BattlePetBreedQuality;
|
||||
public int BattlePetLevel;
|
||||
public ObjectGuid ItemGUID;
|
||||
public List<UiEventToast> Toasts = new();
|
||||
public CraftingData CraftingData;
|
||||
public uint? FirstCraftOperationID;
|
||||
public bool Pushed;
|
||||
public DisplayType DisplayText;
|
||||
public bool Created;
|
||||
@@ -528,7 +544,7 @@ namespace Game.Networking.Packets
|
||||
public EnchantmentLog() : base(ServerOpcodes.EnchantmentLog, ConnectionType.Instance) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Owner);
|
||||
_worldPacket.WritePackedGuid(Caster);
|
||||
_worldPacket.WritePackedGuid(ItemGUID);
|
||||
@@ -572,7 +588,7 @@ namespace Game.Networking.Packets
|
||||
public uint SpellID;
|
||||
public uint Cooldown;
|
||||
}
|
||||
|
||||
|
||||
class ItemEnchantTimeUpdate : ServerPacket
|
||||
{
|
||||
public ItemEnchantTimeUpdate() : base(ServerOpcodes.ItemEnchantTimeUpdate, ConnectionType.Instance) { }
|
||||
@@ -741,7 +757,7 @@ namespace Game.Networking.Packets
|
||||
}
|
||||
|
||||
public class ItemMod
|
||||
{
|
||||
{
|
||||
public uint Value;
|
||||
public ItemModifier Type;
|
||||
|
||||
@@ -858,7 +874,7 @@ namespace Game.Networking.Packets
|
||||
public ItemInstance(Item item)
|
||||
{
|
||||
ItemID = item.GetEntry();
|
||||
List<uint> bonusListIds = item.m_itemData.BonusListIDs;
|
||||
List<uint> bonusListIds = item.GetBonusListIDs();
|
||||
if (!bonusListIds.Empty())
|
||||
{
|
||||
ItemBonus = new();
|
||||
@@ -984,8 +1000,44 @@ namespace Game.Networking.Packets
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemBonusKey : IEquatable<ItemBonusKey>
|
||||
{
|
||||
public uint ItemID;
|
||||
public List<uint> BonusListIDs = new();
|
||||
public List<ItemMod> Modifications = new();
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteUInt32(ItemID);
|
||||
data.WriteInt32(BonusListIDs.Count);
|
||||
data.WriteInt32(Modifications.Count);
|
||||
|
||||
if (!BonusListIDs.Empty())
|
||||
foreach (var id in BonusListIDs)
|
||||
data.WriteUInt32(id);
|
||||
|
||||
foreach (ItemMod modification in Modifications)
|
||||
modification.Write(data);
|
||||
}
|
||||
|
||||
public bool Equals(ItemBonusKey right)
|
||||
{
|
||||
if (ItemID != right.ItemID)
|
||||
return false;
|
||||
|
||||
if (BonusListIDs != right.BonusListIDs)
|
||||
return false;
|
||||
|
||||
if (Modifications != right.Modifications)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class ItemEnchantData
|
||||
{
|
||||
public ItemEnchantData() { }
|
||||
public ItemEnchantData(uint id, uint expiration, int charges, byte slot)
|
||||
{
|
||||
ID = id;
|
||||
@@ -1093,4 +1145,16 @@ namespace Game.Networking.Packets
|
||||
public ItemPurchaseRefundItem[] Items = new ItemPurchaseRefundItem[5];
|
||||
public ItemPurchaseRefundCurrency[] Currencies = new ItemPurchaseRefundCurrency[5];
|
||||
}
|
||||
|
||||
public struct UiEventToast
|
||||
{
|
||||
public int UiEventToastID;
|
||||
public int Asset;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(UiEventToastID);
|
||||
data.WriteInt32(Asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,9 +29,11 @@ namespace Game.Networking.Packets
|
||||
public override void Read()
|
||||
{
|
||||
Unit = _worldPacket.ReadPackedGuid();
|
||||
IsSoftInteract = _worldPacket.HasBit();
|
||||
}
|
||||
|
||||
public ObjectGuid Unit;
|
||||
public bool IsSoftInteract;
|
||||
}
|
||||
|
||||
public class LootResponse : ServerPacket
|
||||
@@ -273,6 +275,9 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteInt32(MapID);
|
||||
_worldPacket.WriteUInt32(RollTime);
|
||||
_worldPacket.WriteUInt8((byte)ValidRolls);
|
||||
foreach (var reason in LootRollIneligibleReason)
|
||||
_worldPacket.WriteUInt32((uint)reason);
|
||||
|
||||
_worldPacket.WriteUInt8((byte)Method);
|
||||
Item.Write(_worldPacket);
|
||||
}
|
||||
@@ -282,6 +287,7 @@ namespace Game.Networking.Packets
|
||||
public uint RollTime;
|
||||
public LootMethod Method;
|
||||
public RollMask ValidRolls;
|
||||
public Array<LootRollIneligibilityReason> LootRollIneligibleReason = new Array<LootRollIneligibilityReason>(4);
|
||||
public LootItemData Item = new();
|
||||
}
|
||||
|
||||
|
||||
@@ -293,18 +293,6 @@ namespace Game.Networking.Packets
|
||||
public float Delay = 0.0f;
|
||||
}
|
||||
|
||||
class ShowMailbox : ServerPacket
|
||||
{
|
||||
public ShowMailbox() : base(ServerOpcodes.ShowMailbox) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(PostmasterGUID);
|
||||
}
|
||||
|
||||
public ObjectGuid PostmasterGUID;
|
||||
}
|
||||
|
||||
//Structs
|
||||
public class MailAttachedItem
|
||||
{
|
||||
|
||||
@@ -58,21 +58,6 @@ namespace Game.Networking.Packets
|
||||
uint AreaID;
|
||||
}
|
||||
|
||||
public class BinderConfirm : ServerPacket
|
||||
{
|
||||
public BinderConfirm(ObjectGuid unit) : base(ServerOpcodes.BinderConfirm)
|
||||
{
|
||||
Unit = unit;
|
||||
}
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Unit);
|
||||
}
|
||||
|
||||
ObjectGuid Unit;
|
||||
}
|
||||
|
||||
public class InvalidatePlayer : ServerPacket
|
||||
{
|
||||
public InvalidatePlayer() : base(ServerOpcodes.InvalidatePlayer) { }
|
||||
@@ -124,11 +109,13 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(WeeklyQuantity.HasValue);
|
||||
_worldPacket.WriteBit(TrackedQuantity.HasValue);
|
||||
_worldPacket.WriteBit(MaxQuantity.HasValue);
|
||||
_worldPacket.WriteBit(Unused901.HasValue);
|
||||
_worldPacket.WriteBit(TotalEarned.HasValue);
|
||||
_worldPacket.WriteBit(SuppressChatLog);
|
||||
_worldPacket.WriteBit(QuantityChange.HasValue);
|
||||
_worldPacket.WriteBit(QuantityGainSource.HasValue);
|
||||
_worldPacket.WriteBit(QuantityLostSource.HasValue);
|
||||
_worldPacket.WriteBit(QuantityGainSource.HasValue);
|
||||
_worldPacket.WriteBit(FirstCraftOperationID.HasValue);
|
||||
_worldPacket.WriteBit(LastSpendTime.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
if (WeeklyQuantity.HasValue)
|
||||
@@ -140,29 +127,38 @@ namespace Game.Networking.Packets
|
||||
if (MaxQuantity.HasValue)
|
||||
_worldPacket.WriteInt32(MaxQuantity.Value);
|
||||
|
||||
if (Unused901.HasValue)
|
||||
_worldPacket.WriteInt32(Unused901.Value);
|
||||
if (TotalEarned.HasValue)
|
||||
_worldPacket.WriteInt32(TotalEarned.Value);
|
||||
|
||||
if (QuantityChange.HasValue)
|
||||
_worldPacket.WriteInt32(QuantityChange.Value);
|
||||
|
||||
if (QuantityLostSource.HasValue)
|
||||
_worldPacket.WriteInt32(QuantityLostSource.Value);
|
||||
|
||||
if (QuantityGainSource.HasValue)
|
||||
_worldPacket.WriteInt32(QuantityGainSource.Value);
|
||||
|
||||
if (QuantityLostSource.HasValue)
|
||||
_worldPacket.WriteInt32(QuantityLostSource.Value);
|
||||
if (FirstCraftOperationID.HasValue)
|
||||
_worldPacket.WriteUInt32(FirstCraftOperationID.Value);
|
||||
|
||||
if (LastSpendTime.HasValue)
|
||||
_worldPacket.WriteInt64(LastSpendTime.Value);
|
||||
}
|
||||
|
||||
public uint Type;
|
||||
public int Quantity;
|
||||
public uint Flags;
|
||||
public List<UiEventToast> Toasts = new();
|
||||
public int? WeeklyQuantity;
|
||||
public int? TrackedQuantity;
|
||||
public int? MaxQuantity;
|
||||
public int? Unused901;
|
||||
public int? TotalEarned;
|
||||
public int? QuantityChange;
|
||||
public int? QuantityGainSource;
|
||||
public int? QuantityLostSource;
|
||||
public uint? FirstCraftOperationID;
|
||||
public long? LastSpendTime;
|
||||
public bool SuppressChatLog;
|
||||
}
|
||||
|
||||
@@ -209,7 +205,8 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(data.MaxWeeklyQuantity.HasValue);
|
||||
_worldPacket.WriteBit(data.TrackedQuantity.HasValue);
|
||||
_worldPacket.WriteBit(data.MaxQuantity.HasValue);
|
||||
_worldPacket.WriteBit(data.Unused901.HasValue);
|
||||
_worldPacket.WriteBit(data.TotalEarned.HasValue);
|
||||
_worldPacket.WriteBit(data.LastSpendTime.HasValue);
|
||||
_worldPacket.WriteBits(data.Flags, 5);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
@@ -221,8 +218,10 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt32(data.TrackedQuantity.Value);
|
||||
if (data.MaxQuantity.HasValue)
|
||||
_worldPacket.WriteInt32(data.MaxQuantity.Value);
|
||||
if (data.Unused901.HasValue)
|
||||
_worldPacket.WriteInt32(data.Unused901.Value);
|
||||
if (data.TotalEarned.HasValue)
|
||||
_worldPacket.WriteInt32(data.TotalEarned.Value);
|
||||
if (data.LastSpendTime.HasValue)
|
||||
_worldPacket.WriteInt64(data.LastSpendTime.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,7 +235,8 @@ namespace Game.Networking.Packets
|
||||
public uint? MaxWeeklyQuantity; // Weekly Currency cap.
|
||||
public uint? TrackedQuantity;
|
||||
public int? MaxQuantity;
|
||||
public int? Unused901;
|
||||
public int? TotalEarned;
|
||||
public long? LastSpendTime;
|
||||
public byte Flags; // 0 = none,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ namespace Game.Networking.Packets
|
||||
data.ReadBit(); // HeightChangeFailed
|
||||
data.ReadBit(); // RemoteTimeValid
|
||||
bool hasInertia = data.HasBit();
|
||||
bool hasAdvFlying = data.HasBit();
|
||||
|
||||
if (hasTransport)
|
||||
ReadTransportInfo(data, ref movementInfo.transport);
|
||||
@@ -113,13 +114,22 @@ namespace Game.Networking.Packets
|
||||
if (hasInertia)
|
||||
{
|
||||
MovementInfo.Inertia inertia = new();
|
||||
inertia.guid = data.ReadPackedGuid();
|
||||
inertia.id = data.ReadInt32();
|
||||
inertia.force = data.ReadPosition();
|
||||
inertia.lifetime = data.ReadUInt32();
|
||||
|
||||
movementInfo.inertia = inertia;
|
||||
}
|
||||
|
||||
if (hasAdvFlying)
|
||||
{
|
||||
MovementInfo.AdvFlying advFlying = new();
|
||||
|
||||
advFlying.forwardVelocity = data.ReadFloat();
|
||||
advFlying.upVelocity = data.ReadFloat();
|
||||
movementInfo.advFlying = advFlying;
|
||||
}
|
||||
|
||||
if (hasFall)
|
||||
{
|
||||
movementInfo.jump.fallTime = data.ReadUInt32();
|
||||
@@ -146,6 +156,7 @@ namespace Game.Networking.Packets
|
||||
bool hasFallData = hasFallDirection || movementInfo.jump.fallTime != 0;
|
||||
bool hasSpline = false; // todo 6.x send this infos
|
||||
bool hasInertia = movementInfo.inertia.HasValue;
|
||||
bool hasAdvFlying = movementInfo.advFlying.HasValue;
|
||||
|
||||
data.WritePackedGuid(movementInfo.Guid);
|
||||
data.WriteUInt32((uint)movementInfo.GetMovementFlags());
|
||||
@@ -176,6 +187,7 @@ namespace Game.Networking.Packets
|
||||
data.WriteBit(false); // HeightChangeFailed
|
||||
data.WriteBit(false); // RemoteTimeValid
|
||||
data.WriteBit(hasInertia);
|
||||
data.WriteBit(hasAdvFlying);
|
||||
data.FlushBits();
|
||||
|
||||
if (hasTransportData)
|
||||
@@ -183,11 +195,17 @@ namespace Game.Networking.Packets
|
||||
|
||||
if (hasInertia)
|
||||
{
|
||||
data.WritePackedGuid(movementInfo.inertia.Value.guid);
|
||||
data.WriteInt32(movementInfo.inertia.Value.id);
|
||||
data.WriteXYZ(movementInfo.inertia.Value.force);
|
||||
data.WriteUInt32(movementInfo.inertia.Value.lifetime);
|
||||
}
|
||||
|
||||
if (hasAdvFlying)
|
||||
{
|
||||
data.WriteFloat(movementInfo.advFlying.Value.forwardVelocity);
|
||||
data.WriteFloat(movementInfo.advFlying.Value.upVelocity);
|
||||
}
|
||||
|
||||
if (hasFallData)
|
||||
{
|
||||
data.WriteUInt32(movementInfo.jump.fallTime);
|
||||
@@ -514,7 +532,7 @@ namespace Game.Networking.Packets
|
||||
}
|
||||
|
||||
public ObjectGuid MoverGUID;
|
||||
public uint SequenceIndex = 0; // Unit movement packet index, incremented each time
|
||||
public uint SequenceIndex; // Unit movement packet index, incremented each time
|
||||
public float Speed = 1.0f;
|
||||
}
|
||||
|
||||
@@ -555,7 +573,7 @@ namespace Game.Networking.Packets
|
||||
}
|
||||
|
||||
public ObjectGuid MoverGUID;
|
||||
public uint SequenceIndex = 0; // Unit movement packet index, incremented each time
|
||||
public uint SequenceIndex; // Unit movement packet index, incremented each time
|
||||
}
|
||||
|
||||
public class TransferPending : ServerPacket
|
||||
@@ -1167,6 +1185,12 @@ namespace Game.Networking.Packets
|
||||
public float InitVertSpeed;
|
||||
}
|
||||
|
||||
public class SpeedRange
|
||||
{
|
||||
public float Min;
|
||||
public float Max;
|
||||
}
|
||||
|
||||
public class MoveStateChange
|
||||
{
|
||||
public MoveStateChange(ServerOpcodes messageId, uint sequenceIndex)
|
||||
@@ -1180,12 +1204,13 @@ namespace Game.Networking.Packets
|
||||
data.WriteUInt16((ushort)MessageID);
|
||||
data.WriteUInt32(SequenceIndex);
|
||||
data.WriteBit(Speed.HasValue);
|
||||
data.WriteBit(SpeedRange != null);
|
||||
data.WriteBit(KnockBack.HasValue);
|
||||
data.WriteBit(VehicleRecID.HasValue);
|
||||
data.WriteBit(CollisionHeight.HasValue);
|
||||
data.WriteBit(@MovementForce != null);
|
||||
data.WriteBit(MovementForceGUID.HasValue);
|
||||
data.WriteBit(MovementInertiaGUID.HasValue);
|
||||
data.WriteBit(MovementInertiaID.HasValue);
|
||||
data.WriteBit(MovementInertiaLifetimeMs.HasValue);
|
||||
data.FlushBits();
|
||||
|
||||
@@ -1195,6 +1220,12 @@ namespace Game.Networking.Packets
|
||||
if (Speed.HasValue)
|
||||
data.WriteFloat(Speed.Value);
|
||||
|
||||
if (SpeedRange != null)
|
||||
{
|
||||
data.WriteFloat(SpeedRange.Min);
|
||||
data.WriteFloat(SpeedRange.Max);
|
||||
}
|
||||
|
||||
if (KnockBack.HasValue)
|
||||
{
|
||||
data.WriteFloat(KnockBack.Value.HorzSpeed);
|
||||
@@ -1216,8 +1247,8 @@ namespace Game.Networking.Packets
|
||||
if (MovementForceGUID.HasValue)
|
||||
data.WritePackedGuid(MovementForceGUID.Value);
|
||||
|
||||
if (MovementInertiaGUID.HasValue)
|
||||
data.WritePackedGuid(MovementInertiaGUID.Value);
|
||||
if (MovementInertiaID.HasValue)
|
||||
data.WriteInt32(MovementInertiaID.Value);
|
||||
|
||||
if (MovementInertiaLifetimeMs.HasValue)
|
||||
data.WriteUInt32(MovementInertiaLifetimeMs.Value);
|
||||
@@ -1226,12 +1257,13 @@ namespace Game.Networking.Packets
|
||||
public ServerOpcodes MessageID;
|
||||
public uint SequenceIndex;
|
||||
public float? Speed;
|
||||
public SpeedRange SpeedRange;
|
||||
public KnockBackInfo? KnockBack;
|
||||
public int? VehicleRecID;
|
||||
public CollisionHeightInfo? CollisionHeight;
|
||||
public MovementForce MovementForce;
|
||||
public ObjectGuid? MovementForceGUID;
|
||||
public ObjectGuid? MovementInertiaGUID;
|
||||
public int? MovementInertiaID;
|
||||
public uint? MovementInertiaLifetimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,6 +43,23 @@ namespace Game.Networking.Packets
|
||||
public ObjectGuid Unit;
|
||||
}
|
||||
|
||||
public class NPCInteractionOpenResult : ServerPacket
|
||||
{
|
||||
public NPCInteractionOpenResult() : base(ServerOpcodes.NpcInteractionOpenResult) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Npc);
|
||||
_worldPacket.WriteInt32((int)InteractionType);
|
||||
_worldPacket.WriteBit(Success);
|
||||
_worldPacket.FlushBits();
|
||||
}
|
||||
|
||||
public ObjectGuid Npc;
|
||||
public PlayerInteractionType InteractionType;
|
||||
public bool Success = true;
|
||||
}
|
||||
|
||||
public class GossipMessagePkt : ServerPacket
|
||||
{
|
||||
public GossipMessagePkt() : base(ServerOpcodes.GossipMessage) { }
|
||||
@@ -52,33 +69,20 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WritePackedGuid(GossipGUID);
|
||||
_worldPacket.WriteUInt32(GossipID);
|
||||
_worldPacket.WriteInt32(FriendshipFactionID);
|
||||
_worldPacket.WriteInt32(TextID);
|
||||
|
||||
_worldPacket.WriteInt32(GossipOptions.Count);
|
||||
_worldPacket.WriteInt32(GossipText.Count);
|
||||
_worldPacket.WriteBit(TextID.HasValue);
|
||||
_worldPacket.WriteBit(TextID2.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
foreach (ClientGossipOptions options in GossipOptions)
|
||||
{
|
||||
_worldPacket.WriteInt32(options.ClientOption);
|
||||
_worldPacket.WriteUInt8((byte)options.OptionNPC);
|
||||
_worldPacket.WriteUInt8(options.OptionFlags);
|
||||
_worldPacket.WriteInt32(options.OptionCost);
|
||||
_worldPacket.WriteUInt32(options.OptionLanguage);
|
||||
options.Write(_worldPacket);
|
||||
|
||||
_worldPacket.WriteBits(options.Text.GetByteCount(), 12);
|
||||
_worldPacket.WriteBits(options.Confirm.GetByteCount(), 12);
|
||||
_worldPacket.WriteBits((byte)options.Status, 2);
|
||||
_worldPacket.WriteBit(options.SpellID.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
if (TextID.HasValue)
|
||||
_worldPacket.WriteInt32(TextID.Value);
|
||||
|
||||
options.Treasure.Write(_worldPacket);
|
||||
|
||||
_worldPacket.WriteString(options.Text);
|
||||
_worldPacket.WriteString(options.Confirm);
|
||||
|
||||
if (options.SpellID.HasValue)
|
||||
_worldPacket.WriteInt32(options.SpellID.Value);
|
||||
}
|
||||
if (TextID2.HasValue)
|
||||
_worldPacket.WriteInt32(TextID2.Value);
|
||||
|
||||
foreach (ClientGossipText text in GossipText)
|
||||
text.Write(_worldPacket);
|
||||
@@ -88,7 +92,8 @@ namespace Game.Networking.Packets
|
||||
public int FriendshipFactionID;
|
||||
public ObjectGuid GossipGUID;
|
||||
public List<ClientGossipText> GossipText = new();
|
||||
public int TextID;
|
||||
public int? TextID;
|
||||
public int? TextID2;
|
||||
public uint GossipID;
|
||||
}
|
||||
|
||||
@@ -100,18 +105,38 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
GossipUnit = _worldPacket.ReadPackedGuid();
|
||||
GossipID = _worldPacket.ReadUInt32();
|
||||
GossipIndex = _worldPacket.ReadUInt32();
|
||||
GossipOptionID = _worldPacket.ReadInt32();
|
||||
|
||||
uint length = _worldPacket.ReadBits<uint>(8);
|
||||
PromotionCode = _worldPacket.ReadString(length);
|
||||
}
|
||||
|
||||
public ObjectGuid GossipUnit;
|
||||
public uint GossipIndex;
|
||||
public int GossipOptionID;
|
||||
public uint GossipID;
|
||||
public string PromotionCode;
|
||||
}
|
||||
|
||||
class GossipOptionNPCInteraction : ServerPacket
|
||||
{
|
||||
public GossipOptionNPCInteraction() : base(ServerOpcodes.GossipOptionNpcInteraction) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(GossipGUID);
|
||||
_worldPacket.WriteInt32(GossipNpcOptionID);
|
||||
_worldPacket.WriteBit(FriendshipFactionID.HasValue);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
if (FriendshipFactionID.HasValue)
|
||||
_worldPacket.WriteInt32(FriendshipFactionID.Value);
|
||||
}
|
||||
|
||||
public ObjectGuid GossipGUID;
|
||||
public int GossipNpcOptionID;
|
||||
public int? FriendshipFactionID;
|
||||
}
|
||||
|
||||
public class GossipComplete : ServerPacket
|
||||
{
|
||||
public bool SuppressSound;
|
||||
@@ -181,30 +206,6 @@ namespace Game.Networking.Packets
|
||||
public string Greeting;
|
||||
}
|
||||
|
||||
public class ShowBank : ServerPacket
|
||||
{
|
||||
public ShowBank() : base(ServerOpcodes.ShowBank, ConnectionType.Instance) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Guid);
|
||||
}
|
||||
|
||||
public ObjectGuid Guid;
|
||||
}
|
||||
|
||||
public class PlayerTabardVendorActivate : ServerPacket
|
||||
{
|
||||
public PlayerTabardVendorActivate() : base(ServerOpcodes.PlayerTabardVendorActivate) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Vendor);
|
||||
}
|
||||
|
||||
public ObjectGuid Vendor;
|
||||
}
|
||||
|
||||
class GossipPOI : ServerPacket
|
||||
{
|
||||
public GossipPOI() : base(ServerOpcodes.GossipPoi) { }
|
||||
@@ -243,18 +244,6 @@ namespace Game.Networking.Packets
|
||||
public ObjectGuid Healer;
|
||||
}
|
||||
|
||||
public class SpiritHealerConfirm : ServerPacket
|
||||
{
|
||||
public SpiritHealerConfirm() : base(ServerOpcodes.SpiritHealerConfirm) { }
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Unit);
|
||||
}
|
||||
|
||||
public ObjectGuid Unit;
|
||||
}
|
||||
|
||||
class TrainerBuySpell : ClientPacket
|
||||
{
|
||||
public TrainerBuySpell(WorldPacket packet) : base(packet) { }
|
||||
@@ -344,16 +333,47 @@ namespace Game.Networking.Packets
|
||||
|
||||
public class ClientGossipOptions
|
||||
{
|
||||
public int ClientOption;
|
||||
public int GossipOptionID;
|
||||
public GossipOptionNpc OptionNPC;
|
||||
public byte OptionFlags;
|
||||
public int OptionCost;
|
||||
public uint OptionLanguage;
|
||||
public GossipOptionFlags Flags;
|
||||
public int OrderIndex;
|
||||
public GossipOptionStatus Status;
|
||||
public string Text;
|
||||
public string Confirm;
|
||||
public string Text = "";
|
||||
public string Confirm = "";
|
||||
public TreasureLootList Treasure = new();
|
||||
public int? SpellID;
|
||||
public int? OverrideIconID;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(GossipOptionID);
|
||||
data.WriteUInt8((byte)OptionNPC);
|
||||
data.WriteInt8((sbyte)OptionFlags);
|
||||
data.WriteInt32(OptionCost);
|
||||
data.WriteUInt32(OptionLanguage);
|
||||
data.WriteInt32((int)Flags);
|
||||
data.WriteInt32(OrderIndex);
|
||||
data.WriteBits(Text.GetByteCount(), 12);
|
||||
data.WriteBits(Confirm.GetByteCount(), 12);
|
||||
data.WriteBits((byte)Status, 2);
|
||||
data.WriteBit(SpellID.HasValue);
|
||||
data.WriteBit(OverrideIconID.HasValue);
|
||||
data.FlushBits();
|
||||
|
||||
Treasure.Write(data);
|
||||
|
||||
data.WriteString(Text);
|
||||
data.WriteString(Confirm);
|
||||
|
||||
if (SpellID.HasValue)
|
||||
data.WriteInt32(SpellID.Value);
|
||||
|
||||
if (OverrideIconID.HasValue)
|
||||
data.WriteInt32(OverrideIconID.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public class ClientGossipText
|
||||
@@ -386,19 +406,20 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(MuID);
|
||||
data.WriteInt32(Type);
|
||||
data.WriteInt32(Quantity);
|
||||
data.WriteUInt64(Price);
|
||||
data.WriteInt32(MuID);
|
||||
data.WriteInt32(Durability);
|
||||
data.WriteInt32(StackCount);
|
||||
data.WriteInt32(Quantity);
|
||||
data.WriteInt32(ExtendedCostID);
|
||||
data.WriteInt32(PlayerConditionFailed);
|
||||
Item.Write(data);
|
||||
data.WriteBits(Type, 3);
|
||||
data.WriteBit(Locked);
|
||||
data.WriteBit(DoNotFilterOnVendor);
|
||||
data.WriteBit(Refundable);
|
||||
data.FlushBits();
|
||||
|
||||
Item.Write(data);
|
||||
}
|
||||
|
||||
public int MuID;
|
||||
|
||||
@@ -197,6 +197,10 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteInt32(Info.Expansion);
|
||||
_worldPacket.WriteInt32(Info.ManagedWorldStateID);
|
||||
_worldPacket.WriteInt32(Info.QuestSessionBonus);
|
||||
_worldPacket.WriteInt32(Info.QuestGiverCreatureID);
|
||||
|
||||
_worldPacket.WriteInt32(Info.ConditionalQuestDescription.Count);
|
||||
_worldPacket.WriteInt32(Info.ConditionalQuestCompletionLog.Count);
|
||||
|
||||
foreach (QuestCompleteDisplaySpell rewardDisplaySpell in Info.RewardDisplaySpell)
|
||||
rewardDisplaySpell.Write(_worldPacket);
|
||||
@@ -243,6 +247,12 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteString(Info.PortraitTurnInText);
|
||||
_worldPacket.WriteString(Info.PortraitTurnInName);
|
||||
_worldPacket.WriteString(Info.QuestCompletionLog);
|
||||
|
||||
foreach (ConditionalQuestText conditionalQuestText in Info.ConditionalQuestDescription)
|
||||
conditionalQuestText.Write(_worldPacket);
|
||||
|
||||
foreach (ConditionalQuestText conditionalQuestText in Info.ConditionalQuestCompletionLog)
|
||||
conditionalQuestText.Write(_worldPacket);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,6 +325,8 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt32(PortraitGiverMount);
|
||||
_worldPacket.WriteInt32(PortraitGiverModelSceneID);
|
||||
_worldPacket.WriteUInt32(PortraitTurnIn);
|
||||
_worldPacket.WriteUInt32(QuestGiverCreatureID);
|
||||
_worldPacket.WriteInt32(ConditionalRewardText.Count);
|
||||
|
||||
_worldPacket.WriteBits(QuestTitle.GetByteCount(), 9);
|
||||
_worldPacket.WriteBits(RewardText.GetByteCount(), 12);
|
||||
@@ -322,6 +334,10 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBits(PortraitGiverName.GetByteCount(), 8);
|
||||
_worldPacket.WriteBits(PortraitTurnInText.GetByteCount(), 10);
|
||||
_worldPacket.WriteBits(PortraitTurnInName.GetByteCount(), 8);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
foreach (ConditionalQuestText conditionalQuestText in ConditionalRewardText)
|
||||
conditionalQuestText.Write(_worldPacket);
|
||||
|
||||
_worldPacket.WriteString(QuestTitle);
|
||||
_worldPacket.WriteString(RewardText);
|
||||
@@ -335,12 +351,14 @@ namespace Game.Networking.Packets
|
||||
public uint PortraitGiver;
|
||||
public uint PortraitGiverMount;
|
||||
public int PortraitGiverModelSceneID;
|
||||
public uint QuestGiverCreatureID;
|
||||
public string QuestTitle = "";
|
||||
public string RewardText = "";
|
||||
public string PortraitGiverText = "";
|
||||
public string PortraitGiverName = "";
|
||||
public string PortraitTurnInText = "";
|
||||
public string PortraitTurnInName = "";
|
||||
public List<ConditionalQuestText> ConditionalRewardText = new();
|
||||
public QuestGiverOfferReward QuestData;
|
||||
public uint QuestPackageID;
|
||||
}
|
||||
@@ -437,12 +455,15 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt32(PortraitTurnIn);
|
||||
_worldPacket.WriteUInt32(QuestFlags[0]); // Flags
|
||||
_worldPacket.WriteUInt32(QuestFlags[1]); // FlagsEx
|
||||
_worldPacket.WriteUInt32(QuestFlags[2]); // FlagsEx
|
||||
_worldPacket.WriteUInt32(SuggestedPartyMembers);
|
||||
_worldPacket.WriteInt32(LearnSpells.Count);
|
||||
_worldPacket.WriteInt32(DescEmotes.Count);
|
||||
_worldPacket.WriteInt32(Objectives.Count);
|
||||
_worldPacket.WriteInt32(QuestStartItemID);
|
||||
_worldPacket.WriteInt32(QuestSessionBonus);
|
||||
_worldPacket.WriteInt32(QuestGiverCreatureID);
|
||||
_worldPacket.WriteInt32(ConditionalDescriptionText.Count);
|
||||
|
||||
foreach (uint spell in LearnSpells)
|
||||
_worldPacket.WriteUInt32(spell);
|
||||
@@ -483,13 +504,16 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteString(PortraitGiverName);
|
||||
_worldPacket.WriteString(PortraitTurnInText);
|
||||
_worldPacket.WriteString(PortraitTurnInName);
|
||||
|
||||
foreach (ConditionalQuestText conditionalQuestText in ConditionalDescriptionText)
|
||||
conditionalQuestText.Write(_worldPacket);
|
||||
}
|
||||
|
||||
public ObjectGuid QuestGiverGUID;
|
||||
public ObjectGuid InformUnit;
|
||||
public uint QuestID;
|
||||
public int QuestPackageID;
|
||||
public uint[] QuestFlags = new uint[2];
|
||||
public uint[] QuestFlags = new uint[3];
|
||||
public uint SuggestedPartyMembers;
|
||||
public QuestRewards Rewards = new();
|
||||
public List<QuestObjectiveSimple> Objectives = new();
|
||||
@@ -501,6 +525,7 @@ namespace Game.Networking.Packets
|
||||
public int PortraitGiverModelSceneID;
|
||||
public int QuestStartItemID;
|
||||
public int QuestSessionBonus;
|
||||
public int QuestGiverCreatureID;
|
||||
public string PortraitGiverText = "";
|
||||
public string PortraitGiverName = "";
|
||||
public string PortraitTurnInText = "";
|
||||
@@ -508,6 +533,7 @@ namespace Game.Networking.Packets
|
||||
public string QuestTitle = "";
|
||||
public string LogDescription = "";
|
||||
public string DescriptionText = "";
|
||||
public List<ConditionalQuestText> ConditionalDescriptionText = new();
|
||||
public bool DisplayPopup;
|
||||
public bool StartCheat;
|
||||
public bool AutoLaunched;
|
||||
@@ -526,6 +552,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteUInt32(CompEmoteType);
|
||||
_worldPacket.WriteUInt32(QuestFlags[0]);
|
||||
_worldPacket.WriteUInt32(QuestFlags[1]);
|
||||
_worldPacket.WriteUInt32(QuestFlags[2]);
|
||||
_worldPacket.WriteUInt32(SuggestPartyMembers);
|
||||
_worldPacket.WriteInt32(MoneyToGet);
|
||||
_worldPacket.WriteInt32(Collect.Count);
|
||||
@@ -547,8 +574,15 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(AutoLaunched);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
_worldPacket.WriteUInt32(QuestGiverCreatureID);
|
||||
_worldPacket.WriteInt32(ConditionalCompletionText.Count);
|
||||
|
||||
_worldPacket.WriteBits(QuestTitle.GetByteCount(), 9);
|
||||
_worldPacket.WriteBits(CompletionText.GetByteCount(), 12);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
foreach (ConditionalQuestText conditionalQuestText in ConditionalCompletionText)
|
||||
conditionalQuestText.Write(_worldPacket);
|
||||
|
||||
_worldPacket.WriteString(QuestTitle);
|
||||
_worldPacket.WriteString(CompletionText);
|
||||
@@ -565,9 +599,10 @@ namespace Game.Networking.Packets
|
||||
public List<QuestObjectiveCollect> Collect = new();
|
||||
public List<QuestCurrency> Currency = new();
|
||||
public int StatusFlags;
|
||||
public uint[] QuestFlags = new uint[2];
|
||||
public uint[] QuestFlags = new uint[3];
|
||||
public string QuestTitle = "";
|
||||
public string CompletionText = "";
|
||||
public List<ConditionalQuestText> ConditionalCompletionText = new();
|
||||
}
|
||||
|
||||
public class QuestGiverRequestReward : ClientPacket
|
||||
@@ -937,6 +972,30 @@ namespace Game.Networking.Packets
|
||||
}
|
||||
}
|
||||
|
||||
public class ConditionalQuestText
|
||||
{
|
||||
public int PlayerConditionID;
|
||||
public int QuestGiverCreatureID;
|
||||
public string Text = "";
|
||||
|
||||
public ConditionalQuestText(int playerConditionID, int questGiverCreatureID, string text)
|
||||
{
|
||||
PlayerConditionID = playerConditionID;
|
||||
QuestGiverCreatureID = questGiverCreatureID;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(PlayerConditionID);
|
||||
data.WriteInt32(QuestGiverCreatureID);
|
||||
data.WriteBits(Text.GetByteCount(), 12);
|
||||
data.FlushBits();
|
||||
|
||||
data.WriteString(Text);
|
||||
}
|
||||
}
|
||||
|
||||
public class QuestInfo
|
||||
{
|
||||
public QuestInfo()
|
||||
@@ -1008,7 +1067,10 @@ namespace Game.Networking.Packets
|
||||
public int Expansion;
|
||||
public int ManagedWorldStateID;
|
||||
public int QuestSessionBonus;
|
||||
public int QuestGiverCreatureID; // used to select ConditionalQuestText
|
||||
public List<QuestObjective> Objectives = new();
|
||||
public List<ConditionalQuestText> ConditionalQuestDescription = new();
|
||||
public List<ConditionalQuestText> ConditionalQuestCompletionLog = new();
|
||||
public uint[] RewardItems = new uint[SharedConst.QuestRewardItemCount];
|
||||
public uint[] RewardAmount = new uint[SharedConst.QuestRewardItemCount];
|
||||
public int[] ItemDrop = new int[SharedConst.QuestItemDropCount];
|
||||
@@ -1144,6 +1206,7 @@ namespace Game.Networking.Packets
|
||||
data.WriteUInt32(QuestID);
|
||||
data.WriteUInt32(QuestFlags[0]); // Flags
|
||||
data.WriteUInt32(QuestFlags[1]); // FlagsEx
|
||||
data.WriteUInt32(QuestFlags[2]); // FlagsEx2
|
||||
data.WriteUInt32(SuggestedPartyMembers);
|
||||
|
||||
data.WriteInt32(Emotes.Count);
|
||||
@@ -1167,7 +1230,7 @@ namespace Game.Networking.Packets
|
||||
public uint SuggestedPartyMembers = 0;
|
||||
public QuestRewards Rewards = new();
|
||||
public List<QuestDescEmote> Emotes = new();
|
||||
public uint[] QuestFlags = new uint[2]; // Flags and FlagsEx
|
||||
public uint[] QuestFlags = new uint[3]; // Flags and FlagsEx
|
||||
}
|
||||
|
||||
public struct QuestObjectiveSimple
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
public class InitializeFactions : ServerPacket
|
||||
{
|
||||
const ushort FactionCount = 400;
|
||||
const ushort FactionCount = 443;
|
||||
|
||||
public InitializeFactions() : base(ServerOpcodes.InitializeFactions, ConnectionType.Instance) { }
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
for (ushort i = 0; i < FactionCount; ++i)
|
||||
{
|
||||
_worldPacket.WriteUInt8((byte)((ushort)FactionFlags[i] & 0xFF));
|
||||
_worldPacket.WriteUInt16((ushort)((ushort)FactionFlags[i] & 0xFF));
|
||||
_worldPacket.WriteInt32(FactionStandings[i]);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WriteFloat(ReferAFriendBonus);
|
||||
_worldPacket.WriteFloat(BonusFromAchievementSystem);
|
||||
|
||||
_worldPacket.WriteInt32(Faction.Count);
|
||||
@@ -83,7 +82,6 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.FlushBits();
|
||||
}
|
||||
|
||||
public float ReferAFriendBonus;
|
||||
public float BonusFromAchievementSystem;
|
||||
public List<FactionStandingData> Faction = new();
|
||||
public bool ShowVisual;
|
||||
|
||||
@@ -305,23 +305,13 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WriteInt32(SpellID.Count);
|
||||
_worldPacket.WriteInt32(Superceded.Count);
|
||||
_worldPacket.WriteInt32(FavoriteSpellID.Count);
|
||||
_worldPacket.WriteInt32(ClientLearnedSpellData.Count);
|
||||
|
||||
foreach (var spellId in SpellID)
|
||||
_worldPacket.WriteUInt32(spellId);
|
||||
|
||||
foreach (var spellId in Superceded)
|
||||
_worldPacket.WriteUInt32(spellId);
|
||||
|
||||
foreach (var spellId in FavoriteSpellID)
|
||||
_worldPacket.WriteInt32(spellId);
|
||||
foreach (LearnedSpellInfo spell in ClientLearnedSpellData)
|
||||
spell.Write(_worldPacket);
|
||||
}
|
||||
|
||||
public List<uint> SpellID = new();
|
||||
public List<uint> Superceded = new();
|
||||
public List<int> FavoriteSpellID = new();
|
||||
public List<LearnedSpellInfo> ClientLearnedSpellData = new();
|
||||
}
|
||||
|
||||
public class LearnedSpells : ServerPacket
|
||||
@@ -330,22 +320,16 @@ namespace Game.Networking.Packets
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WriteInt32(SpellID.Count);
|
||||
_worldPacket.WriteInt32(FavoriteSpellID.Count);
|
||||
_worldPacket.WriteInt32(ClientLearnedSpellData.Count);
|
||||
_worldPacket.WriteUInt32(SpecializationID);
|
||||
|
||||
foreach (uint spell in SpellID)
|
||||
_worldPacket.WriteUInt32(spell);
|
||||
|
||||
foreach (int spell in FavoriteSpellID)
|
||||
_worldPacket.WriteInt32(spell);
|
||||
|
||||
_worldPacket.WriteBit(SuppressMessaging);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
foreach (LearnedSpellInfo spell in ClientLearnedSpellData)
|
||||
spell.Write(_worldPacket);
|
||||
}
|
||||
|
||||
public List<uint> SpellID = new();
|
||||
public List<int> FavoriteSpellID = new();
|
||||
public List<LearnedSpellInfo> ClientLearnedSpellData = new();
|
||||
public uint SpecializationID;
|
||||
public bool SuppressMessaging;
|
||||
}
|
||||
@@ -998,10 +982,12 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
SpellClickUnitGuid = _worldPacket.ReadPackedGuid();
|
||||
TryAutoDismount = _worldPacket.HasBit();
|
||||
IsSoftInteract = _worldPacket.HasBit();
|
||||
}
|
||||
|
||||
public ObjectGuid SpellClickUnitGuid;
|
||||
public bool TryAutoDismount;
|
||||
public bool IsSoftInteract;
|
||||
}
|
||||
|
||||
class ResyncRunes : ServerPacket
|
||||
@@ -1520,7 +1506,7 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
public void Read(WorldPacket data)
|
||||
{
|
||||
Flags = (SpellCastTargetFlags)data.ReadBits<uint>(26);
|
||||
Flags = (SpellCastTargetFlags)data.ReadBits<uint>(28);
|
||||
if (data.HasBit())
|
||||
SrcLocation = new();
|
||||
|
||||
@@ -1552,7 +1538,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteBits((uint)Flags, 26);
|
||||
data.WriteBits((uint)Flags, 28);
|
||||
data.WriteBit(SrcLocation != null);
|
||||
data.WriteBit(DstLocation != null);
|
||||
data.WriteBit(Orientation.HasValue);
|
||||
@@ -1607,15 +1593,20 @@ namespace Game.Networking.Packets
|
||||
public uint Quantity;
|
||||
}
|
||||
|
||||
public struct SpellOptionalReagent
|
||||
public struct SpellCraftingReagent
|
||||
{
|
||||
public int ItemID;
|
||||
public int Slot;
|
||||
public int DataSlotIndex;
|
||||
public int Quantity;
|
||||
public byte? Unknown_1000;
|
||||
|
||||
public void Read(WorldPacket data)
|
||||
{
|
||||
ItemID = data.ReadInt32();
|
||||
Slot = data.ReadInt32();
|
||||
DataSlotIndex = data.ReadInt32();
|
||||
Quantity = data.ReadInt32();
|
||||
if (data.HasBit())
|
||||
Unknown_1000 = data.ReadUInt8();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1641,8 +1632,9 @@ namespace Game.Networking.Packets
|
||||
public MissileTrajectoryRequest MissileTrajectory;
|
||||
public MovementInfo MoveUpdate;
|
||||
public List<SpellWeight> Weight = new();
|
||||
public Array<SpellOptionalReagent> OptionalReagents = new(3);
|
||||
public Array<SpellCraftingReagent> OptionalReagents = new(3);
|
||||
public Array<SpellExtraCurrencyCost> OptionalCurrencies = new(5 /*MAX_ITEM_EXT_COST_CURRENCIES*/);
|
||||
public ulong? CraftingOrderID;
|
||||
public ObjectGuid CraftingNPC;
|
||||
public uint[] Misc = new uint[2];
|
||||
|
||||
@@ -1658,21 +1650,25 @@ namespace Game.Networking.Packets
|
||||
MissileTrajectory.Read(data);
|
||||
CraftingNPC = data.ReadPackedGuid();
|
||||
|
||||
var optionalReagents = data.ReadUInt32();
|
||||
var optionalCurrencies = data.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < optionalReagents; ++i)
|
||||
OptionalReagents[i].Read(data);
|
||||
var optionalReagents = data.ReadUInt32();
|
||||
|
||||
for (var i = 0; i < optionalCurrencies; ++i)
|
||||
OptionalCurrencies[i].Read(data);
|
||||
|
||||
SendCastFlags = data.ReadBits<uint>(5);
|
||||
bool hasMoveUpdate = data.HasBit();
|
||||
|
||||
bool hasCraftingOrderID = data.HasBit();
|
||||
var weightCount = data.ReadBits<uint>(2);
|
||||
|
||||
Target.Read(data);
|
||||
|
||||
if (hasCraftingOrderID)
|
||||
CraftingOrderID = data.ReadUInt64();
|
||||
|
||||
for (var i = 0; i < optionalReagents; ++i)
|
||||
OptionalReagents[i].Read(data);
|
||||
|
||||
if (hasMoveUpdate)
|
||||
MoveUpdate = MovementExtensions.ReadMovementInfo(data);
|
||||
|
||||
@@ -1884,6 +1880,34 @@ namespace Game.Networking.Packets
|
||||
public SpellHealPrediction Predict;
|
||||
}
|
||||
|
||||
public struct LearnedSpellInfo
|
||||
{
|
||||
public uint SpellID;
|
||||
public bool IsFavorite;
|
||||
public int? field_8;
|
||||
public int? Superceded;
|
||||
public int? TraitDefinitionID;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteUInt32(SpellID);
|
||||
data.WriteBit(IsFavorite);
|
||||
data.WriteBit(field_8.HasValue);
|
||||
data.WriteBit(Superceded.HasValue);
|
||||
data.WriteBit(TraitDefinitionID.HasValue);
|
||||
data.FlushBits();
|
||||
|
||||
if (field_8.HasValue)
|
||||
data.WriteInt32(field_8.Value);
|
||||
|
||||
if (Superceded.HasValue)
|
||||
data.WriteInt32(Superceded.Value);
|
||||
|
||||
if (TraitDefinitionID.HasValue)
|
||||
data.WriteInt32(TraitDefinitionID.Value);
|
||||
}
|
||||
}
|
||||
|
||||
public struct SpellModifierData
|
||||
{
|
||||
public float ModifierValue;
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace Game.Networking.Packets
|
||||
|
||||
_worldPacket.WriteInt16(MaxPlayerNameQueriesPerPacket);
|
||||
_worldPacket.WriteInt16(PlayerNameQueryTelemetryInterval);
|
||||
_worldPacket.WriteUInt32((uint)PlayerNameQueryInterval.TotalSeconds);
|
||||
|
||||
foreach (GameRuleValuePair gameRuleValue in GameRuleValues)
|
||||
gameRuleValue.Write(_worldPacket);
|
||||
@@ -70,6 +71,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(BpayStoreDisabledByParentalControls);
|
||||
_worldPacket.WriteBit(ItemRestorationButtonEnabled);
|
||||
_worldPacket.WriteBit(BrowserEnabled);
|
||||
|
||||
_worldPacket.WriteBit(SessionAlert.HasValue);
|
||||
_worldPacket.WriteBit(RAFSystem.Enabled);
|
||||
_worldPacket.WriteBit(RAFSystem.RecruitingEnabled);
|
||||
@@ -78,6 +80,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(CommerceSystemEnabled);
|
||||
_worldPacket.WriteBit(TutorialsEnabled);
|
||||
_worldPacket.WriteBit(TwitterEnabled);
|
||||
|
||||
_worldPacket.WriteBit(Unk67);
|
||||
_worldPacket.WriteBit(WillKickFromWorld);
|
||||
_worldPacket.WriteBit(KioskModeEnabled);
|
||||
@@ -86,6 +89,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(WarModeFeatureEnabled);
|
||||
_worldPacket.WriteBit(ClubsEnabled);
|
||||
_worldPacket.WriteBit(ClubsBattleNetClubTypeAllowed);
|
||||
|
||||
_worldPacket.WriteBit(ClubsCharacterClubTypeAllowed);
|
||||
_worldPacket.WriteBit(ClubsPresenceUpdateEnabled);
|
||||
_worldPacket.WriteBit(VoiceChatDisabledByParentalControl);
|
||||
@@ -94,10 +98,14 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(IsMuted);
|
||||
_worldPacket.WriteBit(ClubFinderEnabled);
|
||||
_worldPacket.WriteBit(Unknown901CheckoutRelated);
|
||||
|
||||
_worldPacket.WriteBit(TextToSpeechFeatureEnabled);
|
||||
_worldPacket.WriteBit(ChatDisabledByDefault);
|
||||
_worldPacket.WriteBit(ChatDisabledByPlayer);
|
||||
_worldPacket.WriteBit(LFGListCustomRequiresAuthenticator);
|
||||
_worldPacket.WriteBit(AddonsDisabled);
|
||||
_worldPacket.WriteBit(Unused1000);
|
||||
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
{
|
||||
@@ -164,6 +172,7 @@ namespace Game.Networking.Packets
|
||||
public int ActiveSeason; // Currently active Classic season
|
||||
public short MaxPlayerNameQueriesPerPacket = 50;
|
||||
public short PlayerNameQueryTelemetryInterval = 600;
|
||||
public TimeSpan PlayerNameQueryInterval = TimeSpan.FromSeconds(10);
|
||||
public bool ItemRestorationButtonEnabled;
|
||||
public bool CharUndeleteEnabled; // Implemented
|
||||
public bool BpayStoreDisabledByParentalControls;
|
||||
@@ -192,6 +201,8 @@ namespace Game.Networking.Packets
|
||||
public bool ChatDisabledByDefault;
|
||||
public bool ChatDisabledByPlayer;
|
||||
public bool LFGListCustomRequiresAuthenticator;
|
||||
public bool AddonsDisabled;
|
||||
public bool Unused1000;
|
||||
|
||||
public SocialQueueConfig QuickJoinConfig;
|
||||
public SquelchInfo Squelch;
|
||||
@@ -264,6 +275,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(Unk14);
|
||||
_worldPacket.WriteBit(WillKickFromWorld);
|
||||
_worldPacket.WriteBit(IsExpansionPreorderInStore);
|
||||
|
||||
_worldPacket.WriteBit(KioskModeEnabled);
|
||||
_worldPacket.WriteBit(CompetitiveModeEnabled);
|
||||
_worldPacket.WriteBit(TrialBoostEnabled);
|
||||
@@ -272,9 +284,12 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteBit(LiveRegionCharacterCopyEnabled);
|
||||
_worldPacket.WriteBit(LiveRegionAccountCopyEnabled);
|
||||
_worldPacket.WriteBit(LiveRegionKeyBindingsCopyEnabled);
|
||||
|
||||
_worldPacket.WriteBit(Unknown901CheckoutRelated);
|
||||
_worldPacket.WriteBit(EuropaTicketSystemStatus.HasValue);
|
||||
_worldPacket.WriteBit(LaunchETA.HasValue);
|
||||
_worldPacket.WriteBit(AddonsDisabled);
|
||||
_worldPacket.WriteBit(Unused1000);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
if (EuropaTicketSystemStatus.HasValue)
|
||||
@@ -294,6 +309,7 @@ namespace Game.Networking.Packets
|
||||
_worldPacket.WriteInt32(GameRuleValues.Count);
|
||||
_worldPacket.WriteInt16(MaxPlayerNameQueriesPerPacket);
|
||||
_worldPacket.WriteInt16(PlayerNameQueryTelemetryInterval);
|
||||
_worldPacket.WriteUInt32((uint)PlayerNameQueryInterval.TotalSeconds);
|
||||
|
||||
if (LaunchETA.HasValue)
|
||||
_worldPacket.WriteInt32(LaunchETA.Value);
|
||||
@@ -320,8 +336,10 @@ namespace Game.Networking.Packets
|
||||
public bool LiveRegionCharacterListEnabled; // NYI
|
||||
public bool LiveRegionCharacterCopyEnabled; // NYI
|
||||
public bool LiveRegionAccountCopyEnabled; // NYI
|
||||
public bool LiveRegionKeyBindingsCopyEnabled = false;
|
||||
public bool Unknown901CheckoutRelated = false; // NYI
|
||||
public bool LiveRegionKeyBindingsCopyEnabled;
|
||||
public bool Unknown901CheckoutRelated; // NYI
|
||||
public bool AddonsDisabled;
|
||||
public bool Unused1000;
|
||||
public EuropaTicketConfig? EuropaTicketSystemStatus;
|
||||
public List<int> LiveRegionCharacterCopySourceRegions = new();
|
||||
public uint TokenPollTimeSeconds; // NYI
|
||||
@@ -337,6 +355,7 @@ namespace Game.Networking.Packets
|
||||
public List<GameRuleValuePair> GameRuleValues = new();
|
||||
public short MaxPlayerNameQueriesPerPacket = 50;
|
||||
public short PlayerNameQueryTelemetryInterval = 600;
|
||||
public TimeSpan PlayerNameQueryInterval = TimeSpan.FromSeconds(10);
|
||||
public int? LaunchETA;
|
||||
}
|
||||
|
||||
@@ -368,12 +387,18 @@ namespace Game.Networking.Packets
|
||||
{
|
||||
_worldPacket.WriteBits(ServerTimeTZ.GetByteCount(), 7);
|
||||
_worldPacket.WriteBits(GameTimeTZ.GetByteCount(), 7);
|
||||
_worldPacket.WriteBits(ServerRegionalTZ.GetByteCount(), 7);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
_worldPacket.WriteString(ServerTimeTZ);
|
||||
_worldPacket.WriteString(GameTimeTZ);
|
||||
_worldPacket.WriteString(ServerRegionalTZ);
|
||||
|
||||
}
|
||||
|
||||
public string ServerTimeTZ;
|
||||
public string GameTimeTZ;
|
||||
public string ServerRegionalTZ;
|
||||
}
|
||||
|
||||
public struct SavedThrottleObjectState
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2020 CypherCore <http://github.com/CypherCore>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using Framework.Constants;
|
||||
using Game.Entities;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Game.Networking.Packets
|
||||
{
|
||||
public struct TraitEntry
|
||||
{
|
||||
public int TraitNodeID;
|
||||
public int TraitNodeEntryID;
|
||||
public int Rank;
|
||||
public int GrantedRanks;
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(TraitNodeID);
|
||||
data.WriteInt32(TraitNodeEntryID);
|
||||
data.WriteInt32(Rank);
|
||||
data.WriteInt32(GrantedRanks);
|
||||
}
|
||||
}
|
||||
|
||||
public class TraitConfig
|
||||
{
|
||||
public int ID;
|
||||
public TraitConfigType Type;
|
||||
public int ChrSpecializationID = 0;
|
||||
public TraitCombatConfigFlags CombatConfigFlags;
|
||||
public int LocalIdentifier; // Local to specialization
|
||||
public int SkillLineID;
|
||||
public int TraitSystemID;
|
||||
public List<TraitEntry> Entries = new();
|
||||
public string Name = "";
|
||||
|
||||
public void Write(WorldPacket data)
|
||||
{
|
||||
data.WriteInt32(ID);
|
||||
data.WriteInt32((int)Type);
|
||||
data.WriteInt32(Entries.Count);
|
||||
switch (Type)
|
||||
{
|
||||
case TraitConfigType.Combat:
|
||||
data.WriteInt32(ChrSpecializationID);
|
||||
data.WriteInt32((int)CombatConfigFlags);
|
||||
data.WriteInt32(LocalIdentifier);
|
||||
break;
|
||||
case TraitConfigType.Profession:
|
||||
data.WriteInt32(SkillLineID);
|
||||
break;
|
||||
case TraitConfigType.Generic:
|
||||
data.WriteInt32(TraitSystemID);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (TraitEntry traitEntry in Entries)
|
||||
traitEntry.Write(data);
|
||||
|
||||
data.WriteBits(Name.GetByteCount(), 9);
|
||||
data.FlushBits();
|
||||
|
||||
data.WriteString(Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,21 +69,6 @@ namespace Game.Networking.Packets
|
||||
public List<uint> NewAppearances = new();
|
||||
}
|
||||
|
||||
class TransmogrifyNPC : ServerPacket
|
||||
{
|
||||
public TransmogrifyNPC(ObjectGuid guid) : base(ServerOpcodes.TransmogrifyNpc, ConnectionType.Instance)
|
||||
{
|
||||
Guid = guid;
|
||||
}
|
||||
|
||||
public override void Write()
|
||||
{
|
||||
_worldPacket.WritePackedGuid(Guid);
|
||||
}
|
||||
|
||||
ObjectGuid Guid;
|
||||
}
|
||||
|
||||
struct TransmogrifyItem
|
||||
{
|
||||
public void Read(WorldPacket data)
|
||||
|
||||
@@ -279,6 +279,93 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
void LoadConditionalConditionalQuestDescription(SQLFields fields)
|
||||
{
|
||||
Locale locale = fields.Read<string>(4).ToEnum<Locale>();
|
||||
if (locale >= Locale.Total)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `quest_description_conditional` has invalid locale {fields.Read<string>(4)} set for quest {fields.Read<uint>(0)}. Skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
QuestConditionalText text = ConditionalQuestDescription.Find(text => text.PlayerConditionId == fields.Read<int>(1) && text.QuestgiverCreatureId == fields.Read<int>(2));
|
||||
if (text == null)
|
||||
{
|
||||
text = new();
|
||||
ConditionalQuestDescription.Add(text);
|
||||
}
|
||||
|
||||
text.PlayerConditionId = fields.Read<int>(1);
|
||||
text.QuestgiverCreatureId = fields.Read<int>(2);
|
||||
ObjectManager.AddLocaleString(fields.Read<string>(3), locale, text.Text);
|
||||
}
|
||||
|
||||
void LoadConditionalConditionalRequestItemsText(SQLFields fields)
|
||||
{
|
||||
Locale locale = fields.Read<string>(4).ToEnum<Locale>();
|
||||
if (locale >= Locale.Total)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `quest_request_items_conditional` has invalid locale {fields.Read<string>(4)} set for quest {fields.Read<uint>(0)}. Skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
QuestConditionalText text = ConditionalRequestItemsText.Find(text => text.PlayerConditionId == fields.Read<int>(1) && text.QuestgiverCreatureId == fields.Read<uint>(2));
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
text = new();
|
||||
ConditionalRequestItemsText.Add(text);
|
||||
}
|
||||
|
||||
text.PlayerConditionId = fields.Read<int>(1);
|
||||
text.QuestgiverCreatureId = fields.Read<int>(2);
|
||||
ObjectManager.AddLocaleString(fields.Read<string>(3), locale, text.Text);
|
||||
}
|
||||
|
||||
void LoadConditionalConditionalOfferRewardText(SQLFields fields)
|
||||
{
|
||||
Locale locale = fields.Read<string>(4).ToEnum<Locale>();
|
||||
if (locale >= Locale.Total)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `quest_offer_reward_conditional` has invalid locale {fields.Read<string>(4)} set for quest {fields.Read<uint>(0)}. Skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
QuestConditionalText text = ConditionalOfferRewardText.Find(text => text.PlayerConditionId == fields.Read<int>(1) && text.QuestgiverCreatureId == fields.Read<uint>(2));
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
text = new();
|
||||
ConditionalOfferRewardText.Add(text);
|
||||
}
|
||||
|
||||
text.PlayerConditionId = fields.Read<int>(1);
|
||||
text.QuestgiverCreatureId = fields.Read<int>(2);
|
||||
ObjectManager.AddLocaleString(fields.Read<string>(3), locale, text.Text);
|
||||
}
|
||||
|
||||
void LoadConditionalConditionalQuestCompletionLog(SQLFields fields)
|
||||
{
|
||||
Locale locale = fields.Read<string>(4).ToEnum<Locale>();
|
||||
if (locale >= Locale.Total)
|
||||
{
|
||||
Log.outError(LogFilter.Sql, $"Table `quest_completion_log_conditional` has invalid locale {fields.Read<string>(4)} set for quest {fields.Read<uint>(0)}. Skipped.");
|
||||
return;
|
||||
}
|
||||
|
||||
QuestConditionalText text = ConditionalQuestCompletionLog.Find(text => text.PlayerConditionId == fields.Read<int>(1) && text.QuestgiverCreatureId == fields.Read<uint>(2));
|
||||
|
||||
if (text == null)
|
||||
{
|
||||
text = new();
|
||||
ConditionalQuestCompletionLog.Add(text);
|
||||
}
|
||||
|
||||
text.PlayerConditionId = fields.Read<int>(1);
|
||||
text.QuestgiverCreatureId = fields.Read<int>(2);
|
||||
ObjectManager.AddLocaleString(fields.Read<string>(3), locale, text.Text);
|
||||
}
|
||||
|
||||
public uint XPValue(Player player)
|
||||
{
|
||||
if (player)
|
||||
@@ -498,6 +585,20 @@ namespace Game
|
||||
response.Info.PortraitTurnInText = PortraitTurnInText;
|
||||
response.Info.PortraitTurnInName = PortraitTurnInName;
|
||||
|
||||
response.Info.ConditionalQuestDescription = ConditionalQuestDescription.Select(text =>
|
||||
{
|
||||
string content = text.Text[(int)Locale.enUS];
|
||||
ObjectManager.GetLocaleString(text.Text, loc, ref content);
|
||||
return new ConditionalQuestText(text.PlayerConditionId, text.QuestgiverCreatureId, content);
|
||||
}).ToList();
|
||||
|
||||
response.Info.ConditionalQuestCompletionLog = ConditionalQuestCompletionLog.Select(text =>
|
||||
{
|
||||
string content = text.Text[(int)Locale.enUS];
|
||||
ObjectManager.GetLocaleString(text.Text, loc, ref content);
|
||||
return new ConditionalQuestText(text.PlayerConditionId, text.QuestgiverCreatureId, content);
|
||||
}).ToList();
|
||||
|
||||
if (loc != Locale.enUS)
|
||||
{
|
||||
var questTemplateLocale = Global.ObjectMgr.GetQuestLocale(Id);
|
||||
@@ -596,6 +697,7 @@ namespace Game
|
||||
response.Info.Expansion = Expansion;
|
||||
response.Info.ManagedWorldStateID = ManagedWorldStateID;
|
||||
response.Info.QuestSessionBonus = 0; //GetQuestSessionBonus(); // this is only sent while quest session is active
|
||||
response.Info.QuestGiverCreatureID = 0; // only sent during npc interaction
|
||||
|
||||
foreach (QuestObjective questObjective in Objectives)
|
||||
{
|
||||
@@ -744,6 +846,12 @@ namespace Game
|
||||
public string PortraitTurnInName = "";
|
||||
public string QuestCompletionLog = "";
|
||||
|
||||
// quest_description_conditional
|
||||
public List<QuestConditionalText> ConditionalQuestDescription = new();
|
||||
|
||||
// quest_completion_log_conditional
|
||||
public List<QuestConditionalText> ConditionalQuestCompletionLog = new();
|
||||
|
||||
// quest_detais table
|
||||
public uint[] DetailsEmote = new uint[SharedConst.QuestEmoteCount];
|
||||
public uint[] DetailsEmoteDelay = new uint[SharedConst.QuestEmoteCount];
|
||||
@@ -755,11 +863,17 @@ namespace Game
|
||||
public uint EmoteOnIncompleteDelay;
|
||||
public string RequestItemsText = "";
|
||||
|
||||
// quest_request_items_conditional
|
||||
public List<QuestConditionalText> ConditionalRequestItemsText = new();
|
||||
|
||||
// quest_offer_reward table
|
||||
public int[] OfferRewardEmote = new int[SharedConst.QuestEmoteCount];
|
||||
public uint[] OfferRewardEmoteDelay = new uint[SharedConst.QuestEmoteCount];
|
||||
public string OfferRewardText = "";
|
||||
|
||||
// quest_offer_reward_conditional
|
||||
public List<QuestConditionalText> ConditionalOfferRewardText = new();
|
||||
|
||||
// quest_template_addon table (custom data)
|
||||
public uint MaxLevel { get; set; }
|
||||
public uint AllowableClasses { get; set; }
|
||||
@@ -864,6 +978,13 @@ namespace Game
|
||||
}
|
||||
}
|
||||
|
||||
public class QuestConditionalText
|
||||
{
|
||||
public int PlayerConditionId;
|
||||
public int QuestgiverCreatureId;
|
||||
public StringArray Text = new((int)Locale.Total);
|
||||
}
|
||||
|
||||
public class QuestObjective
|
||||
{
|
||||
public uint Id;
|
||||
|
||||
@@ -239,7 +239,6 @@ namespace Game
|
||||
public void SendState(FactionState faction)
|
||||
{
|
||||
SetFactionStanding setFactionStanding = new();
|
||||
setFactionStanding.ReferAFriendBonus = 0.0f;
|
||||
setFactionStanding.BonusFromAchievementSystem = 0.0f;
|
||||
if (faction != null)
|
||||
setFactionStanding.Faction.Add(new FactionStandingData((int)faction.ReputationListID, faction.Standing));
|
||||
|
||||
@@ -59,12 +59,12 @@ namespace Game.Scripting
|
||||
// Using provided text, not from DB
|
||||
public static void AddGossipItemFor(Player player, GossipOptionNpc optionNpc, string text, uint sender, uint action)
|
||||
{
|
||||
player.PlayerTalkClass.GetGossipMenu().AddMenuItem(-1, optionNpc, text, sender, action, "", 0);
|
||||
player.PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, false, 0, "", null, null, sender, action);
|
||||
}
|
||||
// Using provided texts, not from DB
|
||||
public static void AddGossipItemFor(Player player, GossipOptionNpc optionNpc, string text, uint sender, uint action, string popupText, uint popupMoney, bool coded)
|
||||
{
|
||||
player.PlayerTalkClass.GetGossipMenu().AddMenuItem(-1, optionNpc, text, sender, action, popupText, popupMoney, coded);
|
||||
player.PlayerTalkClass.GetGossipMenu().AddMenuItem(0, -1, optionNpc, text, 0, GossipOptionFlags.None, null, coded, popupMoney, popupText, null, null, sender, action);
|
||||
}
|
||||
// Uses gossip item info from DB
|
||||
public static void AddGossipItemFor(Player player, uint gossipMenuID, uint gossipMenuItemID, uint sender, uint action)
|
||||
|
||||
@@ -372,7 +372,7 @@ namespace Game
|
||||
Values[WorldCfg.CharacterCreatingDisabledRacemask] = GetDefaultValue("CharacterCreating.Disabled.RaceMask", 0);
|
||||
Values[WorldCfg.CharacterCreatingDisabledClassmask] = GetDefaultValue("CharacterCreating.Disabled.ClassMask", 0);
|
||||
|
||||
Values[WorldCfg.CharactersPerRealm] = GetDefaultValue("CharactersPerRealm", 50);
|
||||
Values[WorldCfg.CharactersPerRealm] = GetDefaultValue("CharactersPerRealm", 60);
|
||||
if ((int)Values[WorldCfg.CharactersPerRealm] < 1 || (int)Values[WorldCfg.CharactersPerRealm] > 200)
|
||||
{
|
||||
Log.outError(LogFilter.ServerLoading, "CharactersPerRealm ({0}) must be in range 1..200. Set to 200.", Values[WorldCfg.CharactersPerRealm]);
|
||||
@@ -380,14 +380,22 @@ namespace Game
|
||||
}
|
||||
|
||||
// must be after CharactersPerRealm
|
||||
Values[WorldCfg.CharactersPerAccount] = GetDefaultValue("CharactersPerAccount", 50);
|
||||
Values[WorldCfg.CharactersPerAccount] = GetDefaultValue("CharactersPerAccount", 60);
|
||||
if ((int)Values[WorldCfg.CharactersPerAccount] < (int)Values[WorldCfg.CharactersPerRealm])
|
||||
{
|
||||
Log.outError(LogFilter.ServerLoading, "CharactersPerAccount ({0}) can't be less than CharactersPerRealm ({1}).", Values[WorldCfg.CharactersPerAccount], Values[WorldCfg.CharactersPerRealm]);
|
||||
Values[WorldCfg.CharactersPerAccount] = Values[WorldCfg.CharactersPerRealm];
|
||||
}
|
||||
|
||||
Values[WorldCfg.CharacterCreatingEvokersPerRealm] = GetDefaultValue("CharacterCreating.EvokersPerRealm", 1);
|
||||
if ((int)Values[WorldCfg.CharacterCreatingEvokersPerRealm] < 0 || (int)Values[WorldCfg.CharacterCreatingEvokersPerRealm] > 10)
|
||||
{
|
||||
Log.outError(LogFilter.ServerLoading, $"CharacterCreating.EvokersPerRealm ({Values[WorldCfg.CharacterCreatingEvokersPerRealm]}) must be in range 0..10. Set to 1.");
|
||||
Values[WorldCfg.CharacterCreatingEvokersPerRealm] = 1;
|
||||
}
|
||||
|
||||
Values[WorldCfg.CharacterCreatingMinLevelForDemonHunter] = GetDefaultValue("CharacterCreating.MinLevelForDemonHunter", 0);
|
||||
Values[WorldCfg.CharacterCreatingMinLevelForEvoker] = GetDefaultValue("CharacterCreating.MinLevelForEvoker", 50);
|
||||
Values[WorldCfg.CharacterCreatingDisableAlliedRaceAchievementRequirement] = GetDefaultValue("CharacterCreating.DisableAlliedRaceAchievementRequirement", false);
|
||||
|
||||
Values[WorldCfg.SkipCinematics] = GetDefaultValue("SkipCinematics", 0);
|
||||
|
||||
+16
-17
@@ -4763,6 +4763,11 @@ namespace Game.Spells
|
||||
if (m_spellInfo.ExcludeCasterAuraSpell != 0 && unitCaster.HasAura(m_spellInfo.ExcludeCasterAuraSpell))
|
||||
return SpellCastResult.CasterAurastate;
|
||||
|
||||
if (m_spellInfo.CasterAuraType != 0 && !unitCaster.HasAuraType(m_spellInfo.CasterAuraType))
|
||||
return SpellCastResult.CasterAurastate;
|
||||
if (m_spellInfo.ExcludeCasterAuraType != 0 && unitCaster.HasAuraType(m_spellInfo.ExcludeCasterAuraType))
|
||||
return SpellCastResult.CasterAurastate;
|
||||
|
||||
if (reqCombat && unitCaster.IsInCombat() && !m_spellInfo.CanBeUsedInCombat())
|
||||
return SpellCastResult.AffectingCombat;
|
||||
}
|
||||
@@ -5589,21 +5594,15 @@ namespace Game.Spells
|
||||
|
||||
if (spellEffectInfo.Effect == SpellEffectName.ChangeBattlepetQuality)
|
||||
{
|
||||
var qualityRecord = CliDB.BattlePetBreedQualityStorage.Values.FirstOrDefault(a1 => a1.MaxQualityRoll < spellEffectInfo.BasePoints);
|
||||
|
||||
BattlePetBreedQuality quality = BattlePetBreedQuality.Poor;
|
||||
switch (spellEffectInfo.BasePoints)
|
||||
{
|
||||
case 85:
|
||||
quality = BattlePetBreedQuality.Rare;
|
||||
break;
|
||||
case 75:
|
||||
quality = BattlePetBreedQuality.Uncommon;
|
||||
break;
|
||||
default:
|
||||
// Ignore Epic Battle-Stones
|
||||
break;
|
||||
}
|
||||
if (qualityRecord != null)
|
||||
quality = (BattlePetBreedQuality)qualityRecord.QualityEnum;
|
||||
|
||||
if (battlePet.PacketInfo.Quality >= (byte)quality)
|
||||
return SpellCastResult.CantUpgradeBattlePet;
|
||||
|
||||
}
|
||||
|
||||
if (spellEffectInfo.Effect == SpellEffectName.GrantBattlepetLevel || spellEffectInfo.Effect == SpellEffectName.GrantBattlepetExperience)
|
||||
@@ -6634,21 +6633,21 @@ namespace Game.Spells
|
||||
{
|
||||
Item item = m_targets.GetItemTarget();
|
||||
if (!item)
|
||||
return SpellCastResult.CantBeDisenchanted;
|
||||
return SpellCastResult.CantBeSalvaged;
|
||||
|
||||
// prevent disenchanting in trade slot
|
||||
if (item.GetOwnerGUID() != player.GetGUID())
|
||||
return SpellCastResult.CantBeDisenchanted;
|
||||
return SpellCastResult.CantBeSalvaged;
|
||||
|
||||
ItemTemplate itemProto = item.GetTemplate();
|
||||
if (itemProto == null)
|
||||
return SpellCastResult.CantBeDisenchanted;
|
||||
return SpellCastResult.CantBeSalvaged;
|
||||
|
||||
ItemDisenchantLootRecord itemDisenchantLoot = item.GetDisenchantLoot(m_caster.ToPlayer());
|
||||
if (itemDisenchantLoot == null)
|
||||
return SpellCastResult.CantBeDisenchanted;
|
||||
return SpellCastResult.CantBeSalvaged;
|
||||
if (itemDisenchantLoot.SkillRequired > player.GetSkillValue(SkillType.Enchanting))
|
||||
return SpellCastResult.LowCastlevel;
|
||||
return SpellCastResult.CantBeSalvagedSkill;
|
||||
break;
|
||||
}
|
||||
case SpellEffectName.Prospecting:
|
||||
|
||||
@@ -2127,30 +2127,7 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
// select enchantment duration
|
||||
uint duration;
|
||||
|
||||
// rogue family enchantments exception by duration
|
||||
if (m_spellInfo.Id == 38615)
|
||||
duration = 1800; // 30 mins
|
||||
// other rogue family enchantments always 1 hour (some have spell damage=0, but some have wrong data in EffBasePoints)
|
||||
else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Rogue)
|
||||
duration = 3600; // 1 hour
|
||||
// shaman family enchantments
|
||||
else if (m_spellInfo.SpellFamilyName == SpellFamilyNames.Shaman)
|
||||
duration = 3600; // 30 mins
|
||||
// other cases with this SpellVisual already selected
|
||||
else if (m_spellInfo.GetSpellVisual() == 215)
|
||||
duration = 1800; // 30 mins
|
||||
// some fishing pole bonuses except Glow Worm which lasts full hour
|
||||
else if (m_spellInfo.GetSpellVisual() == 563 && m_spellInfo.Id != 64401)
|
||||
duration = 600; // 10 mins
|
||||
else if (m_spellInfo.Id == 29702)
|
||||
duration = 300; // 5 mins
|
||||
else if (m_spellInfo.Id == 37360)
|
||||
duration = 300; // 5 mins
|
||||
// default case
|
||||
else
|
||||
duration = 3600; // 1 hour
|
||||
uint duration = (uint)pEnchant.Duration;
|
||||
|
||||
// item can be in trade slot and have owner diff. from caster
|
||||
Player item_owner = itemTarget.GetOwner();
|
||||
@@ -5208,19 +5185,11 @@ namespace Game.Spells
|
||||
if (unitTarget == null || !unitTarget.IsCreature())
|
||||
return;
|
||||
|
||||
var quality = BattlePetBreedQuality.Poor;
|
||||
switch (damage)
|
||||
{
|
||||
case 85:
|
||||
quality = BattlePetBreedQuality.Rare;
|
||||
break;
|
||||
case 75:
|
||||
quality = BattlePetBreedQuality.Uncommon;
|
||||
break;
|
||||
default:
|
||||
// Ignore Epic Battle-Stones
|
||||
break;
|
||||
}
|
||||
var qualityRecord = CliDB.BattlePetBreedQualityStorage.Values.FirstOrDefault(a1 => a1.MaxQualityRoll < damage);
|
||||
|
||||
BattlePetBreedQuality quality = BattlePetBreedQuality.Poor;
|
||||
if (qualityRecord != null)
|
||||
quality = (BattlePetBreedQuality)qualityRecord.QualityEnum;
|
||||
|
||||
playerCaster.GetSession().GetBattlePetMgr().ChangeBattlePetQuality(unitTarget.GetBattlePetCompanionGUID(), quality);
|
||||
}
|
||||
@@ -5634,6 +5603,79 @@ namespace Game.Spells
|
||||
|
||||
player.GetSession().GetCollectionMgr().AddTransmogIllusion(illusionId);
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ModifyAuraStacks)]
|
||||
void EffectModifyAuraStacks()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.HitTarget)
|
||||
return;
|
||||
|
||||
Aura targetAura = unitTarget.GetAura(effectInfo.TriggerSpell);
|
||||
if (targetAura == null)
|
||||
return;
|
||||
|
||||
switch (effectInfo.MiscValue)
|
||||
{
|
||||
case 0:
|
||||
targetAura.ModStackAmount(damage);
|
||||
break;
|
||||
case 1:
|
||||
targetAura.SetStackAmount((byte)damage);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ModifyCooldown)]
|
||||
void EffectModifyCooldown()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.HitTarget)
|
||||
return;
|
||||
|
||||
unitTarget.GetSpellHistory().ModifyCooldown(effectInfo.TriggerSpell, TimeSpan.FromMilliseconds(damage));
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ModifyCooldowns)]
|
||||
void EffectModifyCooldowns()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.HitTarget)
|
||||
return;
|
||||
|
||||
unitTarget.GetSpellHistory().ModifyCoooldowns(itr =>
|
||||
{
|
||||
SpellInfo spellOnCooldown = Global.SpellMgr.GetSpellInfo(itr.SpellId, Difficulty.None);
|
||||
if ((int)spellOnCooldown.SpellFamilyName != effectInfo.MiscValue)
|
||||
return false;
|
||||
|
||||
int bitIndex = effectInfo.MiscValueB - 1;
|
||||
if (bitIndex < 0 || bitIndex >= sizeof(uint) * 8)
|
||||
return false;
|
||||
|
||||
FlagArray128 reqFlag = new();
|
||||
reqFlag[bitIndex / 32] = 1u << (bitIndex % 32);
|
||||
return (spellOnCooldown.SpellFamilyFlags & reqFlag);
|
||||
}, TimeSpan.FromMilliseconds(damage));
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ModifyCooldownsByCategory)]
|
||||
void EffectModifyCooldownsByCategory()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.HitTarget)
|
||||
return;
|
||||
|
||||
unitTarget.GetSpellHistory().ModifyCoooldowns(itr => Global.SpellMgr.GetSpellInfo(itr.SpellId, Difficulty.None).CategoryId == effectInfo.MiscValue, TimeSpan.FromMilliseconds(damage));
|
||||
}
|
||||
|
||||
[SpellEffectHandler(SpellEffectName.ModifyCharges)]
|
||||
void EffectModifySpellCharges()
|
||||
{
|
||||
if (effectHandleMode != SpellEffectHandleMode.HitTarget)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < damage; ++i)
|
||||
unitTarget.GetSpellHistory().RestoreCharge((uint)effectInfo.MiscValue);
|
||||
}
|
||||
}
|
||||
|
||||
public class DispelableAura
|
||||
|
||||
@@ -514,20 +514,25 @@ namespace Game.Spells
|
||||
}
|
||||
}
|
||||
|
||||
public void ModifySpellCooldown(uint spellId, TimeSpan offset, bool withoutCategoryCooldown = false)
|
||||
public void ModifySpellCooldown(uint spellId, TimeSpan cooldownMod, bool withoutCategoryCooldown)
|
||||
{
|
||||
var cooldownEntry = _spellCooldowns.LookupByKey(spellId);
|
||||
if (offset.TotalMilliseconds == 0 || cooldownEntry == null)
|
||||
if (cooldownMod.TotalMilliseconds == 0 || cooldownEntry == null)
|
||||
return;
|
||||
|
||||
ModifySpellCooldown(cooldownEntry, cooldownMod, withoutCategoryCooldown);
|
||||
}
|
||||
|
||||
void ModifySpellCooldown(CooldownEntry cooldownEntry, TimeSpan cooldownMod, bool withoutCategoryCooldown)
|
||||
{
|
||||
DateTime now = GameTime.GetSystemTime();
|
||||
|
||||
cooldownEntry.CooldownEnd += offset;
|
||||
cooldownEntry.CooldownEnd += cooldownMod;
|
||||
|
||||
if (cooldownEntry.CategoryId != 0)
|
||||
{
|
||||
if (!withoutCategoryCooldown)
|
||||
cooldownEntry.CategoryEnd += offset;
|
||||
cooldownEntry.CategoryEnd += cooldownMod;
|
||||
|
||||
// Because category cooldown existence is tied to regular cooldown, we cannot allow a situation where regular cooldown is shorter than category
|
||||
if (cooldownEntry.CooldownEnd < cooldownEntry.CategoryEnd)
|
||||
@@ -535,9 +540,9 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
if (cooldownEntry.CooldownEnd <= now)
|
||||
{
|
||||
{
|
||||
_categoryCooldowns.Remove(cooldownEntry.CategoryId);
|
||||
_spellCooldowns.Remove(spellId);
|
||||
_spellCooldowns.Remove(cooldownEntry.SpellId);
|
||||
}
|
||||
|
||||
Player playerOwner = GetPlayerOwner();
|
||||
@@ -545,8 +550,8 @@ namespace Game.Spells
|
||||
{
|
||||
ModifyCooldown modifyCooldown = new();
|
||||
modifyCooldown.IsPet = _owner != playerOwner;
|
||||
modifyCooldown.SpellID = spellId;
|
||||
modifyCooldown.DeltaTime = (int)offset.TotalMilliseconds;
|
||||
modifyCooldown.SpellID = cooldownEntry.SpellId;
|
||||
modifyCooldown.DeltaTime = (int)cooldownMod.TotalMilliseconds;
|
||||
modifyCooldown.WithoutCategoryCooldown = withoutCategoryCooldown;
|
||||
playerOwner.SendPacket(modifyCooldown);
|
||||
}
|
||||
@@ -569,7 +574,16 @@ namespace Game.Spells
|
||||
else
|
||||
ModifySpellCooldown(spellInfo.Id, cooldownMod, withoutCategoryCooldown);
|
||||
}
|
||||
|
||||
|
||||
public void ModifyCoooldowns(Func<CooldownEntry, bool> predicate, TimeSpan cooldownMod, bool withoutCategoryCooldown = false)
|
||||
{
|
||||
foreach (var cooldownEntry in _spellCooldowns.Values.ToList())
|
||||
{
|
||||
if (predicate(cooldownEntry))
|
||||
ModifySpellCooldown(cooldownEntry, cooldownMod, withoutCategoryCooldown);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetCooldown(uint spellId, bool update = false)
|
||||
{
|
||||
var entry = _spellCooldowns.LookupByKey(spellId);
|
||||
@@ -635,6 +649,9 @@ namespace Game.Spells
|
||||
if (_spellCooldowns.ContainsKey(spellInfo.Id))
|
||||
return true;
|
||||
|
||||
if (spellInfo.CooldownAuraSpellId != 0 && _owner.HasAura(spellInfo.CooldownAuraSpellId))
|
||||
return true;
|
||||
|
||||
uint category = 0;
|
||||
GetCooldownDurations(spellInfo, itemId, ref category);
|
||||
|
||||
|
||||
@@ -120,6 +120,10 @@ namespace Game.Spells
|
||||
TargetAuraSpell = _aura.TargetAuraSpell;
|
||||
ExcludeCasterAuraSpell = _aura.ExcludeCasterAuraSpell;
|
||||
ExcludeTargetAuraSpell = _aura.ExcludeTargetAuraSpell;
|
||||
CasterAuraType = (AuraType)_aura.CasterAuraType;
|
||||
TargetAuraType = (AuraType)_aura.TargetAuraType;
|
||||
ExcludeCasterAuraType = (AuraType)_aura.ExcludeCasterAuraType;
|
||||
ExcludeTargetAuraType = (AuraType)_aura.ExcludeTargetAuraType;
|
||||
}
|
||||
|
||||
RequiredAreasID = -1;
|
||||
@@ -161,6 +165,7 @@ namespace Game.Spells
|
||||
RecoveryTime = _cooldowns.RecoveryTime;
|
||||
CategoryRecoveryTime = _cooldowns.CategoryRecoveryTime;
|
||||
StartRecoveryTime = _cooldowns.StartRecoveryTime;
|
||||
CooldownAuraSpellId = _cooldowns.AuraSpellID;
|
||||
}
|
||||
|
||||
EquippedItemClass = ItemClass.None;
|
||||
@@ -2855,7 +2860,7 @@ namespace Game.Spells
|
||||
}
|
||||
|
||||
Log.outError(LogFilter.Spells, $"SpellInfo.CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id}");
|
||||
return default;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2863,6 +2868,36 @@ namespace Game.Spells
|
||||
else
|
||||
{
|
||||
powerCost = (int)power.OptionalCost;
|
||||
|
||||
if (power.OptionalCostPct != 0)
|
||||
{
|
||||
switch (power.PowerType)
|
||||
{
|
||||
// health as power used
|
||||
case PowerType.Health:
|
||||
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetMaxHealth(), power.OptionalCostPct);
|
||||
break;
|
||||
case PowerType.Mana:
|
||||
powerCost += (int)MathFunctions.CalculatePct(unitCaster.GetCreateMana(), power.OptionalCostPct);
|
||||
break;
|
||||
case PowerType.AlternatePower:
|
||||
Log.outError(LogFilter.Spells, $"SpellInfo::CalcPowerCost: Unsupported power type POWER_ALTERNATE_POWER in spell {Id} for optional cost percent");
|
||||
return null;
|
||||
default:
|
||||
{
|
||||
var powerTypeEntry = Global.DB2Mgr.GetPowerTypeEntry(power.PowerType);
|
||||
if (powerTypeEntry != null)
|
||||
{
|
||||
powerCost += (int)MathFunctions.CalculatePct(powerTypeEntry.MaxBasePower, power.OptionalCostPct);
|
||||
break;
|
||||
}
|
||||
|
||||
Log.outError(LogFilter.Spells, $"SpellInfo::CalcPowerCost: Unknown power type '{power.PowerType}' in spell {Id} for optional cost percent");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
powerCost += unitCaster.GetTotalAuraModifier(AuraType.ModAdditionalPowerCost, aurEff =>
|
||||
{
|
||||
return aurEff.GetMiscValue() == (int)power.PowerType && aurEff.IsAffectingSpell(this);
|
||||
@@ -3964,11 +3999,16 @@ namespace Game.Spells
|
||||
public uint TargetAuraSpell { get; set; }
|
||||
public uint ExcludeCasterAuraSpell { get; set; }
|
||||
public uint ExcludeTargetAuraSpell { get; set; }
|
||||
public AuraType CasterAuraType { get; set; }
|
||||
public AuraType TargetAuraType { get; set; }
|
||||
public AuraType ExcludeCasterAuraType { get; set; }
|
||||
public AuraType ExcludeTargetAuraType { get; set; }
|
||||
public SpellCastTimesRecord CastTimeEntry { get; set; }
|
||||
public uint RecoveryTime { get; set; }
|
||||
public uint CategoryRecoveryTime { get; set; }
|
||||
public uint StartRecoveryCategory { get; set; }
|
||||
public uint StartRecoveryTime { get; set; }
|
||||
public uint CooldownAuraSpellId { get; set; }
|
||||
public SpellInterruptFlags InterruptFlags { get; set; }
|
||||
public SpellAuraInterruptFlags AuraInterruptFlags { get; set; }
|
||||
public SpellAuraInterruptFlags2 AuraInterruptFlags2 { get; set; }
|
||||
@@ -4777,8 +4817,23 @@ namespace Game.Spells
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 285 SPELL_EFFECT_MODIFY_KEYSTONE_2
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 286 SPELL_EFFECT_GRANT_BATTLEPET_EXPERIENCE
|
||||
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 287 SPELL_EFFECT_SET_GARRISON_FOLLOWER_LEVEL
|
||||
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 288 SPELL_EFFECT_288
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 289 SPELL_EFFECT_289
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 288 SPELL_EFFECT_CRAFT_ITEM
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 289 SPELL_EFFECT_MODIFY_AURA_STACKS
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 290 SPELL_EFFECT_MODIFY_COOLDOWN
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 291 SPELL_EFFECT_MODIFY_COOLDOWNS
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 292 SPELL_EFFECT_MODIFY_COOLDOWNS_BY_CATEGORY
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 293 SPELL_EFFECT_MODIFY_CHARGES
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 294 SPELL_EFFECT_CRAFT_LOOT
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 295 SPELL_EFFECT_SALVAGE_ITEM
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 296 SPELL_EFFECT_CRAFT_SALVAGE_ITEM
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 297 SPELL_EFFECT_RECRAFT_ITEM
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 298 SPELL_EFFECT_CANCEL_ALL_PRIVATE_CONVERSATIONS
|
||||
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 299 SPELL_EFFECT_299
|
||||
new StaticData(SpellEffectImplicitTargetTypes.None, SpellTargetObjectTypes.None), // 300 SPELL_EFFECT_300
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Item), // 301 SPELL_EFFECT_CRAFT_ENCHANT
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.None), // 302 SPELL_EFFECT_GATHERING
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 303 SPELL_EFFECT_CREATE_TRAIT_TREE_CONFIG
|
||||
new StaticData(SpellEffectImplicitTargetTypes.Explicit, SpellTargetObjectTypes.Unit), // 304 SPELL_EFFECT_CHANGE_ACTIVE_COMBAT_TRAIT_CONFIG
|
||||
};
|
||||
|
||||
#region Fields
|
||||
|
||||
@@ -2471,17 +2471,19 @@ namespace Game.Entities
|
||||
"AttributesEx4, AttributesEx5, AttributesEx6, AttributesEx7, AttributesEx8, AttributesEx9, AttributesEx10, AttributesEx11, AttributesEx12, AttributesEx13, " +
|
||||
//19 20 21 22 23 24 25 26 27
|
||||
"AttributesEx14, Stances, StancesNot, Targets, TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, " +
|
||||
//28 29 30 31 32 33 34
|
||||
"ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex, " +
|
||||
//35 36 37 38 39 40 41
|
||||
//28 29 30 31 32 33
|
||||
"ExcludeCasterAuraState, ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, " +
|
||||
//34 35 36 37 38
|
||||
"CasterAuraType, TargetAuraType, ExcludeCasterAuraType, ExcludeTargetAuraType, CastingTimeIndex, " +
|
||||
//39 40 41 42 43 44 45
|
||||
"RecoveryTime, CategoryRecoveryTime, StartRecoveryCategory, StartRecoveryTime, InterruptFlags, AuraInterruptFlags1, AuraInterruptFlags2, " +
|
||||
//42 43 44 45 46 47 48 49 50 51 52
|
||||
//46 47 48 49 50 51 52 53 54 55 56
|
||||
"ChannelInterruptFlags1, ChannelInterruptFlags2, ProcFlags, ProcFlags2, ProcChance, ProcCharges, ProcCooldown, ProcBasePPM, MaxLevel, BaseLevel, SpellLevel, " +
|
||||
//53 54 55 56 57 58 59 60 61
|
||||
//57 58 59 60 61 62 63 64 65
|
||||
"DurationIndex, RangeIndex, Speed, LaunchDelay, StackAmount, EquippedItemClass, EquippedItemSubClassMask, EquippedItemInventoryTypeMask, ContentTuningId, " +
|
||||
//62 63 64 65 66 67 68 69 70 71
|
||||
//66 67 68 69 70 71 72 73 74 75
|
||||
"SpellName, ConeAngle, ConeWidth, MaxTargetLevel, MaxAffectedTargets, SpellFamilyName, SpellFamilyFlags1, SpellFamilyFlags2, SpellFamilyFlags3, SpellFamilyFlags4, " +
|
||||
//72 73 74 75 76
|
||||
//76 77 78 79 80
|
||||
"DmgClass, PreventionType, AreaGroupId, SchoolMask, ChargeCategoryId FROM serverside_spell");
|
||||
|
||||
if (!spellsResult.IsEmpty())
|
||||
@@ -2496,7 +2498,7 @@ namespace Game.Entities
|
||||
continue;
|
||||
}
|
||||
|
||||
mServersideSpellNames.Add(new(spellId, spellsResult.Read<string>(62)));
|
||||
mServersideSpellNames.Add(new(spellId, spellsResult.Read<string>(66)));
|
||||
|
||||
SpellInfo spellInfo = new(mServersideSpellNames.Last().Name, difficulty, spellEffects[(spellId, difficulty)]);
|
||||
spellInfo.CategoryId = spellsResult.Read<uint>(2);
|
||||
@@ -2531,44 +2533,48 @@ namespace Game.Entities
|
||||
spellInfo.TargetAuraSpell = spellsResult.Read<uint>(31);
|
||||
spellInfo.ExcludeCasterAuraSpell = spellsResult.Read<uint>(32);
|
||||
spellInfo.ExcludeTargetAuraSpell = spellsResult.Read<uint>(33);
|
||||
spellInfo.CastTimeEntry = CliDB.SpellCastTimesStorage.LookupByKey(spellsResult.Read<uint>(34));
|
||||
spellInfo.RecoveryTime = spellsResult.Read<uint>(35);
|
||||
spellInfo.CategoryRecoveryTime = spellsResult.Read<uint>(36);
|
||||
spellInfo.StartRecoveryCategory = spellsResult.Read<uint>(37);
|
||||
spellInfo.StartRecoveryTime = spellsResult.Read<uint>(38);
|
||||
spellInfo.InterruptFlags = (SpellInterruptFlags)spellsResult.Read<uint>(39);
|
||||
spellInfo.AuraInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read<uint>(40);
|
||||
spellInfo.AuraInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read<uint>(41);
|
||||
spellInfo.ChannelInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read<uint>(42);
|
||||
spellInfo.ChannelInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read<uint>(43);
|
||||
spellInfo.ProcFlags = new ProcFlagsInit(spellsResult.Read<int>(44), spellsResult.Read<int>(45));
|
||||
spellInfo.ProcChance = spellsResult.Read<uint>(46);
|
||||
spellInfo.ProcCharges = spellsResult.Read<uint>(47);
|
||||
spellInfo.ProcCooldown = spellsResult.Read<uint>(48);
|
||||
spellInfo.ProcBasePPM = spellsResult.Read<float>(49);
|
||||
spellInfo.MaxLevel = spellsResult.Read<uint>(50);
|
||||
spellInfo.BaseLevel = spellsResult.Read<uint>(51);
|
||||
spellInfo.SpellLevel = spellsResult.Read<uint>(52);
|
||||
spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(spellsResult.Read<uint>(53));
|
||||
spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(spellsResult.Read<uint>(54));
|
||||
spellInfo.Speed = spellsResult.Read<float>(55);
|
||||
spellInfo.LaunchDelay = spellsResult.Read<float>(56);
|
||||
spellInfo.StackAmount = spellsResult.Read<uint>(57);
|
||||
spellInfo.EquippedItemClass = (ItemClass)spellsResult.Read<int>(58);
|
||||
spellInfo.EquippedItemSubClassMask = spellsResult.Read<int>(59);
|
||||
spellInfo.EquippedItemInventoryTypeMask = spellsResult.Read<int>(60);
|
||||
spellInfo.ContentTuningId = spellsResult.Read<uint>(61);
|
||||
spellInfo.ConeAngle = spellsResult.Read<float>(63);
|
||||
spellInfo.Width = spellsResult.Read<float>(64);
|
||||
spellInfo.MaxTargetLevel = spellsResult.Read<uint>(65);
|
||||
spellInfo.MaxAffectedTargets = spellsResult.Read<uint>(66);
|
||||
spellInfo.SpellFamilyName = (SpellFamilyNames)spellsResult.Read<uint>(67);
|
||||
spellInfo.SpellFamilyFlags = new FlagArray128(spellsResult.Read<uint>(68), spellsResult.Read<uint>(69), spellsResult.Read<uint>(70), spellsResult.Read<uint>(71));
|
||||
spellInfo.DmgClass = (SpellDmgClass)spellsResult.Read<uint>(72);
|
||||
spellInfo.PreventionType = (SpellPreventionType)spellsResult.Read<uint>(73);
|
||||
spellInfo.RequiredAreasID = spellsResult.Read<int>(74);
|
||||
spellInfo.SchoolMask = (SpellSchoolMask)spellsResult.Read<uint>(75);
|
||||
spellInfo.ChargeCategoryId = spellsResult.Read<uint>(76);
|
||||
spellInfo.CasterAuraType = (AuraType)spellsResult.Read<int>(34);
|
||||
spellInfo.TargetAuraType = (AuraType)spellsResult.Read<int>(35);
|
||||
spellInfo.ExcludeCasterAuraType = (AuraType)spellsResult.Read<int>(36);
|
||||
spellInfo.ExcludeTargetAuraType = (AuraType)spellsResult.Read<int>(37);
|
||||
spellInfo.CastTimeEntry = CliDB.SpellCastTimesStorage.LookupByKey(spellsResult.Read<uint>(38));
|
||||
spellInfo.RecoveryTime = spellsResult.Read<uint>(39);
|
||||
spellInfo.CategoryRecoveryTime = spellsResult.Read<uint>(40);
|
||||
spellInfo.StartRecoveryCategory = spellsResult.Read<uint>(41);
|
||||
spellInfo.StartRecoveryTime = spellsResult.Read<uint>(42);
|
||||
spellInfo.InterruptFlags = (SpellInterruptFlags)spellsResult.Read<uint>(43);
|
||||
spellInfo.AuraInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read<uint>(44);
|
||||
spellInfo.AuraInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read<uint>(45);
|
||||
spellInfo.ChannelInterruptFlags = (SpellAuraInterruptFlags)spellsResult.Read<uint>(46);
|
||||
spellInfo.ChannelInterruptFlags2 = (SpellAuraInterruptFlags2)spellsResult.Read<uint>(47);
|
||||
spellInfo.ProcFlags = new ProcFlagsInit(spellsResult.Read<int>(48), spellsResult.Read<int>(49));
|
||||
spellInfo.ProcChance = spellsResult.Read<uint>(50);
|
||||
spellInfo.ProcCharges = spellsResult.Read<uint>(51);
|
||||
spellInfo.ProcCooldown = spellsResult.Read<uint>(52);
|
||||
spellInfo.ProcBasePPM = spellsResult.Read<float>(53);
|
||||
spellInfo.MaxLevel = spellsResult.Read<uint>(54);
|
||||
spellInfo.BaseLevel = spellsResult.Read<uint>(55);
|
||||
spellInfo.SpellLevel = spellsResult.Read<uint>(56);
|
||||
spellInfo.DurationEntry = CliDB.SpellDurationStorage.LookupByKey(spellsResult.Read<uint>(57));
|
||||
spellInfo.RangeEntry = CliDB.SpellRangeStorage.LookupByKey(spellsResult.Read<uint>(58));
|
||||
spellInfo.Speed = spellsResult.Read<float>(59);
|
||||
spellInfo.LaunchDelay = spellsResult.Read<float>(60);
|
||||
spellInfo.StackAmount = spellsResult.Read<uint>(61);
|
||||
spellInfo.EquippedItemClass = (ItemClass)spellsResult.Read<int>(62);
|
||||
spellInfo.EquippedItemSubClassMask = spellsResult.Read<int>(63);
|
||||
spellInfo.EquippedItemInventoryTypeMask = spellsResult.Read<int>(64);
|
||||
spellInfo.ContentTuningId = spellsResult.Read<uint>(65);
|
||||
spellInfo.ConeAngle = spellsResult.Read<float>(67);
|
||||
spellInfo.Width = spellsResult.Read<float>(68);
|
||||
spellInfo.MaxTargetLevel = spellsResult.Read<uint>(69);
|
||||
spellInfo.MaxAffectedTargets = spellsResult.Read<uint>(70);
|
||||
spellInfo.SpellFamilyName = (SpellFamilyNames)spellsResult.Read<uint>(71);
|
||||
spellInfo.SpellFamilyFlags = new FlagArray128(spellsResult.Read<uint>(72), spellsResult.Read<uint>(73), spellsResult.Read<uint>(74), spellsResult.Read<uint>(75));
|
||||
spellInfo.DmgClass = (SpellDmgClass)spellsResult.Read<uint>(76);
|
||||
spellInfo.PreventionType = (SpellPreventionType)spellsResult.Read<uint>(77);
|
||||
spellInfo.RequiredAreasID = spellsResult.Read<int>(78);
|
||||
spellInfo.SchoolMask = (SpellSchoolMask)spellsResult.Read<uint>(79);
|
||||
spellInfo.ChargeCategoryId = spellsResult.Read<uint>(80);
|
||||
|
||||
mSpellInfoMap.Add(spellId, spellInfo);
|
||||
|
||||
|
||||
@@ -890,9 +890,6 @@ namespace Game
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loading Gossip menu addon...");
|
||||
Global.ObjectMgr.LoadGossipMenuAddon();
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loading Gossip menu item addon...");
|
||||
Global.ObjectMgr.LoadGossipMenuItemAddon();
|
||||
|
||||
Log.outInfo(LogFilter.ServerLoading, "Loading Creature trainers...");
|
||||
Global.ObjectMgr.LoadCreatureTrainers(); // must be after LoadGossipMenuItems
|
||||
|
||||
|
||||
Reference in New Issue
Block a user