diff --git a/Source/Framework/Database/Databases/WorldDatabase.cs b/Source/Framework/Database/Databases/WorldDatabase.cs index 2262c1134..fd8e20cc1 100644 --- a/Source/Framework/Database/Databases/WorldDatabase.cs +++ b/Source/Framework/Database/Databases/WorldDatabase.cs @@ -61,7 +61,7 @@ namespace Framework.Database PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_ID_BY_GUID, "SELECT id FROM waypoint_scripts WHERE guid = ?"); PrepareStatement(WorldStatements.DEL_CREATURE, "DELETE FROM creature WHERE guid = ?"); PrepareStatement(WorldStatements.SEL_COMMANDS, "SELECT name, help FROM command"); - PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, gossip_menu_id, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?"); + PrepareStatement(WorldStatements.SEL_CREATURE_TEMPLATE, "SELECT entry, difficulty_entry_1, difficulty_entry_2, difficulty_entry_3, KillCredit1, KillCredit2, name, femaleName, subname, TitleAlt, IconName, HealthScalingExpansion, RequiredExpansion, VignetteID, faction, npcflag, speed_walk, speed_run, scale, `rank`, dmgschool, BaseAttackTime, RangeAttackTime, BaseVariance, RangeVariance, unit_class, unit_flags, unit_flags2, unit_flags3, dynamicflags, family, trainer_class, type, type_flags, type_flags2, lootid, pickpocketloot, skinloot, VehicleId, mingold, maxgold, AIName, MovementType, ctm.Ground, ctm.Swim, ctm.Flight, ctm.Rooted, ctm.Chase, ctm.Random, ctm.InteractionPauseTimer, HoverHeight, HealthModifier, HealthModifierExtra, ManaModifier, ManaModifierExtra, ArmorModifier, DamageModifier, ExperienceModifier, RacialLeader, movementId, CreatureDifficultyID, WidgetSetID, WidgetSetUnitConditionID, RegenHealth, mechanic_immune_mask, spell_school_immune_mask, flags_extra, ScriptName, StringId FROM creature_template ct LEFT JOIN creature_template_movement ctm ON ct.entry = ctm.CreatureId WHERE entry = ? OR 1 = ?"); PrepareStatement(WorldStatements.SEL_WAYPOINT_SCRIPT_BY_ID, "SELECT guid, delay, command, datalong, datalong2, dataint, x, y, z, o FROM waypoint_scripts WHERE id = ?"); PrepareStatement(WorldStatements.SEL_CREATURE_BY_ID, "SELECT guid FROM creature WHERE id = ?"); PrepareStatement(WorldStatements.SEL_GAMEOBJECT_NEAREST, "SELECT guid, id, position_x, position_y, position_z, map, (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) AS order_ FROM gameobject WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_"); diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 5c5e4e997..be9819597 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -623,17 +623,18 @@ namespace Game bool AddToGossipMenus(Condition cond) { var pMenuBounds = Global.ObjectMgr.GetGossipMenusMapBounds(cond.SourceGroup); - - foreach (var menu in pMenuBounds) + if (!pMenuBounds.Empty()) { - if (menu.MenuId == cond.SourceGroup && menu.TextId == cond.SourceEntry) + foreach (var menu in pMenuBounds) { - menu.Conditions.Add(cond); - return true; + if (menu.MenuId == cond.SourceGroup && (menu.TextId == cond.SourceEntry || cond.SourceEntry == 0)) + menu.Conditions.Add(cond); } + + return true; } - Log.outError(LogFilter.Sql, "{0} GossipMenu {1} not found.", cond.ToString(), cond.SourceGroup); + Log.outError(LogFilter.Sql, $"{cond} GossipMenu {cond.SourceGroup} not found."); return false; } diff --git a/Source/Game/Entities/Creature/Creature.Fields.cs b/Source/Game/Entities/Creature/Creature.Fields.cs index a0ed50c0d..05b7886e5 100644 --- a/Source/Game/Entities/Creature/Creature.Fields.cs +++ b/Source/Game/Entities/Creature/Creature.Fields.cs @@ -28,7 +28,7 @@ namespace Game.Entities bool _isMissingCanSwimFlagOutOfCombat; - uint? _gossipMenuId; + uint _gossipMenuId; uint? _trainerId; public ulong m_PlayerDamageReq; diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index 0f0f87d28..86c3e7916 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -1140,13 +1140,10 @@ namespace Game.Entities public uint GetGossipMenuId() { - if (_gossipMenuId.HasValue) - return _gossipMenuId.Value; - - return GetCreatureTemplate().GossipMenuId; + return _gossipMenuId; } - public void SetGossipMenuId(uint? gossipMenuId) + public void SetGossipMenuId(uint gossipMenuId) { _gossipMenuId = gossipMenuId; } diff --git a/Source/Game/Entities/Creature/CreatureData.cs b/Source/Game/Entities/Creature/CreatureData.cs index a39dcc651..ae1409654 100644 --- a/Source/Game/Entities/Creature/CreatureData.cs +++ b/Source/Game/Entities/Creature/CreatureData.cs @@ -21,7 +21,7 @@ namespace Game.Entities public string SubName; public string TitleAlt; public string IconName; - public uint GossipMenuId; + public List GossipMenuIds = new(); public Dictionary scalingStorage = new(); public int HealthScalingExpansion; public uint RequiredExpansion; diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index d48a7097d..aa1d52cee 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -21,12 +21,13 @@ using Game.Maps; using Game.Misc; using Game.Networking; using Game.Networking.Packets; -using Game.PvP; using Game.Spells; using System; using System.Collections.Generic; using System.Linq; +using static Global; + namespace Game.Entities { public partial class Player : Unit @@ -92,7 +93,7 @@ namespace Game.Entities m_isActive = true; m_ControlledByPlayer = true; - Global.WorldMgr.IncreasePlayerCount(); + WorldMgr.IncreasePlayerCount(); _cinematicMgr = new CinematicManager(this); @@ -142,7 +143,7 @@ namespace Game.Entities ClearResurrectRequestData(); - Global.WorldMgr.DecreasePlayerCount(); + WorldMgr.DecreasePlayerCount(); base.Dispose(); } @@ -154,7 +155,7 @@ namespace Game.Entities SetName(createInfo.Name); - PlayerInfo info = Global.ObjectMgr.GetPlayerInfo(createInfo.RaceId, createInfo.ClassId); + PlayerInfo info = ObjectMgr.GetPlayerInfo(createInfo.RaceId, createInfo.ClassId); if (info == null) { Log.outError(LogFilter.Player, "PlayerCreate: Possible hacking-attempt: Account {0} tried creating a character named '{1}' with an invalid race/class pair ({2}/{3}) - refusing to do so.", @@ -184,7 +185,7 @@ namespace Game.Entities Relocate(position.Loc); - SetMap(Global.MapMgr.CreateMap(position.Loc.GetMapId(), this)); + SetMap(MapMgr.CreateMap(position.Loc.GetMapId(), this)); if (position.TransportGuid.HasValue) { @@ -313,7 +314,7 @@ namespace Game.Entities } // all item positions resolved - ChrSpecializationRecord defaultSpec = Global.DB2Mgr.GetDefaultChrSpecializationForClass(GetClass()); + ChrSpecializationRecord defaultSpec = DB2Mgr.GetDefaultChrSpecializationForClass(GetClass()); if (defaultSpec != null) { SetActiveTalentGroup(defaultSpec.OrderIndex); @@ -531,7 +532,7 @@ namespace Game.Entities if (diff >= m_nextSave) { // m_nextSave reset in SaveToDB call - Global.ScriptMgr.OnPlayerSave(this); + ScriptMgr.OnPlayerSave(this); SaveToDB(); Log.outDebug(LogFilter.Player, "Player '{0}' (GUID: {1}) saved", GetName(), GetGUID().ToString()); } @@ -717,8 +718,8 @@ namespace Game.Entities ClearComboPoints(); GetSession().DoLootReleaseAll(); m_lootRolls.Clear(); - Global.OutdoorPvPMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); - Global.BattleFieldMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); + OutdoorPvPMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); + BattleFieldMgr.HandlePlayerLeaveZone(this, m_zoneUpdateId); } // Remove items from world before self - player must be found in Item.RemoveFromObjectUpdate @@ -1053,14 +1054,14 @@ namespace Game.Entities for (uint i = 0; i < SharedConst.MaxCreatureSpells; ++i) { uint spellId = vehicle.m_spells[i]; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); + SpellInfo spellInfo = SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo == null) continue; if (spellInfo.HasAttribute(SpellAttr5.NotAvailableWhileCharmed)) continue; - if (!Global.ConditionMgr.IsObjectMeetingVehicleSpellConditions(vehicle.GetEntry(), spellId, this, vehicle)) + if (!ConditionMgr.IsObjectMeetingVehicleSpellConditions(vehicle.GetEntry(), spellId, this, vehicle)) { Log.outDebug(LogFilter.Condition, "VehicleSpellInitialize: conditions not met for Vehicle entry {0} spell {1}", vehicle.ToCreature().GetEntry(), spellId); continue; @@ -1337,7 +1338,7 @@ namespace Game.Entities uint maxQuantity = currency.MaxQty; if (currency.MaxQtyWorldStateID != 0) - maxQuantity = (uint)Global.WorldStateMgr.GetValue(currency.MaxQtyWorldStateID, GetMap()); + maxQuantity = (uint)WorldStateMgr.GetValue(currency.MaxQtyWorldStateID, GetMap()); uint increasedCap = 0; if (currency.GetFlags().HasFlag(CurrencyTypesFlags.DynamicMaximum)) @@ -1392,14 +1393,14 @@ namespace Game.Entities switch ((ActionButtonType)type) { case ActionButtonType.Spell: - if (!Global.SpellMgr.HasSpellInfo((uint)action, Difficulty.None)) + if (!SpellMgr.HasSpellInfo((uint)action, Difficulty.None)) { Log.outError(LogFilter.Player, $"Player::IsActionButtonDataValid: Spell action {action} not added into button {button} for player {GetName()} ({GetGUID()}): spell not exist"); return false; } break; case ActionButtonType.Item: - if (Global.ObjectMgr.GetItemTemplate((uint)action) == null) + if (ObjectMgr.GetItemTemplate((uint)action) == null) { Log.outError(LogFilter.Player, $"Player::IsActionButtonDataValid: Item action {action} not added into button {button} for player {GetName()} ({GetGUID()}): item not exist"); return false; @@ -1548,7 +1549,7 @@ namespace Game.Entities return 0; // Multiply result with the faction specific rate - RepRewardRate repData = Global.ObjectMgr.GetRepRewardRate((uint)faction); + RepRewardRate repData = ObjectMgr.GetRepRewardRate((uint)faction); if (repData != null) { float repRate = 0.0f; @@ -1598,7 +1599,7 @@ namespace Game.Entities if (victim.ToCreature().IsReputationGainDisabled()) return; - ReputationOnKillEntry Rep = Global.ObjectMgr.GetReputationOnKilEntry(victim.ToCreature().GetCreatureTemplate().Entry); + ReputationOnKillEntry Rep = ObjectMgr.GetReputationOnKilEntry(victim.ToCreature().GetCreatureTemplate().Entry); if (Rep == null) return; @@ -1610,12 +1611,12 @@ namespace Game.Entities Map map = GetMap(); if (map.IsNonRaidDungeon()) { - LFGDungeonsRecord dungeon = Global.DB2Mgr.GetLfgDungeon(map.GetId(), map.GetDifficultyID()); + LFGDungeonsRecord dungeon = DB2Mgr.GetLfgDungeon(map.GetId(), map.GetDifficultyID()); if (dungeon != null) { - var dungeonLevels = Global.DB2Mgr.GetContentTuningData(dungeon.ContentTuningID, m_playerData.CtrOptions.GetValue().ContentTuningConditionMask); + var dungeonLevels = DB2Mgr.GetContentTuningData(dungeon.ContentTuningID, m_playerData.CtrOptions.GetValue().ContentTuningConditionMask); if (dungeonLevels.HasValue) - if (dungeonLevels.Value.TargetLevelMax == Global.ObjectMgr.GetMaxLevelForExpansion(Expansion.WrathOfTheLichKing)) + if (dungeonLevels.Value.TargetLevelMax == ObjectMgr.GetMaxLevelForExpansion(Expansion.WrathOfTheLichKing)) ChampioningFaction = GetChampioningFaction(); } } @@ -1716,7 +1717,7 @@ namespace Game.Entities return false; } - if (!GetSession().HasPermission(RBACPermissions.SkipCheckDisableMap) && Global.DisableMgr.IsDisabledFor(DisableType.Map, mapid, this)) + if (!GetSession().HasPermission(RBACPermissions.SkipCheckDisableMap) && DisableMgr.IsDisabledFor(DisableType.Map, mapid, this)) { Log.outError(LogFilter.Maps, "Player (GUID: {0}, name: {1}) tried to enter a forbidden map {2}", GetGUID().ToString(), GetName(), mapid); SendTransferAborted(mapid, TransferAbortReason.MapNotAllowed); @@ -2148,7 +2149,7 @@ namespace Game.Entities SummonRequest summonRequest = new(); summonRequest.SummonerGUID = summoner.GetGUID(); - summonRequest.SummonerVirtualRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); + summonRequest.SummonerVirtualRealmAddress = WorldMgr.GetVirtualRealmAddress(); summonRequest.AreaID = (int)summoner.GetZoneId(); SendPacket(summonRequest); @@ -2299,7 +2300,7 @@ namespace Game.Entities pet.SetFaction(GetFaction()); // restore FFA PvP Server state - if (Global.WorldMgr.IsFFAPvPRealm()) + if (WorldMgr.IsFFAPvPRealm()) SetPvpFlag(UnitPVPStateFlags.FFAPvp); // restore FFA PvP area state, remove not allowed for GM mounts @@ -2356,7 +2357,7 @@ namespace Game.Entities menu.GetGossipMenu().SetMenuId(menuId); - var menuItemBounds = Global.ObjectMgr.GetGossipMenuItemsMapBounds(menuId); + var menuItemBounds = ObjectMgr.GetGossipMenuItemsMapBounds(menuId); if (source.IsTypeId(TypeId.Unit)) { @@ -2369,7 +2370,7 @@ namespace Game.Entities foreach (var gossipMenuItem in menuItemBounds) { - if (!Global.ConditionMgr.IsObjectMeetToConditions(this, source, gossipMenuItem.Conditions)) + if (!ConditionMgr.IsObjectMeetToConditions(this, source, gossipMenuItem.Conditions)) continue; bool canTalk = true; @@ -2528,7 +2529,7 @@ namespace Game.Entities GetSession().SendTaxiMenu(source.ToCreature()); break; case GossipOptionNpc.Trainer: - GetSession().SendTrainerList(source.ToCreature(), Global.ObjectMgr.GetCreatureTrainerForGossipOption(source.GetEntry(), menuId, item.OrderIndex)); + GetSession().SendTrainerList(source.ToCreature(), ObjectMgr.GetCreatureTrainerForGossipOption(source.GetEntry(), menuId, item.OrderIndex)); break; case GossipOptionNpc.SpiritHealer: source.CastSpell(source.ToCreature(), 17251, new CastSpellExtraArgs(TriggerCastFlags.FullMask).SetOriginalCaster(GetGUID())); @@ -2540,7 +2541,7 @@ namespace Game.Entities break; case GossipOptionNpc.Battlemaster: { - BattlegroundTypeId bgTypeId = Global.BattlegroundMgr.GetBattleMasterBG(source.GetEntry()); + BattlegroundTypeId bgTypeId = BattlegroundMgr.GetBattleMasterBG(source.GetEntry()); if (bgTypeId == BattlegroundTypeId.None) { @@ -2548,7 +2549,7 @@ namespace Game.Entities return; } - Global.BattlegroundMgr.SendBattlegroundList(this, guid, bgTypeId); + BattlegroundMgr.SendBattlegroundList(this, guid, bgTypeId); break; } case GossipOptionNpc.Auctioneer: @@ -2619,7 +2620,7 @@ namespace Game.Entities { if (item.GossipNpcOptionID.HasValue) { - GossipMenuAddon addon = Global.ObjectMgr.GetGossipMenuAddon(menuId); + GossipMenuAddon addon = ObjectMgr.GetGossipMenuAddon(menuId); GossipOptionNPCInteraction npcInteraction = new(); npcInteraction.GossipGUID = source.GetGUID(); @@ -2673,7 +2674,7 @@ namespace Game.Entities if (source == null) return SharedConst.DefaultGossipMessage; - return GetGossipTextId(GetDefaultGossipMenuForSource(source), source); + return GetGossipTextId(GetGossipMenuForSource(source), source); } public uint GetGossipTextId(uint menuId, WorldObject source) @@ -2683,22 +2684,48 @@ namespace Game.Entities if (menuId == 0) return textId; - var menuBounds = Global.ObjectMgr.GetGossipMenusMapBounds(menuId); + var menuBounds = ObjectMgr.GetGossipMenusMapBounds(menuId); foreach (var menu in menuBounds) { - if (Global.ConditionMgr.IsObjectMeetToConditions(this, source, menu.Conditions)) + // continue if only checks menuid instead of text + if (menu.TextId == 0) + continue; + + if (ConditionMgr.IsObjectMeetToConditions(this, source, menu.Conditions)) textId = menu.TextId; } return textId; } - public static uint GetDefaultGossipMenuForSource(WorldObject source) + + public uint GetGossipMenuForSource(WorldObject source) { switch (source.GetTypeId()) { case TypeId.Unit: - return source.ToCreature().GetGossipMenuId(); + { + uint menuIdToShow = source.ToCreature().GetGossipMenuId(); + + // if menu id is set by script + if (menuIdToShow != 0) + return menuIdToShow; + + // otherwise pick from db based on conditions + foreach (uint menuId in source.ToCreature().GetCreatureTemplate().GossipMenuIds) + { + var menuBounds = ObjectMgr.GetGossipMenusMapBounds(menuId); + + foreach (var itr in menuBounds) + { + if (!ConditionMgr.IsObjectMeetToConditions(this, source, itr.Conditions)) + continue; + + menuIdToShow = menuId; + } + } + return menuIdToShow; + } case TypeId.GameObject: return source.ToGameObject().GetGoInfo().GetGossipMenuId(); default: @@ -3008,7 +3035,7 @@ namespace Game.Entities packet.AreaID = zoneId; packet.SubareaID = areaId; - Global.WorldStateMgr.FillInitialWorldStates(packet, GetMap(), areaId); + WorldStateMgr.FillInitialWorldStates(packet, GetMap(), areaId); SendPacket(packet); } @@ -3308,7 +3335,7 @@ namespace Game.Entities int curValue = GetPower(power); // TODO: updating haste should update UNIT_FIELD_POWER_REGEN_FLAT_MODIFIER for certain power types - PowerTypeRecord powerType = Global.DB2Mgr.GetPowerTypeEntry(power); + PowerTypeRecord powerType = DB2Mgr.GetPowerTypeEntry(power); if (powerType == null) return; @@ -3511,7 +3538,7 @@ namespace Game.Entities { ObjectGuid selectionGUID = GetTarget(); if (!selectionGUID.IsEmpty()) - return Global.ObjAccessor.GetUnit(this, selectionGUID); + return ObjAccessor.GetUnit(this, selectionGUID); return null; } @@ -3519,7 +3546,7 @@ namespace Game.Entities { ObjectGuid selectionGUID = GetTarget(); if (!selectionGUID.IsEmpty()) - return Global.ObjAccessor.GetPlayer(this, selectionGUID); + return ObjAccessor.GetPlayer(this, selectionGUID); return null; } @@ -3714,7 +3741,7 @@ namespace Game.Entities StopMirrorTimers(); //disable timers(bars) // OnPlayerRepop hook - Global.ScriptMgr.OnPlayerRepop(this); + ScriptMgr.OnPlayerRepop(this); } public void StopMirrorTimers() @@ -3953,7 +3980,7 @@ namespace Game.Entities uint newzone, newarea; GetZoneAndAreaId(out newzone, out newarea); UpdateZone(newzone, newarea); - Global.OutdoorPvPMgr.HandlePlayerResurrects(this, newzone); + OutdoorPvPMgr.HandlePlayerResurrects(this, newzone); if (InBattleground()) { @@ -4128,11 +4155,11 @@ namespace Game.Entities ClosestGrave = bg.GetClosestGraveYard(this); else { - BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(GetMap(), GetZoneId()); + BattleField bf = BattleFieldMgr.GetBattlefieldToZoneId(GetMap(), GetZoneId()); if (bf != null) ClosestGrave = bf.GetClosestGraveYard(this); else - ClosestGrave = Global.ObjectMgr.GetClosestGraveYard(this, GetTeam(), this); + ClosestGrave = ObjectMgr.GetClosestGraveYard(this, GetTeam(), this); } // stop countdown until repop @@ -4300,7 +4327,7 @@ namespace Game.Entities } Map map = GetMap(); - uint petNumber = Global.ObjectMgr.GeneratePetNumber(); + uint petNumber = ObjectMgr.GeneratePetNumber(); if (!pet.Create(map.GenerateLowGuid(HighGuid.Pet), map, entry, petNumber)) { Log.outError(LogFilter.Server, "no such creature entry {0}", entry); @@ -4368,7 +4395,7 @@ namespace Game.Entities { //returning of reagents only for players, so best done here uint spellId = pet ? pet.m_unitData.CreatedBySpell : m_oldpetspell; - SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); + SpellInfo spellInfo = SpellMgr.GetSpellInfo(spellId, GetMap().GetDifficultyID()); if (spellInfo != null) { @@ -4485,12 +4512,12 @@ namespace Game.Entities public void SendPlayerChoice(ObjectGuid sender, int choiceId) { - PlayerChoice playerChoice = Global.ObjectMgr.GetPlayerChoice(choiceId); + PlayerChoice playerChoice = ObjectMgr.GetPlayerChoice(choiceId); if (playerChoice == null) return; Locale locale = GetSession().GetSessionDbLocaleIndex(); - PlayerChoiceLocale playerChoiceLocale = locale != Locale.enUS ? Global.ObjectMgr.GetPlayerChoiceLocale(choiceId) : null; + PlayerChoiceLocale playerChoiceLocale = locale != Locale.enUS ? ObjectMgr.GetPlayerChoiceLocale(choiceId) : null; PlayerTalkClass.GetInteractionData().Reset(); PlayerTalkClass.GetInteractionData().SourceGuid = sender; @@ -4810,7 +4837,7 @@ namespace Game.Entities if (amount == 0) return true; - Global.ScriptMgr.OnPlayerMoneyChanged(this, amount); + ScriptMgr.OnPlayerMoneyChanged(this, amount); if (amount < 0) SetMoney((ulong)(GetMoney() > (ulong)-amount ? (long)GetMoney() + amount : 0)); @@ -4880,7 +4907,7 @@ namespace Game.Entities RemovePlayerFlag(PlayerFlags.GuildLevelEnabled); } - Global.CharacterCacheStorage.UpdateCharacterGuildId(GetGUID(), guildId); + CharacterCacheStorage.UpdateCharacterGuildId(GetGUID(), guildId); } public void SetGuildRank(byte rankId) { SetUpdateFieldValue(m_values.ModifyValue(m_playerData).ModifyValue(m_playerData.GuildRankID), rankId); } public uint GetGuildRank() { return m_playerData.GuildRankID; } @@ -4891,12 +4918,12 @@ namespace Game.Entities public Guild GetGuild() { ulong guildId = GetGuildId(); - return guildId != 0 ? Global.GuildMgr.GetGuildById(guildId) : null; + return guildId != 0 ? GuildMgr.GetGuildById(guildId) : null; } public ulong GetGuildIdInvited() { return m_GuildIdInvited; } public string GetGuildName() { - return GetGuildId() != 0 ? Global.GuildMgr.GetGuildById(GetGuildId()).GetName() : ""; + return GetGuildId() != 0 ? GuildMgr.GetGuildById(GetGuildId()).GetName() : ""; } public void SetFreePrimaryProfessions(uint profs) { SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.CharacterPoints), profs); } @@ -4910,9 +4937,9 @@ namespace Game.Entities if (guild != null) guild.UpdateMemberData(this, GuildMemberData.Level, level); - PlayerLevelInfo info = Global.ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), level); + PlayerLevelInfo info = ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), level); - Global.ObjectMgr.GetPlayerClassLevelInfo(GetClass(), level, out uint basemana); + ObjectMgr.GetPlayerClassLevelInfo(GetClass(), level, out uint basemana); LevelUpInfo packet = new(); packet.Level = level; @@ -4930,12 +4957,12 @@ namespace Game.Entities for (Stats i = Stats.Strength; i < Stats.Max; ++i) packet.StatDelta[(int)i] = info.stats[(int)i] - (int)GetCreateStat(i); - packet.NumNewTalents = (int)(Global.DB2Mgr.GetNumTalentsAtLevel(level, GetClass()) - Global.DB2Mgr.GetNumTalentsAtLevel(oldLevel, GetClass())); - packet.NumNewPvpTalentSlots = Global.DB2Mgr.GetPvpTalentNumSlotsAtLevel(level, GetClass()) - Global.DB2Mgr.GetPvpTalentNumSlotsAtLevel(oldLevel, GetClass()); + packet.NumNewTalents = (int)(DB2Mgr.GetNumTalentsAtLevel(level, GetClass()) - DB2Mgr.GetNumTalentsAtLevel(oldLevel, GetClass())); + packet.NumNewPvpTalentSlots = DB2Mgr.GetPvpTalentNumSlotsAtLevel(level, GetClass()) - DB2Mgr.GetPvpTalentNumSlotsAtLevel(oldLevel, GetClass()); SendPacket(packet); - SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.NextLevelXP), Global.ObjectMgr.GetXPForLevel(level)); + SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.NextLevelXP), ObjectMgr.GetXPForLevel(level)); //update level, max level of skills m_PlayedTimeLevel = 0; // Level Played Time reset @@ -4979,7 +5006,7 @@ namespace Game.Entities if (pet) pet.SynchronizeLevelWithOwner(); - MailLevelReward mailReward = Global.ObjectMgr.GetMailLevelReward(level, (uint)SharedConst.GetMaskForRace(GetRace())); + MailLevelReward mailReward = ObjectMgr.GetMailLevelReward(level, (uint)SharedConst.GetMaskForRace(GetRace())); if (mailReward != null) { //- TODO: Poor design of mail system @@ -4993,7 +5020,7 @@ namespace Game.Entities PushQuests(); - Global.ScriptMgr.OnPlayerLevelChanged(this, (byte)oldLevel); + ScriptMgr.OnPlayerLevelChanged(this, (byte)oldLevel); } public bool CanParry() @@ -5049,7 +5076,7 @@ namespace Game.Entities public void InitDisplayIds() { - ChrModelRecord model = Global.DB2Mgr.GetChrModel(GetRace(), GetNativeGender()); + ChrModelRecord model = DB2Mgr.GetChrModel(GetRace(), GetNativeGender()); if (model == null) { Log.outError(LogFilter.Player, $"Player {GetGUID()} has incorrect race/gender pair. Can't init display ids."); @@ -5057,7 +5084,7 @@ namespace Game.Entities } SetDisplayId(model.DisplayID, true); - SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StateAnimID), Global.DB2Mgr.GetEmptyAnimStateID()); + SetUpdateFieldValue(m_values.ModifyValue(m_unitData).ModifyValue(m_unitData.StateAnimID), DB2Mgr.GetEmptyAnimStateID()); } //Creature @@ -5195,7 +5222,7 @@ namespace Game.Entities ActiveGlyphs activeGlyphs = new(); foreach (uint glyphId in GetGlyphs(GetActiveTalentGroup())) { - List bindableSpells = Global.DB2Mgr.GetGlyphBindableSpells(glyphId); + List bindableSpells = DB2Mgr.GetGlyphBindableSpells(glyphId); foreach (uint bindableSpell in bindableSpells) if (HasSpell(bindableSpell) && !m_overrideSpells.ContainsKey(bindableSpell)) activeGlyphs.Glyphs.Add(new GlyphBinding(bindableSpell, (ushort)glyphId)); @@ -5359,7 +5386,7 @@ namespace Game.Entities if (!GetPlayerSharingQuest().IsEmpty()) { - Quest quest = Global.ObjectMgr.GetQuestTemplate(GetSharedQuestID()); + Quest quest = ObjectMgr.GetQuestTemplate(GetSharedQuestID()); if (quest != null) PlayerTalkClass.SendQuestGiverQuestDetails(quest, GetGUID(), true, false); else @@ -5371,7 +5398,7 @@ namespace Game.Entities public void RemoveSocial() { - Global.SocialMgr.RemovePlayerSocial(GetGUID()); + SocialMgr.RemovePlayerSocial(GetGUID()); m_social = null; } @@ -5413,17 +5440,17 @@ namespace Game.Entities _RemoveAllStatBonuses(); uint basemana; - Global.ObjectMgr.GetPlayerClassLevelInfo(GetClass(), GetLevel(), out basemana); + ObjectMgr.GetPlayerClassLevelInfo(GetClass(), GetLevel(), out basemana); - PlayerLevelInfo info = Global.ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), GetLevel()); + PlayerLevelInfo info = ObjectMgr.GetPlayerLevelInfo(GetRace(), GetClass(), GetLevel()); - int exp_max_lvl = (int)Global.ObjectMgr.GetMaxLevelForExpansion(GetSession().GetExpansion()); + int exp_max_lvl = (int)ObjectMgr.GetMaxLevelForExpansion(GetSession().GetExpansion()); int conf_max_lvl = WorldConfig.GetIntValue(WorldCfg.MaxPlayerLevel); if (exp_max_lvl == SharedConst.DefaultMaxLevel || exp_max_lvl >= conf_max_lvl) SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.MaxLevel), conf_max_lvl); else SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.MaxLevel), exp_max_lvl); - SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.NextLevelXP), Global.ObjectMgr.GetXPForLevel(GetLevel())); + SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.NextLevelXP), ObjectMgr.GetXPForLevel(GetLevel())); if (m_activePlayerData.XP >= m_activePlayerData.NextLevelXP) SetUpdateFieldValue(m_values.ModifyValue(m_activePlayerData).ModifyValue(m_activePlayerData.XP), m_activePlayerData.NextLevelXP - 1); @@ -5913,7 +5940,7 @@ namespace Game.Entities uint arenaTeamId = GetArenaTeamId(arenaSlot); if (arenaTeamId != 0) { - ArenaTeam arenaTeam = Global.ArenaTeamMgr.GetArenaTeamById(arenaTeamId); + ArenaTeam arenaTeam = ArenaTeamMgr.GetArenaTeamById(arenaTeamId); arenaTeam.FinishWeek(); // set played this week etc values to 0 in memory, too arenaTeam.SaveToDB(); // save changes arenaTeam.NotifyStatsChanged(); // notify the players of the changes @@ -5972,7 +5999,7 @@ namespace Game.Entities UpdateCriteria(CriteriaType.RevealWorldMapOverlay, GetAreaId()); - var areaLevels = Global.DB2Mgr.GetContentTuningData(areaEntry.ContentTuningID, m_playerData.CtrOptions.GetValue().ContentTuningConditionMask); + var areaLevels = DB2Mgr.GetContentTuningData(areaEntry.ContentTuningID, m_playerData.CtrOptions.GetValue().ContentTuningConditionMask); if (areaLevels.HasValue) { if (IsMaxLevel()) @@ -5986,7 +6013,7 @@ namespace Game.Entities uint XP; if (diff < -5) { - XP = (uint)(Global.ObjectMgr.GetBaseXP(GetLevel() + 5) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); + XP = (uint)(ObjectMgr.GetBaseXP(GetLevel() + 5) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); } else if (diff > 5) { @@ -5994,16 +6021,16 @@ namespace Game.Entities if (exploration_percent < 0) exploration_percent = 0; - XP = (uint)(Global.ObjectMgr.GetBaseXP(areaLevel) * exploration_percent / 100 * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); + XP = (uint)(ObjectMgr.GetBaseXP(areaLevel) * exploration_percent / 100 * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); } else { - XP = (uint)(Global.ObjectMgr.GetBaseXP(areaLevel) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); + XP = (uint)(ObjectMgr.GetBaseXP(areaLevel) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)); } if (WorldConfig.GetIntValue(WorldCfg.MinDiscoveredScaledXpRatio) != 0) { - uint minScaledXP = (uint)(Global.ObjectMgr.GetBaseXP(areaLevel) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)) * WorldConfig.GetUIntValue(WorldCfg.MinDiscoveredScaledXpRatio) / 100; + uint minScaledXP = (uint)(ObjectMgr.GetBaseXP(areaLevel) * WorldConfig.GetFloatValue(WorldCfg.RateXpExplore)) * WorldConfig.GetUIntValue(WorldCfg.MinDiscoveredScaledXpRatio) / 100; XP = Math.Max(minScaledXP, XP); } @@ -6021,7 +6048,7 @@ namespace Game.Entities public void SendSysMessage(CypherStrings str, params object[] args) { - string input = Global.ObjectMgr.GetCypherString(str); + string input = ObjectMgr.GetCypherString(str); string pattern = @"%(\d+(\.\d+)?)?(d|f|s|u)"; int count = 0; @@ -6057,7 +6084,7 @@ namespace Game.Entities #region Chat public override void Say(string text, Language language, WorldObject obj = null) { - Global.ScriptMgr.OnPlayerChat(this, ChatMsg.Say, language, text); + ScriptMgr.OnPlayerChat(this, ChatMsg.Say, language, text); SendChatMessageToSetInRange(ChatMsg.Say, language, text, WorldConfig.GetFloatValue(WorldCfg.ListenRangeSay)); } @@ -6081,7 +6108,7 @@ namespace Game.Entities } public override void Yell(string text, Language language, WorldObject obj = null) { - Global.ScriptMgr.OnPlayerChat(this, ChatMsg.Yell, language, text); + ScriptMgr.OnPlayerChat(this, ChatMsg.Yell, language, text); ChatPkt data = new(); data.Initialize(ChatMsg.Yell, language, this, this, text); @@ -6093,7 +6120,7 @@ namespace Game.Entities } public override void TextEmote(string text, WorldObject obj = null, bool something = false) { - Global.ScriptMgr.OnPlayerChat(this, ChatMsg.Emote, Language.Universal, text); + ScriptMgr.OnPlayerChat(this, ChatMsg.Emote, Language.Universal, text); ChatPkt data = new(); data.Initialize(ChatMsg.Emote, Language.Universal, this, this, text); @@ -6105,7 +6132,7 @@ namespace Game.Entities } public void WhisperAddon(string text, string prefix, bool isLogged, Player receiver) { - Global.ScriptMgr.OnPlayerChat(this, ChatMsg.Whisper, isLogged ? Language.AddonLogged : Language.Addon, text, receiver); + ScriptMgr.OnPlayerChat(this, ChatMsg.Whisper, isLogged ? Language.AddonLogged : Language.Addon, text, receiver); if (!receiver.GetSession().IsAddonRegistered(prefix)) return; @@ -6123,7 +6150,7 @@ namespace Game.Entities //Player rPlayer = Global.ObjAccessor.FindPlayer(receiver); - Global.ScriptMgr.OnPlayerChat(this, ChatMsg.Whisper, language, text, target); + ScriptMgr.OnPlayerChat(this, ChatMsg.Whisper, language, text, target); ChatPkt data = new(); data.Initialize(ChatMsg.Whisper, language, this, this, text); @@ -6163,7 +6190,7 @@ namespace Game.Entities Locale locale = target.GetSession().GetSessionDbLocaleIndex(); ChatPkt packet = new(); - packet.Initialize(ChatMsg.Whisper, Language.Universal, this, target, Global.DB2Mgr.GetBroadcastTextValue(bct, locale, GetGender())); + packet.Initialize(ChatMsg.Whisper, Language.Universal, this, target, DB2Mgr.GetBroadcastTextValue(bct, locale, GetGender())); target.SendPacket(packet); } public bool CanUnderstandLanguage(Language language) @@ -6171,7 +6198,7 @@ namespace Game.Entities if (IsGameMaster()) return true; - foreach (var languageDesc in Global.LanguageMgr.GetLanguageDescById(language)) + foreach (var languageDesc in LanguageMgr.GetLanguageDescById(language)) if (languageDesc.SkillId != 0 && HasSkill((SkillType)languageDesc.SkillId)) return true; @@ -6267,7 +6294,7 @@ namespace Game.Entities uint level = GetLevel(); - Global.ScriptMgr.OnGivePlayerXP(this, xp, victim); + ScriptMgr.OnGivePlayerXP(this, xp, victim); // XP to money conversion processed in Player.RewardQuest if (IsMaxLevel()) @@ -6586,7 +6613,7 @@ namespace Game.Entities uint path, cost; lastnode = nodes[i]; - Global.ObjectMgr.GetTaxiPath(prevnode, lastnode, out path, out cost); + ObjectMgr.GetTaxiPath(prevnode, lastnode, out path, out cost); if (path == 0) { @@ -6616,7 +6643,7 @@ namespace Game.Entities if (node.Flags.HasAnyFlag(TaxiNodeFlags.UseFavoriteMount) && preferredMountDisplay != 0) mount_display_id = preferredMountDisplay; else - mount_display_id = Global.ObjectMgr.GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == null || (sourcenode == 315 && GetClass() == Class.Deathknight)); + mount_display_id = ObjectMgr.GetTaxiMountDisplayId(sourcenode, GetTeam(), npc == null || (sourcenode == 315 && GetClass() == Class.Deathknight)); // in spell case allow 0 model if ((mount_display_id == 0 && spellid == 0) || sourcepath == 0) @@ -6704,7 +6731,7 @@ namespace Game.Entities Log.outDebug(LogFilter.Unit, "WORLD: Restart character {0} taxi flight", GetGUID().ToString()); - uint mountDisplayId = Global.ObjectMgr.GetTaxiMountDisplayId(sourceNode, GetTeam(), true); + uint mountDisplayId = ObjectMgr.GetTaxiMountDisplayId(sourceNode, GetTeam(), true); if (mountDisplayId == 0) return; @@ -6848,7 +6875,7 @@ namespace Game.Entities return true; // GMs are visible for higher gms (or players are visible for gms) - if (!Global.AccountMgr.IsPlayerAccount(u.GetSession().GetSecurity())) + if (!AccountMgr.IsPlayerAccount(u.GetSession().GetSecurity())) return GetSession().GetSecurity() <= u.GetSession().GetSecurity(); // non faction visibility non-breakable for non-GMs @@ -6876,7 +6903,7 @@ namespace Game.Entities long racemask = SharedConst.GetMaskForRace(GetRace()); uint classmask = GetClassMask(); - var bounds = Global.SpellMgr.GetSkillLineAbilityMapBounds(spell_id); + var bounds = SpellMgr.GetSkillLineAbilityMapBounds(spell_id); if (bounds.Empty()) return true; @@ -6892,7 +6919,7 @@ namespace Game.Entities continue; // skip wrong class and race skill saved in SkillRaceClassInfo.dbc - if (Global.DB2Mgr.GetSkillRaceClassInfo(_spell_idx.SkillLine, GetRace(), GetClass()) == null) + if (DB2Mgr.GetSkillRaceClassInfo(_spell_idx.SkillLine, GetRace(), GetClass()) == null) continue; return true; @@ -6999,7 +7026,7 @@ namespace Game.Entities { ObjectGuid guid = m_activePlayerData.FarsightObject; if (!guid.IsEmpty()) - return Global.ObjAccessor.GetObjectByTypeMask(this, guid, TypeMask.Seer); + return ObjAccessor.GetObjectByTypeMask(this, guid, TypeMask.Seer); return null; } @@ -7118,7 +7145,7 @@ namespace Game.Entities offItem.DeleteFromInventoryDB(trans); // deletes item from character's inventory offItem.SaveToDB(trans); // recursive and not have transaction guard into self, item not in inventory and can be save standalone - string subject = Global.ObjectMgr.GetCypherString(CypherStrings.NotEquippedItem); + string subject = ObjectMgr.GetCypherString(CypherStrings.NotEquippedItem); new MailDraft(subject, "There were problems with equipping one or several items").AddItem(offItem).SendMailTo(trans, this, new MailSender(this, MailStationery.Gm), MailCheckMask.Copied); DB.Characters.CommitTransaction(trans); diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index aa8dc2745..39e97a9d8 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -1822,34 +1822,33 @@ namespace Game creature.SubName = fields.Read(8); creature.TitleAlt = fields.Read(9); creature.IconName = fields.Read(10); - creature.GossipMenuId = fields.Read(11); - creature.HealthScalingExpansion = fields.Read(12); - creature.RequiredExpansion = fields.Read(13); - creature.VignetteID = fields.Read(14); - creature.Faction = fields.Read(15); - creature.Npcflag = fields.Read(16); - creature.SpeedWalk = fields.Read(17); - creature.SpeedRun = fields.Read(18); - creature.Scale = fields.Read(19); - creature.Rank = (CreatureEliteType)fields.Read(20); - creature.DmgSchool = fields.Read(21); - creature.BaseAttackTime = fields.Read(22); - creature.RangeAttackTime = fields.Read(23); - creature.BaseVariance = fields.Read(24); - creature.RangeVariance = fields.Read(25); - creature.UnitClass = fields.Read(26); - creature.UnitFlags = (UnitFlags)fields.Read(27); - creature.UnitFlags2 = fields.Read(28); - creature.UnitFlags3 = fields.Read(29); - creature.DynamicFlags = fields.Read(30); - creature.Family = (CreatureFamily)fields.Read(31); - creature.TrainerClass = (Class)fields.Read(32); - creature.CreatureType = (CreatureType)fields.Read(33); - creature.TypeFlags = (CreatureTypeFlags)fields.Read(34); - creature.TypeFlags2 = fields.Read(35); - creature.LootId = fields.Read(36); - creature.PickPocketId = fields.Read(37); - creature.SkinLootId = fields.Read(38); + creature.HealthScalingExpansion = fields.Read(11); + creature.RequiredExpansion = fields.Read(12); + creature.VignetteID = fields.Read(13); + creature.Faction = fields.Read(14); + creature.Npcflag = fields.Read(15); + creature.SpeedWalk = fields.Read(16); + creature.SpeedRun = fields.Read(17); + creature.Scale = fields.Read(18); + creature.Rank = (CreatureEliteType)fields.Read(19); + creature.DmgSchool = fields.Read(20); + creature.BaseAttackTime = fields.Read(21); + creature.RangeAttackTime = fields.Read(22); + creature.BaseVariance = fields.Read(23); + creature.RangeVariance = fields.Read(24); + creature.UnitClass = fields.Read(25); + creature.UnitFlags = (UnitFlags)fields.Read(26); + creature.UnitFlags2 = fields.Read(27); + creature.UnitFlags3 = fields.Read(28); + creature.DynamicFlags = fields.Read(29); + creature.Family = (CreatureFamily)fields.Read(30); + creature.TrainerClass = (Class)fields.Read(31); + creature.CreatureType = (CreatureType)fields.Read(32); + creature.TypeFlags = (CreatureTypeFlags)fields.Read(33); + creature.TypeFlags2 = fields.Read(34); + creature.LootId = fields.Read(35); + creature.PickPocketId = fields.Read(36); + creature.SkinLootId = fields.Read(37); for (var i = (int)SpellSchools.Holy; i < (int)SpellSchools.Max; ++i) creature.Resistance[i] = 0; @@ -1857,56 +1856,98 @@ namespace Game for (var i = 0; i < SharedConst.MaxCreatureSpells; ++i) creature.Spells[i] = 0; - creature.VehicleId = fields.Read(39); - creature.MinGold = fields.Read(40); - creature.MaxGold = fields.Read(41); - creature.AIName = fields.Read(42); - creature.MovementType = fields.Read(43); + creature.VehicleId = fields.Read(38); + creature.MinGold = fields.Read(39); + creature.MaxGold = fields.Read(40); + creature.AIName = fields.Read(41); + creature.MovementType = fields.Read(42); + + if (!fields.IsNull(43)) + creature.Movement.Ground = (CreatureGroundMovementType)fields.Read(43); if (!fields.IsNull(44)) - creature.Movement.Ground = (CreatureGroundMovementType)fields.Read(44); + creature.Movement.Swim = fields.Read(44); if (!fields.IsNull(45)) - creature.Movement.Swim = fields.Read(45); + creature.Movement.Flight = (CreatureFlightMovementType)fields.Read(45); if (!fields.IsNull(46)) - creature.Movement.Flight = (CreatureFlightMovementType)fields.Read(46); + creature.Movement.Rooted = fields.Read(46); if (!fields.IsNull(47)) - creature.Movement.Rooted = fields.Read(47); + creature.Movement.Chase = (CreatureChaseMovementType)fields.Read(47); if (!fields.IsNull(48)) - creature.Movement.Chase = (CreatureChaseMovementType)fields.Read(48); + creature.Movement.Random = (CreatureRandomMovementType)fields.Read(48); if (!fields.IsNull(49)) - creature.Movement.Random = (CreatureRandomMovementType)fields.Read(49); + creature.Movement.InteractionPauseTimer = fields.Read(49); - if (!fields.IsNull(50)) - creature.Movement.InteractionPauseTimer = fields.Read(50); - - creature.HoverHeight = fields.Read(51); - creature.ModHealth = fields.Read(52); - creature.ModHealthExtra = fields.Read(53); - creature.ModMana = fields.Read(54); - creature.ModManaExtra = fields.Read(55); - creature.ModArmor = fields.Read(56); - creature.ModDamage = fields.Read(57); - creature.ModExperience = fields.Read(58); - creature.RacialLeader = fields.Read(59); - creature.MovementId = fields.Read(60); - creature.CreatureDifficultyID = fields.Read(61); - creature.WidgetSetID = fields.Read(62); - creature.WidgetSetUnitConditionID = fields.Read(63); - creature.RegenHealth = fields.Read(64); - creature.MechanicImmuneMask = fields.Read(65); - creature.SpellSchoolImmuneMask = fields.Read(66); - creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(67); - creature.ScriptID = GetScriptId(fields.Read(68)); - creature.StringId = fields.Read(69); + creature.HoverHeight = fields.Read(50); + creature.ModHealth = fields.Read(51); + creature.ModHealthExtra = fields.Read(52); + creature.ModMana = fields.Read(53); + creature.ModManaExtra = fields.Read(54); + creature.ModArmor = fields.Read(55); + creature.ModDamage = fields.Read(56); + creature.ModExperience = fields.Read(57); + creature.RacialLeader = fields.Read(58); + creature.MovementId = fields.Read(59); + creature.CreatureDifficultyID = fields.Read(60); + creature.WidgetSetID = fields.Read(61); + creature.WidgetSetUnitConditionID = fields.Read(62); + creature.RegenHealth = fields.Read(63); + creature.MechanicImmuneMask = fields.Read(64); + creature.SpellSchoolImmuneMask = fields.Read(65); + creature.FlagsExtra = (CreatureFlagsExtra)fields.Read(66); + creature.ScriptID = GetScriptId(fields.Read(67)); + creature.StringId = fields.Read(68); creatureTemplateStorage[entry] = creature; } + public void LoadCreatureTemplateGossip() + { + uint oldMSTime = Time.GetMSTime(); + + // 0 1 + SQLResult result = DB.World.Query("SELECT CreatureID, MenuID FROM creature_template_gossip"); + if (result == null) + { + Log.outInfo(LogFilter.ServerLoading, "Loaded 0 creature template gossip definitions. DB table `creature_template_gossip` is empty."); + return; + } + + uint count = 0; + + do + { + uint creatureID = result.Read(0); + uint menuID = result.Read(1); + + var creatureTemplate = creatureTemplateStorage.LookupByKey(creatureID); + if (creatureTemplate == null) + { + Log.outError(LogFilter.Sql, $"creature_template_gossip has gossip definitions for creature {creatureID} but this creature doesn't exist"); + continue; + } + + var menuBounds = GetGossipMenusMapBounds(menuID); + if (menuBounds.Empty()) + { + Log.outError(LogFilter.Sql, $"creature_template_gossip has gossip definitions for menu id {menuID} but this menu doesn't exist"); + continue; + } + + creatureTemplate.GossipMenuIds.Add(menuID); + + ++count; + + } while (result.NextRow()); + + Log.outInfo(LogFilter.ServerLoading, $"Loaded {count} creature template gossip menus in {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); + } + void LoadCreatureTemplateResistances() { uint oldMSTime = Time.GetMSTime(); @@ -3004,9 +3045,9 @@ namespace Game cInfo.ModDamage *= Creature._GetDamageMod(cInfo.Rank); - if (cInfo.GossipMenuId != 0 && !cInfo.Npcflag.HasAnyFlag((ulong)NPCFlags.Gossip)) - Log.outInfo(LogFilter.Sql, $"Creature (Entry: {cInfo.Entry}) has assigned gossip menu {cInfo.GossipMenuId}, but npcflag does not include UNIT_NPC_FLAG_GOSSIP."); - else if (cInfo.GossipMenuId == 0 && cInfo.Npcflag.HasAnyFlag((ulong)NPCFlags.Gossip)) + if (!cInfo.GossipMenuIds.Empty() && !cInfo.Npcflag.HasAnyFlag((uint)NPCFlags.Gossip)) + Log.outInfo(LogFilter.Sql, $"Creature (Entry: {cInfo.Entry}) has assigned gossip menu, but npcflag does not include UNIT_NPC_FLAG_GOSSIP."); + else if (cInfo.GossipMenuIds.Empty() && cInfo.Npcflag.HasAnyFlag((uint)NPCFlags.Gossip)) Log.outInfo(LogFilter.Sql, $"Creature (Entry: {cInfo.Entry}) has npcflag UNIT_NPC_FLAG_GOSSIP, but gossip menu is unassigned."); } void CheckCreatureMovement(string table, ulong id, CreatureMovementData creatureMovement) diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 26c50b50c..d892f3d70 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -153,7 +153,7 @@ namespace Game _player.PlayerTalkClass.ClearMenus(); if (!unit.GetAI().OnGossipHello(_player)) { - GetPlayer().PrepareGossipMenu(unit, unit.GetGossipMenuId(), true); + GetPlayer().PrepareGossipMenu(unit, _player.GetGossipMenuForSource(unit), true); GetPlayer().SendPreparedGossip(unit); } } diff --git a/Source/Game/Handlers/QuestHandler.cs b/Source/Game/Handlers/QuestHandler.cs index c789767e1..24f82502e 100644 --- a/Source/Game/Handlers/QuestHandler.cs +++ b/Source/Game/Handlers/QuestHandler.cs @@ -68,7 +68,7 @@ namespace Game if (creature.GetAI().OnGossipHello(_player)) return; - GetPlayer().PrepareGossipMenu(creature, creature.GetGossipMenuId(), true); + GetPlayer().PrepareGossipMenu(creature, _player.GetGossipMenuForSource(creature), true); GetPlayer().SendPreparedGossip(creature); } diff --git a/Source/Game/World/WorldManager.cs b/Source/Game/World/WorldManager.cs index 6cd84dc99..8fb99563d 100644 --- a/Source/Game/World/WorldManager.cs +++ b/Source/Game/World/WorldManager.cs @@ -884,6 +884,9 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, "Loading Gossip menu addon..."); Global.ObjectMgr.LoadGossipMenuAddon(); + Log.outInfo(LogFilter.ServerLoading, "Loading Creature Template Gossip..."); + Global.ObjectMgr.LoadCreatureTemplateGossip(); + Log.outInfo(LogFilter.ServerLoading, "Loading Creature trainers..."); Global.ObjectMgr.LoadCreatureTrainers(); // must be after LoadGossipMenuItems