From 468b053946fb6c4a38b154f7068e01312cf16487 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Mon, 17 Sep 2018 12:08:48 -0400 Subject: [PATCH] Core/Maps: Replaced spawnmask with difficulty list --- Source/Framework/Constants/ConditionConst.cs | 5 +- .../Database/Databases/WorldDatabase.cs | 4 +- Source/Game/AI/ScriptedAI/ScriptedAI.cs | 2 +- Source/Game/AI/SmartScripts/SmartScript.cs | 24 ++- .../Game/Chat/Commands/GameObjectCommands.cs | 2 +- Source/Game/Chat/Commands/NPCCommands.cs | 4 +- Source/Game/Chat/Commands/WPCommands.cs | 9 +- Source/Game/Conditions/Condition.cs | 26 +-- Source/Game/Conditions/ConditionManager.cs | 18 +- Source/Game/Entities/Creature/Creature.cs | 10 +- Source/Game/Entities/Creature/CreatureData.cs | 2 +- Source/Game/Entities/GameObject/GameObject.cs | 8 +- .../Entities/GameObject/GameObjectData.cs | 3 +- Source/Game/Entities/Player/Player.DB.cs | 3 +- Source/Game/Entities/Player/Player.Fields.cs | 2 +- Source/Game/Entities/Player/Player.Map.cs | 81 ++++----- Source/Game/Entities/Player/Player.cs | 9 +- Source/Game/Entities/TemporarySummon.cs | 2 +- Source/Game/Entities/Transport.cs | 2 +- Source/Game/Garrisons/Garrisons.cs | 2 +- Source/Game/Globals/ObjectManager.cs | 162 ++++++++++-------- Source/Game/Groups/Group.cs | 54 +++--- Source/Game/Handlers/CalendarHandler.cs | 25 +-- Source/Game/Maps/Map.cs | 19 +- Source/Game/Maps/ObjectGridLoader.cs | 4 +- .../TrialOfTheCrusader/TrialOfTheCrusader.cs | 12 +- .../InstanceIcecrownCitadel.cs | 6 +- .../IcecrownCitadel/LordMarrowgar.cs | 2 +- .../world/master/2018_09_15_00_world.sql | 12 ++ 29 files changed, 285 insertions(+), 229 deletions(-) create mode 100644 sql/updates/world/master/2018_09_15_00_world.sql diff --git a/Source/Framework/Constants/ConditionConst.cs b/Source/Framework/Constants/ConditionConst.cs index 391997ef5..c1f7aca80 100644 --- a/Source/Framework/Constants/ConditionConst.cs +++ b/Source/Framework/Constants/ConditionConst.cs @@ -38,7 +38,7 @@ namespace Framework.Constants Race = 16, // Race 0 0 True If Player'S Race Is Equal To Race Achievement = 17, // Achievement_Id 0 0 True If Achievement Is Complete Title = 18, // Title Id 0 0 True If Player Has Title - Spawnmask = 19, // Spawnmask 0 0 True If In Spawnmask + SpawnmaskDeprecated = 19, // Deprecated Gender = 20, // Gender 0 0 True If Player'S Gender Is Equal To Gender UnitState = 21, // Unitstate 0 0 True If Unit Has Unitstate Mapid = 22, // Map_Id 0 0 True If In Map_Id @@ -68,7 +68,8 @@ namespace Framework.Constants Taxi = 46, // 0 0 0 true if player is on taxi Queststate = 47, // quest_id state_mask 0 true if player is in any of the provided quest states for the quest (1 = not taken, 2 = completed, 8 = in progress, 32 = failed, 64 = rewarded) ObjectiveComplete = 48, // ID 0 0 true if player has ID objective complete, but quest not yet rewarded - Max = 49 // Max + DifficultyId = 49, // Difficulty 0 0 true is map has difficulty id + Max } public enum ConditionSourceType diff --git a/Source/Framework/Database/Databases/WorldDatabase.cs b/Source/Framework/Database/Databases/WorldDatabase.cs index f8feab42e..8384645bb 100644 --- a/Source/Framework/Database/Databases/WorldDatabase.cs +++ b/Source/Framework/Database/Databases/WorldDatabase.cs @@ -80,10 +80,10 @@ namespace Framework.Database 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_"); PrepareStatement(WorldStatements.SEL_CREATURE_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 creature WHERE map = ? AND (POW(position_x - ?, 2) + POW(position_y - ?, 2) + POW(position_z - ?, 2)) <= ? ORDER BY order_"); - PrepareStatement(WorldStatements.INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnMask, PhaseId, PhaseGroup, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, unit_flags2, unit_flags3, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(WorldStatements.INS_CREATURE, "INSERT INTO creature (guid, id , map, spawnDifficulties, PhaseId, PhaseGroup, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, unit_flags2, unit_flags3, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(WorldStatements.DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?"); PrepareStatement(WorldStatements.DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?"); - PrepareStatement(WorldStatements.INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, PhaseId, PhaseGroup, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + PrepareStatement(WorldStatements.INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnDifficulties, PhaseId, PhaseGroup, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(WorldStatements.INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)"); PrepareStatement(WorldStatements.SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?"); PrepareStatement(WorldStatements.DEL_DISABLES, "DELETE FROM disables WHERE entry = ? AND sourceType = ?"); diff --git a/Source/Game/AI/ScriptedAI/ScriptedAI.cs b/Source/Game/AI/ScriptedAI/ScriptedAI.cs index fbae9cf57..f74538916 100644 --- a/Source/Game/AI/ScriptedAI/ScriptedAI.cs +++ b/Source/Game/AI/ScriptedAI/ScriptedAI.cs @@ -32,7 +32,7 @@ namespace Game.AI { _isCombatMovementAllowed = true; _isHeroic = me.GetMap().IsHeroic(); - _difficulty = me.GetMap().GetSpawnMode(); + _difficulty = me.GetMap().GetDifficultyID(); } void AttackStartNoMove(Unit target) diff --git a/Source/Game/AI/SmartScripts/SmartScript.cs b/Source/Game/AI/SmartScripts/SmartScript.cs index c855e1db6..7c32ec452 100644 --- a/Source/Game/AI/SmartScripts/SmartScript.cs +++ b/Source/Game/AI/SmartScripts/SmartScript.cs @@ -3612,9 +3612,29 @@ namespace Game.AI { if (obj != null && obj.GetMap().IsDungeon()) { - if (Convert.ToBoolean(1 << ((int)obj.GetMap().GetSpawnMode() + 1) & (int)holder.Event.event_flags)) + // TODO: fix it for new maps and difficulties + switch (obj.GetMap().GetDifficultyID()) { - mEvents.Add(holder); + case Difficulty.Normal: + case Difficulty.Raid10N: + if (holder.Event.event_flags.HasAnyFlag(SmartEventFlags.Difficulty0)) + mEvents.Add(holder); + break; + case Difficulty.Heroic: + case Difficulty.Raid25N: + if (holder.Event.event_flags.HasAnyFlag(SmartEventFlags.Difficulty1)) + mEvents.Add(holder); + break; + case Difficulty.Raid10HC: + if (holder.Event.event_flags.HasAnyFlag(SmartEventFlags.Difficulty2)) + mEvents.Add(holder); + break; + case Difficulty.Raid25HC: + if (holder.Event.event_flags.HasAnyFlag(SmartEventFlags.Difficulty3)) + mEvents.Add(holder); + break; + default: + break; } } continue; diff --git a/Source/Game/Chat/Commands/GameObjectCommands.cs b/Source/Game/Chat/Commands/GameObjectCommands.cs index a15a37a37..932785d58 100644 --- a/Source/Game/Chat/Commands/GameObjectCommands.cs +++ b/Source/Game/Chat/Commands/GameObjectCommands.cs @@ -484,7 +484,7 @@ namespace Game.Chat } // fill the gameobject data and save to the db - obj.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + obj.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong spawnId = obj.GetSpawnId(); // this will generate a new guid if the object is in an instance diff --git a/Source/Game/Chat/Commands/NPCCommands.cs b/Source/Game/Chat/Commands/NPCCommands.cs index b7f5ce6ee..23315812c 100644 --- a/Source/Game/Chat/Commands/NPCCommands.cs +++ b/Source/Game/Chat/Commands/NPCCommands.cs @@ -1095,7 +1095,7 @@ namespace Game.Chat // @todo: add phases Creature _creature = trans.CreateNPCPassenger(guid, data); - _creature.SaveToDB((uint)trans.GetGoInfo().MoTransport.SpawnMap, 1ul << (int)map.GetSpawnMode()); + _creature.SaveToDB((uint)trans.GetGoInfo().MoTransport.SpawnMap, new List() { map.GetDifficultyID() }); Global.ObjectMgr.AddCreatureToGrid(guid, data); return true; @@ -1106,7 +1106,7 @@ namespace Game.Chat return false; PhasingHandler.InheritPhaseShift(creature, chr); - creature.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + creature.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong db_guid = creature.GetSpawnId(); diff --git a/Source/Game/Chat/Commands/WPCommands.cs b/Source/Game/Chat/Commands/WPCommands.cs index dd47337de..c77929642 100644 --- a/Source/Game/Chat/Commands/WPCommands.cs +++ b/Source/Game/Chat/Commands/WPCommands.cs @@ -21,6 +21,7 @@ using Framework.IO; using Game.Entities; using Game.Maps; using System; +using System.Collections.Generic; namespace Game.Chat.Commands { @@ -549,7 +550,7 @@ namespace Game.Chat.Commands } PhasingHandler.InheritPhaseShift(creature, chr); - creature.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + creature.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong dbGuid = creature.GetSpawnId(); @@ -769,7 +770,7 @@ namespace Game.Chat.Commands } PhasingHandler.InheritPhaseShift(creature, chr); - creature.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + creature.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong dbGuid = creature.GetSpawnId(); @@ -835,7 +836,7 @@ namespace Game.Chat.Commands } PhasingHandler.InheritPhaseShift(creature, chr); - creature.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + creature.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong dbGuid = creature.GetSpawnId(); @@ -890,7 +891,7 @@ namespace Game.Chat.Commands } PhasingHandler.InheritPhaseShift(creature, chr); - creature.SaveToDB(map.GetId(), 1ul << (int)map.GetSpawnMode()); + creature.SaveToDB(map.GetId(), new List() { map.GetDifficultyID() }); ulong dbGuid = creature.GetSpawnId(); diff --git a/Source/Game/Conditions/Condition.cs b/Source/Game/Conditions/Condition.cs index 17fd98a15..8edd31d24 100644 --- a/Source/Game/Conditions/Condition.cs +++ b/Source/Game/Conditions/Condition.cs @@ -276,9 +276,6 @@ namespace Game.Conditions if (player != null) condMeets = player.HasTitle(ConditionValue1); break; - case ConditionTypes.Spawnmask: - condMeets = Convert.ToBoolean((1ul << (int)obj.GetMap().GetSpawnMode()) & ConditionValue1); - break; case ConditionTypes.UnitState: if (unit != null) condMeets = unit.HasUnitState((UnitState)ConditionValue1); @@ -372,6 +369,11 @@ namespace Game.Conditions } break; } + case ConditionTypes.DifficultyId: + { + condMeets = (uint)obj.GetMap().GetDifficultyID() == ConditionValue1; + break; + } default: condMeets = false; break; @@ -397,20 +399,20 @@ namespace Game.Conditions GridMapTypeMask mask = 0; switch (ConditionType) { - case ConditionTypes.DistanceTo: - case ConditionTypes.WorldState: - case ConditionTypes.PhaseId: - case ConditionTypes.Spawnmask: - case ConditionTypes.NearCreature: - case ConditionTypes.NearGameobject: case ConditionTypes.ActiveEvent: + case ConditionTypes.Areaid: + case ConditionTypes.DifficultyId: + case ConditionTypes.DistanceTo: case ConditionTypes.InstanceInfo: case ConditionTypes.Mapid: - case ConditionTypes.Areaid: + case ConditionTypes.NearCreature: + case ConditionTypes.NearGameobject: case ConditionTypes.None: - case ConditionTypes.Zoneid: - case ConditionTypes.TerrainSwap: + case ConditionTypes.PhaseId: case ConditionTypes.RealmAchievement: + case ConditionTypes.TerrainSwap: + case ConditionTypes.WorldState: + case ConditionTypes.Zoneid: mask |= GridMapTypeMask.All; break; case ConditionTypes.Gender: diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index 3780d4983..9a5ec70c5 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -1491,15 +1491,10 @@ namespace Game } break; } - case ConditionTypes.Spawnmask: + case ConditionTypes.SpawnmaskDeprecated: { - // @todo: ConditionValue need to be extended to uint64 - if ((ulong)cond.ConditionValue1 > 1ul << (int)SpawnMask.RaidAll) - { - Log.outError(LogFilter.Sql, "{0} has non existing SpawnMask in value1 ({1}), skipped.", cond.ToString(true), cond.ConditionValue1); - return false; - } - break; + Log.outError(LogFilter.Sql, $"{cond.ToString(true)} using deprecated condition type CONDITION_SPAWNMASK."); + return false; } case ConditionTypes.UnitState: { @@ -1576,6 +1571,13 @@ namespace Game case ConditionTypes.Charmed: case ConditionTypes.Taxi: break; + case ConditionTypes.DifficultyId: + if (!CliDB.DifficultyStorage.ContainsKey(cond.ConditionValue1)) + { + Log.outError(LogFilter.Sql, $"{cond.ToString(true)} has non existing difficulty in value1 ({cond.ConditionValue1}), skipped."); + return false; + } + break; default: Log.outError(LogFilter.Sql, $"{cond.ToString()} Invalid ConditionType in `condition` table, ignoring."); return false; diff --git a/Source/Game/Entities/Creature/Creature.cs b/Source/Game/Entities/Creature/Creature.cs index d808c1f3e..47ad53304 100644 --- a/Source/Game/Entities/Creature/Creature.cs +++ b/Source/Game/Entities/Creature/Creature.cs @@ -158,7 +158,7 @@ namespace Game.Entities // get difficulty 1 mode entry CreatureTemplate cinfo = null; - DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(GetMap().GetSpawnMode()); + DifficultyRecord difficultyEntry = CliDB.DifficultyStorage.LookupByKey(GetMap().GetDifficultyID()); while (cinfo == null && difficultyEntry != null) { int idx = CreatureTemplate.DifficultyIDToDifficultyEntryIndex(difficultyEntry.Id); @@ -992,10 +992,10 @@ namespace Game.Entities } uint mapId = GetTransport() ? (uint)GetTransport().GetGoInfo().MoTransport.SpawnMap : GetMapId(); - SaveToDB(mapId, data.spawnMask); + SaveToDB(mapId, data.spawnDifficulties); } - public virtual void SaveToDB(uint mapid, ulong spawnMask) + public virtual void SaveToDB(uint mapid, List spawnDifficulties) { // update in loaded data if (m_spawnId == 0) @@ -1052,7 +1052,7 @@ namespace Game.Entities // prevent add data integrity problems data.movementType = (byte)(m_respawnradius == 0 && GetDefaultMovementType() == MovementGeneratorType.Random ? MovementGeneratorType.Idle : GetDefaultMovementType()); - data.spawnMask = spawnMask; + data.spawnDifficulties = spawnDifficulties; data.npcflag = npcflag; data.unit_flags = unitFlags; data.unit_flags2 = unitFlags2; @@ -1075,7 +1075,7 @@ namespace Game.Entities stmt.AddValue(index++, m_spawnId); stmt.AddValue(index++, GetEntry()); stmt.AddValue(index++, mapid); - stmt.AddValue(index++, spawnMask); + stmt.AddValue(index++, string.Join(",", data.spawnDifficulties)); stmt.AddValue(index++, data.phaseId); stmt.AddValue(index++, data.phaseGroup); stmt.AddValue(index++, displayId); diff --git a/Source/Game/Entities/Creature/CreatureData.cs b/Source/Game/Entities/Creature/CreatureData.cs index f581b2f21..bac1e4fc0 100644 --- a/Source/Game/Entities/Creature/CreatureData.cs +++ b/Source/Game/Entities/Creature/CreatureData.cs @@ -291,7 +291,7 @@ namespace Game.Entities public uint curhealth; public uint curmana; public byte movementType; - public ulong spawnMask; + public List spawnDifficulties = new List(); public ulong npcflag; public uint unit_flags; // enum UnitFlags mask values public uint unit_flags2; // enum UnitFlags2 mask values diff --git a/Source/Game/Entities/GameObject/GameObject.cs b/Source/Game/Entities/GameObject/GameObject.cs index 5c55b6272..36dac5204 100644 --- a/Source/Game/Entities/GameObject/GameObject.cs +++ b/Source/Game/Entities/GameObject/GameObject.cs @@ -875,10 +875,10 @@ namespace Game.Entities return; } - SaveToDB(GetMapId(), data.spawnMask); + SaveToDB(GetMapId(), data.spawnDifficulties); } - public void SaveToDB(uint mapid, ulong spawnMask) + public void SaveToDB(uint mapid, List spawnDifficulties) { GameObjectTemplate goI = GetGoInfo(); @@ -902,7 +902,7 @@ namespace Game.Entities data.spawntimesecs = (int)(m_spawnedByDefault ? m_respawnDelayTime : -m_respawnDelayTime); data.animprogress = GetGoAnimProgress(); data.go_state = GetGoState(); - data.spawnMask = spawnMask; + data.spawnDifficulties = spawnDifficulties; data.artKit = GetGoArtKit(); Global.ObjectMgr.NewGOData(m_spawnId, data); @@ -919,7 +919,7 @@ namespace Game.Entities stmt.AddValue(index++, m_spawnId); stmt.AddValue(index++, GetEntry()); stmt.AddValue(index++, mapid); - stmt.AddValue(index++, spawnMask); + stmt.AddValue(index++, string.Join(",", data.spawnDifficulties)); stmt.AddValue(index++, data.phaseId); stmt.AddValue(index++, data.phaseGroup); stmt.AddValue(index++, GetPositionX()); diff --git a/Source/Game/Entities/GameObject/GameObjectData.cs b/Source/Game/Entities/GameObject/GameObjectData.cs index 424b8d1f7..2317f032b 100644 --- a/Source/Game/Entities/GameObject/GameObjectData.cs +++ b/Source/Game/Entities/GameObject/GameObjectData.cs @@ -18,6 +18,7 @@ using Framework.Collections; using Framework.Constants; using Framework.GameMath; +using System.Collections.Generic; using System.Runtime.InteropServices; namespace Game.Entities @@ -1087,7 +1088,7 @@ namespace Game.Entities public int spawntimesecs; public uint animprogress; public GameObjectState go_state; - public ulong spawnMask; + public List spawnDifficulties = new List(); public byte artKit; public PhaseUseFlagsValues phaseUseFlags; public uint phaseId; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 122596152..e221ff569 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -1010,8 +1010,7 @@ namespace Game.Entities } void _LoadBoundInstances(SQLResult result) { - for (byte i = 0; i < (int)Difficulty.Max; ++i) - m_boundInstances[i].Clear(); + m_boundInstances.Clear(); Group group = GetGroup(); diff --git a/Source/Game/Entities/Player/Player.Fields.cs b/Source/Game/Entities/Player/Player.Fields.cs index 6834742cb..084148297 100644 --- a/Source/Game/Entities/Player/Player.Fields.cs +++ b/Source/Game/Entities/Player/Player.Fields.cs @@ -75,7 +75,7 @@ namespace Game.Entities bool m_bPassOnGroupLoot; GroupUpdateCounter[] m_groupUpdateSequences = new GroupUpdateCounter[2]; - public Dictionary[] m_boundInstances = new Dictionary[(int)Difficulty.Max]; + public Dictionary> m_boundInstances = new Dictionary>(); Dictionary _instanceResetTimes = new Dictionary(); uint _pendingBindId; uint _pendingBindTimer; diff --git a/Source/Game/Entities/Player/Player.Map.cs b/Source/Game/Entities/Player/Player.Map.cs index a5db581fb..9bdad59b7 100644 --- a/Source/Game/Entities/Player/Player.Map.cs +++ b/Source/Game/Entities/Player/Player.Map.cs @@ -24,7 +24,6 @@ using Game.Maps; using Game.Network.Packets; using System; using System.Collections.Generic; -using System.Linq; namespace Game.Entities { @@ -236,14 +235,18 @@ namespace Game.Entities if (mapDiff == null) return null; - var bind = m_boundInstances[(int)difficulty].LookupByKey(mapid); - if (bind != null) - if (bind.extendState != 0 || withExpired) - return bind; + var difficultyDic = m_boundInstances.LookupByKey(difficulty); + if (difficultyDic == null) + return null; + + var instanceBind = difficultyDic.LookupByKey(mapid); + if (instanceBind != null) + if (instanceBind.extendState != 0 || withExpired) + return instanceBind; return null; } - public Dictionary GetBoundInstances(Difficulty difficulty) { return m_boundInstances[(int)difficulty]; } + public Dictionary GetBoundInstances(Difficulty difficulty) { return m_boundInstances.LookupByKey(difficulty); } public InstanceSave GetInstanceSave(uint mapid) { @@ -266,28 +269,16 @@ namespace Game.Entities public void UnbindInstance(uint mapid, Difficulty difficulty, bool unload = false) { - var bound = m_boundInstances[(int)difficulty].LookupByKey(mapid); - if (bound != null) + var difficultyDic = m_boundInstances.LookupByKey(difficulty); + if (difficultyDic != null) { - if (!unload) - { - PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CHAR_INSTANCE_BY_INSTANCE_GUID); - - stmt.AddValue(0, GetGUID().GetCounter()); - stmt.AddValue(1, bound.save.GetInstanceId()); - - DB.Characters.Execute(stmt); - } - - if (bound.perm) - GetSession().SendCalendarRaidLockout(bound.save, false); - - bound.save.RemovePlayer(this); // save can become invalid - m_boundInstances[(int)difficulty].Remove(mapid); + var pair = difficultyDic.Find(mapid); + if (pair.Value != null) + UnbindInstance(pair, difficultyDic, unload); } } - public void UnbindInstance(KeyValuePair pair, Difficulty difficulty, bool unload) + public void UnbindInstance(KeyValuePair pair, Dictionary difficultyDic, bool unload) { if (pair.Value != null) { @@ -305,7 +296,7 @@ namespace Game.Entities GetSession().SendCalendarRaidLockout(pair.Value.save, false); pair.Value.save.RemovePlayer(this); // save can become invalid - m_boundInstances[(int)difficulty].Remove(pair.Key); + difficultyDic.Remove(pair.Key); } } @@ -314,8 +305,8 @@ namespace Game.Entities if (save != null) { InstanceBind bind = new InstanceBind(); - if (m_boundInstances[(int)save.GetDifficultyID()].ContainsKey(save.GetMapId())) - bind = m_boundInstances[(int)save.GetDifficultyID()][save.GetMapId()]; + if (m_boundInstances[save.GetDifficultyID()].ContainsKey(save.GetMapId())) + bind = m_boundInstances[save.GetDifficultyID()][save.GetMapId()]; if (extendState == BindExtensionState.Keep) // special flag, keep the player's current extend state when updating for new boss down { @@ -373,7 +364,7 @@ namespace Game.Entities Global.ScriptMgr.OnPlayerBindToInstance(this, save.GetDifficultyID(), save.GetMapId(), permanent, extendState); - m_boundInstances[(int)save.GetDifficultyID()][save.GetMapId()] = bind; + m_boundInstances[save.GetDifficultyID()][save.GetMapId()] = bind; return bind; } @@ -407,21 +398,19 @@ namespace Game.Entities InstanceInfoPkt instanceInfo = new InstanceInfoPkt(); long now = Time.UnixTime; - for (byte i = 0; i < (int)Difficulty.Max; ++i) + foreach (var difficultyDic in m_boundInstances.Values) { - foreach (var pair in m_boundInstances[i]) + foreach (var instanceBind in difficultyDic.Values) { - InstanceBind bind = pair.Value; - if (bind.perm) + if (instanceBind.perm) { - InstanceSave save = pair.Value.save; + InstanceSave save = instanceBind.save; InstanceLockInfos lockInfos; - lockInfos.InstanceID = save.GetInstanceId(); lockInfos.MapID = save.GetMapId(); lockInfos.DifficultyID = (uint)save.GetDifficultyID(); - if (bind.extendState != BindExtensionState.Extended) + if (instanceBind.extendState != BindExtensionState.Extended) lockInfos.TimeRemaining = (int)(save.GetResetTime() - now); else lockInfos.TimeRemaining = (int)(Global.InstanceSaveMgr.GetSubsequentResetTime(save.GetMapId(), save.GetDifficultyID(), save.GetResetTime()) - now); @@ -435,8 +424,8 @@ namespace Game.Entities lockInfos.CompletedMask = instanceScript.GetCompletedEncounterMask(); } - lockInfos.Locked = bind.extendState != BindExtensionState.Expired; - lockInfos.Extended = bind.extendState == BindExtensionState.Extended; + lockInfos.Locked = instanceBind.extendState != BindExtensionState.Expired; + lockInfos.Extended = instanceBind.extendState == BindExtensionState.Extended; instanceInfo.LockList.Add(lockInfos); } @@ -617,26 +606,30 @@ namespace Game.Entities // method can be INSTANCE_RESET_ALL, INSTANCE_RESET_CHANGE_DIFFICULTY, INSTANCE_RESET_GROUP_JOIN // we assume that when the difficulty changes, all instances that can be reset will be - Difficulty diff = GetDungeonDifficultyID(); + Difficulty difficulty = GetDungeonDifficultyID(); if (isRaid) { if (!isLegacy) - diff = GetRaidDifficultyID(); + difficulty = GetRaidDifficultyID(); else - diff = GetLegacyRaidDifficultyID(); + difficulty = GetLegacyRaidDifficultyID(); } - foreach (var pair in m_boundInstances[(int)diff].ToList()) + var difficultyDic = m_boundInstances.LookupByKey(difficulty); + if (difficultyDic == null) + return; + + foreach (var pair in difficultyDic) { InstanceSave p = pair.Value.save; - MapRecord entry = CliDB.MapStorage.LookupByKey(pair.Key); + MapRecord entry = CliDB.MapStorage.LookupByKey(difficulty); if (entry == null || entry.IsRaid() != isRaid || !p.CanReset()) continue; if (method == InstanceResetMethod.All) { // the "reset all instances" method can only reset normal maps - if (entry.InstanceType == MapTypes.Raid || diff == Difficulty.Heroic) + if (entry.InstanceType == MapTypes.Raid || difficulty == Difficulty.Heroic) continue; } @@ -651,7 +644,7 @@ namespace Game.Entities SendResetInstanceSuccess(p.GetMapId()); p.DeleteFromDB(); - m_boundInstances[(int)diff].Remove(pair.Key); + difficultyDic.Remove(pair.Key); // the following should remove the instance save from the manager and delete it as well p.RemovePlayer(this); diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index f16eb7e20..182142012 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -71,9 +71,6 @@ namespace Game.Entities m_logintime = Time.UnixTime; m_Last_tick = m_logintime; - for (byte i = 0; i < (int)Difficulty.Max; ++i) - m_boundInstances[i] = new Dictionary(); - m_dungeonDifficulty = Difficulty.Normal; m_raidDifficulty = Difficulty.NormalRaid; m_legacyRaidDifficulty = Difficulty.Raid10N; @@ -839,9 +836,9 @@ namespace Game.Entities GetTransport().RemovePassenger(this); // clean up player-instance binds, may unload some instance saves - for (byte i = 0; i < (int)Difficulty.Max; ++i) - foreach (var bound in m_boundInstances[i]) - bound.Value.save.RemovePlayer(this); + foreach (var difficultyDic in m_boundInstances.Values) + foreach (var instanceBind in difficultyDic.Values) + instanceBind.save.RemovePlayer(this); } public override void AddToWorld() diff --git a/Source/Game/Entities/TemporarySummon.cs b/Source/Game/Entities/TemporarySummon.cs index f408581a5..add2c9c42 100644 --- a/Source/Game/Entities/TemporarySummon.cs +++ b/Source/Game/Entities/TemporarySummon.cs @@ -288,7 +288,7 @@ namespace Game.Entities base.RemoveFromWorld(); } - public override void SaveToDB(uint mapid, ulong spawnMask) { } + public override void SaveToDB(uint mapid, List spawnDifficulties) { } public ObjectGuid GetSummonerGUID() { return m_summonerGUID; } diff --git a/Source/Game/Entities/Transport.cs b/Source/Game/Entities/Transport.cs index 0c82c69a0..0762636cc 100644 --- a/Source/Game/Entities/Transport.cs +++ b/Source/Game/Entities/Transport.cs @@ -536,7 +536,7 @@ namespace Game.Entities void LoadStaticPassengers() { uint mapId = (uint)GetGoInfo().MoTransport.SpawnMap; - var cells = Global.ObjectMgr.GetMapObjectGuids(mapId, (byte)GetMap().GetSpawnMode()); + var cells = Global.ObjectMgr.GetMapObjectGuids(mapId, (byte)GetMap().GetDifficultyID()); if (cells == null) return; foreach (var cell in cells) diff --git a/Source/Game/Garrisons/Garrisons.cs b/Source/Game/Garrisons/Garrisons.cs index 4c1736fed..87bf0fc01 100644 --- a/Source/Game/Garrisons/Garrisons.cs +++ b/Source/Game/Garrisons/Garrisons.cs @@ -735,7 +735,7 @@ namespace Game.Garrisons if (go.GetGoType() == GameObjectTypes.GarrisonBuilding && go.GetGoInfo().garrisonBuilding.SpawnMap != 0) { - foreach (var cellGuids in Global.ObjectMgr.GetMapObjectGuids((uint)go.GetGoInfo().garrisonBuilding.SpawnMap, (byte)map.GetSpawnMode())) + foreach (var cellGuids in Global.ObjectMgr.GetMapObjectGuids((uint)go.GetGoInfo().garrisonBuilding.SpawnMap, (byte)map.GetDifficultyID())) { foreach (var spawnId in cellGuids.Value.creatures) { diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index 60d29dc80..c540fe9ea 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -2772,7 +2772,8 @@ namespace Game break; } - if (!Convert.ToBoolean(master.spawnMask & slave.spawnMask)) // they must have a possibility to meet (normal/heroic difficulty) + // they must have a possibility to meet (normal/heroic difficulty) + if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any()) { Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow); error = true; @@ -2809,7 +2810,8 @@ namespace Game break; } - if (!Convert.ToBoolean(master.spawnMask & slave.spawnMask)) // they must have a possibility to meet (normal/heroic difficulty) + // they must have a possibility to meet (normal/heroic difficulty) + if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any()) { Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow); error = true; @@ -2846,7 +2848,8 @@ namespace Game break; } - if (!Convert.ToBoolean(master.spawnMask & slave.spawnMask)) // they must have a possibility to meet (normal/heroic difficulty) + // they must have a possibility to meet (normal/heroic difficulty) + if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any()) { Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow); error = true; @@ -2883,7 +2886,8 @@ namespace Game break; } - if (!Convert.ToBoolean(master.spawnMask & slave.spawnMask)) // they must have a possibility to meet (normal/heroic difficulty) + // they must have a possibility to meet (normal/heroic difficulty) + if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any()) { Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow); error = true; @@ -3227,9 +3231,9 @@ namespace Game // 0 1 2 3 4 5 6 7 8 9 10 SQLResult result = DB.World.Query("SELECT creature.guid, id, map, modelid, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, spawndist, " + - // 11 12 13 14 15 16 17 18 19 20 21 - "currentwaypoint, curhealth, curmana, MovementType, spawnMask, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.unit_flags2, creature.unit_flags3, " + - // 22 23 24 25 26 27 + //11 12 13 14 15 16 17 18 19 20 21 + "currentwaypoint, curhealth, curmana, MovementType, spawnDifficulties, eventEntry, pool_entry, creature.npcflag, creature.unit_flags, creature.unit_flags2, creature.unit_flags3, " + + //22 23 24 25 26 27 "creature.dynamicflags, creature.phaseUseFlags, creature.phaseid, creature.phasegroup, creature.terrainSwapMap, creature.ScriptName " + "FROM creature LEFT OUTER JOIN game_event_creature ON creature.guid = game_event_creature.guid LEFT OUTER JOIN pool_creature ON creature.guid = pool_creature.guid"); @@ -3239,15 +3243,16 @@ namespace Game return; } - Dictionary spawnMasks = new Dictionary(); + // Build single time for check spawnmask + Dictionary> spawnMasks = new Dictionary>(); foreach (var mapDifficultyPair in Global.DB2Mgr.GetMapDifficulties()) { foreach (var difficultyPair in mapDifficultyPair.Value) { if (!spawnMasks.ContainsKey(mapDifficultyPair.Key)) - spawnMasks[mapDifficultyPair.Key] = 0; + spawnMasks[mapDifficultyPair.Key] = new List(); - spawnMasks[mapDifficultyPair.Key] |= (1ul << (int)difficultyPair.Key); + spawnMasks[mapDifficultyPair.Key].Add((Difficulty)difficultyPair.Key); } } @@ -3281,7 +3286,7 @@ namespace Game data.curhealth = result.Read(12); data.curmana = result.Read(13); data.movementType = result.Read(14); - data.spawnMask = result.Read(15); + data.spawnDifficulties = ParseSpawnDifficulties(result.Read(15), "creature", guid, data.mapid, spawnMasks[data.mapid]); short gameEvent = result.Read(16); uint PoolId = result.Read(17); data.npcflag = result.Read(18); @@ -3304,8 +3309,11 @@ namespace Game continue; } - //if (!_transportMaps.Contains(data.mapid) && (spawnMasks.ContainsKey(data.mapid) && Convert.ToBoolean(data.spawnMask & ~spawnMasks[data.mapid]))) - //Log.outError(LogFilter.Sql, "Table `creature` have creature (GUID: {0}) that have wrong spawn mask {1} including not supported difficulty modes for map (Id: {2}) spawnMasks[data.mapid]: {3}.", guid, data.spawnMask, data.mapid, spawnMasks[data.mapid]); + if (data.spawnDifficulties.Empty()) + { + Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid}) that is not spawned in any difficulty, skipped."); + continue; + } bool ok = true; for (uint diff = 0; diff < SharedConst.MaxCreatureDifficulties && ok; ++diff) @@ -3444,31 +3452,23 @@ namespace Game public void AddCreatureToGrid(ulong guid, CreatureData data) { - ulong mask = data.spawnMask; - for (byte i = 0; mask != 0; i++, mask >>= 1) + foreach (Difficulty difficulty in data.spawnDifficulties) { - if (Convert.ToBoolean(mask & 1)) - { - CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); - var cellguids = CreateCellObjectGuids(data.mapid, i, cellCoord); - cellguids.creatures.Add(guid); - } + CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); + var cellguids = CreateCellObjectGuids(data.mapid, difficulty, cellCoord.GetId()); + cellguids.creatures.Add(guid); } } public void RemoveCreatureFromGrid(ulong guid, CreatureData data) { - ulong mask = data.spawnMask; - for (byte i = 0; mask != 0; i++, mask >>= 1) + foreach (Difficulty difficulty in data.spawnDifficulties) { - if (Convert.ToBoolean(mask & 1)) - { - CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); - CellObjectGuids cellguids = GetCellObjectGuids(data.mapid, i, cellCoord.GetId()); - if (cellguids == null) - return; + CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); + CellObjectGuids cellguids = GetCellObjectGuids(data.mapid, difficulty, cellCoord.GetId()); + if (cellguids == null) + return; - cellguids.creatures.Remove(guid); - } + cellguids.creatures.Remove(guid); } } public ulong AddCreatureData(uint entry, uint team, uint mapId, float x, float y, float z, float o, uint spawntimedelay) @@ -3499,7 +3499,7 @@ namespace Game data.curhealth = stats.GenerateHealth(cInfo); data.curmana = stats.GenerateMana(cInfo); data.movementType = (byte)cInfo.MovementType; - data.spawnMask = (int)SpawnMask.Continent; + data.spawnDifficulties.Add(Difficulty.None); data.dbData = false; data.npcflag = (uint)cInfo.Npcflag; data.unit_flags = (uint)cInfo.UnitFlags; @@ -3587,7 +3587,8 @@ namespace Game return false; } - if (!Convert.ToBoolean(master.spawnMask & slave.spawnMask)) // they must have a possibility to meet (normal/heroic difficulty) + // they must have a possibility to meet (normal/heroic difficulty) + if (!master.spawnDifficulties.Intersect(slave.spawnDifficulties).Any()) { Log.outError(LogFilter.Sql, "LinkedRespawn: Creature '{0}' linking to '{1}' with not corresponding spawnMask", guidLow, linkedGuidLow); return false; @@ -3923,11 +3924,11 @@ namespace Game public void LoadGameobjects() { var time = Time.GetMSTime(); - // 0 1 2 3 4 5 6 + // 0 1 2 3 4 5 6 SQLResult result = DB.World.Query("SELECT gameobject.guid, id, map, position_x, position_y, position_z, orientation, " + - // 7 8 9 10 11 12 13 14 15 16 - "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnMask, eventEntry, pool_entry, " + - // 17 18 19 20 21 + //7 8 9 10 11 12 13 14 15 16 + "rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state, spawnDifficulties, eventEntry, pool_entry, " + + //17 18 19 20 21 "phaseUseFlags, phaseid, phasegroup, terrainSwapMap, ScriptName " + "FROM gameobject LEFT OUTER JOIN game_event_gameobject ON gameobject.guid = game_event_gameobject.guid " + "LEFT OUTER JOIN pool_gameobject ON gameobject.guid = pool_gameobject.guid"); @@ -3941,14 +3942,15 @@ namespace Game uint count = 0; // build single time for check spawnmask - Dictionary spawnMasks = new Dictionary(); + Dictionary> spawnMasks = new Dictionary>(); foreach (var mapDifficultyPair in Global.DB2Mgr.GetMapDifficulties()) { foreach (var difficultyPair in mapDifficultyPair.Value) { if (!spawnMasks.ContainsKey(mapDifficultyPair.Key)) - spawnMasks[mapDifficultyPair.Key] = 0; - spawnMasks[mapDifficultyPair.Key] |= (1ul << (int)difficultyPair.Key); + spawnMasks[mapDifficultyPair.Key] = new List(); + + spawnMasks[mapDifficultyPair.Key].Add((Difficulty)difficultyPair.Key); } } @@ -4024,11 +4026,12 @@ namespace Game } data.go_state = (GameObjectState)gostate; - data.spawnMask = result.Read(14); - - //if (!_transportMaps.Contains(data.mapid) && (spawnMasks.ContainsKey(data.mapid) && Convert.ToBoolean(data.spawnMask & ~spawnMasks[data.mapid]))) - //Log.outError(LogFilter.Sql, "Table `gameobject` has gameobject (GUID: {0} Entry: {1}) that has wrong spawn mask {2} including not supported difficulty modes for map (Id: {3}), skip", - //guid, data.id, data.spawnMask, data.mapid); + data.spawnDifficulties = ParseSpawnDifficulties(result.Read(14), "gameobject", guid, data.mapid, spawnMasks[data.mapid]); + if (data.spawnDifficulties.Empty()) + { + Log.outError(LogFilter.Sql, $"Table `creature` has creature (GUID: {guid}) that is not spawned in any difficulty, skipped."); + continue; + } short gameEvent = result.Read(15); uint PoolId = result.Read(16); @@ -4319,31 +4322,23 @@ namespace Game } public void AddGameObjectToGrid(ulong guid, GameObjectData data) { - ulong mask = data.spawnMask; - for (byte i = 0; mask != 0; i++, mask >>= 1) + foreach (Difficulty difficulty in data.spawnDifficulties) { - if (Convert.ToBoolean(mask & 1)) - { - CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); - var cellguids = CreateCellObjectGuids(data.mapid, i, cellCoord); - cellguids.gameobjects.Add(guid); - } + CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); + var cellguids = CreateCellObjectGuids(data.mapid, difficulty, cellCoord.GetId()); + cellguids.gameobjects.Add(guid); } } public void RemoveGameObjectFromGrid(ulong guid, GameObjectData data) { - ulong mask = data.spawnMask; - for (byte i = 0; mask != 0; i++, mask >>= 1) + foreach (Difficulty difficulty in data.spawnDifficulties) { - if (Convert.ToBoolean(mask & 1)) - { - CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); - CellObjectGuids cellguids = GetCellObjectGuids(data.mapid, i, cellCoord.GetId()); - if (cellguids == null) - return; + CellCoord cellCoord = GridDefines.ComputeCellCoord(data.posX, data.posY); + CellObjectGuids cellguids = GetCellObjectGuids(data.mapid, difficulty, cellCoord.GetId()); + if (cellguids == null) + return; - cellguids.gameobjects.Remove(guid); - } + cellguids.gameobjects.Remove(guid); } } public ulong AddGOData(uint entry, uint mapId, float x, float y, float z, float o, uint spawntimedelay, float rotation0, float rotation1, float rotation2, float rotation3) @@ -4370,7 +4365,7 @@ namespace Game data.rotation.W = rotation3; data.spawntimesecs = (int)spawntimedelay; data.animprogress = 100; - data.spawnMask = (int)SpawnMask.Continent; + data.spawnDifficulties.Add(Difficulty.None); data.go_state = GameObjectState.Ready; data.artKit = (byte)(goinfo.type == GameObjectTypes.ControlZone ? 21 : 0); data.dbData = false; @@ -4487,6 +4482,33 @@ namespace Game goInfo.entry, goInfo.type, N, dataN); } + List ParseSpawnDifficulties(string difficultyString, string table, ulong spawnId, uint mapId, List mapDifficulties) + { + StringArray tokens = new StringArray(difficultyString, ','); + List difficulties = new List(); + bool isTransportMap = IsTransportMap(mapId); + foreach (string token in tokens) + { + Difficulty difficultyId = (Difficulty)Enum.Parse(typeof(Difficulty), token); + if (difficultyId != 0 && !CliDB.DifficultyStorage.ContainsKey(difficultyId)) + { + Log.outError(LogFilter.Sql, $"Table `{table}` has {table} (GUID: {spawnId}) with non invalid difficulty id {difficultyId}, skipped."); + continue; + } + + if (!isTransportMap && !mapDifficulties.Contains(difficultyId)) + { + Log.outError(LogFilter.Sql, "Table `{table}` has {table} (GUID: {spawnId}) has unsupported difficulty {difficultyId} for map (Id: {mapId})."); + continue; + } + + difficulties.Add(difficultyId); + } + + difficulties.Sort(); + return difficulties; + } + //Items public void LoadItemTemplates() { @@ -9311,13 +9333,9 @@ namespace Game } return 0; } - public CellObjectGuids CreateCellObjectGuids(uint mapid, byte spawnMask, CellCoord cellCoord) + CellObjectGuids CreateCellObjectGuids(uint mapid, Difficulty difficulty, uint cellid) { - return CreateCellObjectGuids(mapid, spawnMask, cellCoord.GetId()); - } - CellObjectGuids CreateCellObjectGuids(uint mapid, byte spawnMask, uint cellid) - { - uint newid = MathFunctions.MakePair32(mapid, spawnMask); + uint newid = MathFunctions.MakePair32(mapid, (uint)difficulty); if (!mapObjectGuidsStore.ContainsKey(newid)) mapObjectGuidsStore.Add(newid, new Dictionary()); @@ -9327,9 +9345,9 @@ namespace Game return mapObjectGuidsStore[newid][cellid]; } - public CellObjectGuids GetCellObjectGuids(uint mapid, byte spawnMask, uint cellid) + public CellObjectGuids GetCellObjectGuids(uint mapid, Difficulty difficulty, uint cellid) { - uint newid = MathFunctions.MakePair32(mapid, spawnMask); + uint newid = MathFunctions.MakePair32(mapid, (uint)difficulty); if (mapObjectGuidsStore.ContainsKey(newid) && mapObjectGuidsStore[newid].ContainsKey(cellid)) return mapObjectGuidsStore[newid][cellid]; diff --git a/Source/Game/Groups/Group.cs b/Source/Game/Groups/Group.cs index 3ab6d9a0f..ed7f1ea82 100644 --- a/Source/Game/Groups/Group.cs +++ b/Source/Game/Groups/Group.cs @@ -42,9 +42,6 @@ namespace Game.Groups m_legacyRaidDifficulty = Difficulty.Raid10N; m_lootMethod = LootMethod.FreeForAll; m_lootThreshold = ItemQuality.Uncommon; - - for (byte i = 0; i < (int)Difficulty.Max; ++i) - m_boundInstances[i] = new Dictionary(); } public bool Create(Player leader) @@ -645,9 +642,9 @@ namespace Game.Groups SQLTransaction trans = new SQLTransaction(); // Remove the groups permanent instance bindings - for (byte i = 0; i < (int)Difficulty.Max; ++i) + foreach (var difficultyDic in m_boundInstances.Values) { - foreach (var pair in m_boundInstances[i]) + foreach (var pair in difficultyDic) { // Do not unbind saves of instances that already had map created (a newLeader entered) // forcing a new instance with another leader requires group disbanding (confirmed on retail) @@ -659,7 +656,7 @@ namespace Game.Groups trans.Append(stmt); pair.Value.save.RemoveGroup(this); - m_boundInstances[i].Remove(pair.Key); + difficultyDic.Remove(pair.Key); } } } @@ -692,9 +689,9 @@ namespace Game.Groups { // copy all binds to the group, when changing leader it's assumed the character // will not have any solo binds - for (byte i = 0; i < (int)Difficulty.Max; ++i) + foreach (var difficultyDic in player.m_boundInstances.Values) { - foreach (var pair in player.m_boundInstances[i]) + foreach (var pair in difficultyDic) { if (!switchLeader || group.GetBoundInstance(pair.Value.save.GetDifficultyID(), pair.Key) == null) if (pair.Value.extendState != 0) // not expired @@ -703,7 +700,7 @@ namespace Game.Groups // permanent binds are not removed if (switchLeader && !pair.Value.perm) { - player.UnbindInstance(pair, (Difficulty)i, false); + player.UnbindInstance(pair, difficultyDic, false); } } } @@ -1871,7 +1868,11 @@ namespace Game.Groups diff = GetLegacyRaidDifficultyID(); } - foreach (var pair in m_boundInstances[(int)diff].ToList()) + var difficultyDic = m_boundInstances.LookupByKey(diff); + if (difficultyDic == null) + return; + + foreach (var pair in difficultyDic) { InstanceSave instanceSave = pair.Value.save; MapRecord entry = CliDB.MapStorage.LookupByKey(pair.Key); @@ -1933,8 +1934,7 @@ namespace Game.Groups } - // i don't know for sure if hash_map iterators - m_boundInstances[(int)diff].Remove(pair.Key); + difficultyDic.Remove(pair.Key); // this unloads the instance save unless online players are bound to it // (eg. permanent binds or GM solo binds) instanceSave.RemoveGroup(this); @@ -1968,7 +1968,15 @@ namespace Game.Groups // some instances only have one difficulty Global.DB2Mgr.GetDownscaledMapDifficultyData(mapId, ref difficulty); - return m_boundInstances[(int)difficulty].LookupByKey(mapId); + var difficultyDic = m_boundInstances.LookupByKey(difficulty); + if (difficultyDic == null) + return null; + + var instanceBind = difficultyDic.LookupByKey(mapId); + if (instanceBind != null) + return instanceBind; + + return null; } public InstanceBind BindToInstance(InstanceSave save, bool permanent, bool load = false) @@ -1976,10 +1984,10 @@ namespace Game.Groups if (save == null || isBGGroup() || isBFGroup()) return null; - if (!m_boundInstances[(int)save.GetDifficultyID()].ContainsKey(save.GetMapId())) - m_boundInstances[(int)save.GetDifficultyID()][save.GetMapId()] = new InstanceBind(); + if (!m_boundInstances[save.GetDifficultyID()].ContainsKey(save.GetMapId())) + m_boundInstances[save.GetDifficultyID()][save.GetMapId()] = new InstanceBind(); - InstanceBind bind = m_boundInstances[(int)save.GetDifficultyID()][save.GetMapId()]; + InstanceBind bind = m_boundInstances[save.GetDifficultyID()][save.GetMapId()]; if (!load && (bind.save == null || permanent != bind.perm || save != bind.save)) { PreparedStatement stmt = DB.Characters.GetPreparedStatement(CharStatements.REP_GROUP_INSTANCE); @@ -2004,14 +2012,18 @@ namespace Game.Groups Log.outDebug(LogFilter.Maps, "Group.BindToInstance: Group ({0}, storage id: {1}) is now bound to map {2}, instance {3}, difficulty {4}", GetGUID().ToString(), m_dbStoreId, save.GetMapId(), save.GetInstanceId(), save.GetDifficultyID()); - m_boundInstances[(int)save.GetDifficultyID()][save.GetMapId()] = bind; + m_boundInstances[save.GetDifficultyID()][save.GetMapId()] = bind; return bind; } public void UnbindInstance(uint mapid, Difficulty difficulty, bool unload = false) { - var instanceBind = m_boundInstances[(int)difficulty].LookupByKey(mapid); + var difficultyDic = m_boundInstances.LookupByKey(difficulty); + if (difficultyDic == null) + return; + + var instanceBind = difficultyDic.LookupByKey(mapid); if (instanceBind != null) { if (!unload) @@ -2025,7 +2037,7 @@ namespace Game.Groups } instanceBind.save.RemoveGroup(this); // save can become invalid - m_boundInstances[(int)difficulty].Remove(mapid); + difficultyDic.Remove(mapid); } } @@ -2465,7 +2477,7 @@ namespace Game.Groups public Dictionary GetBoundInstances(Difficulty difficulty) { - return m_boundInstances[(int)difficulty]; + return m_boundInstances.LookupByKey(difficulty); } void _initRaidSubGroupsCounter() @@ -2560,7 +2572,7 @@ namespace Game.Groups ObjectGuid m_looterGuid; ObjectGuid m_masterLooterGuid; List RollId = new List(); - Dictionary[] m_boundInstances = new Dictionary[(int)Difficulty.Max]; + Dictionary> m_boundInstances = new Dictionary>(); byte[] m_subGroupsCounts; ObjectGuid m_guid; uint m_maxEnchantingLevel; diff --git a/Source/Game/Handlers/CalendarHandler.cs b/Source/Game/Handlers/CalendarHandler.cs index bbc50ab5c..7865323d2 100644 --- a/Source/Game/Handlers/CalendarHandler.cs +++ b/Source/Game/Handlers/CalendarHandler.cs @@ -71,22 +71,25 @@ namespace Game packet.Events.Add(eventInfo); } - for (byte i = 0; i < (int)Difficulty.Max; ++i) + for (Difficulty i = 0; i < Difficulty.Max; ++i) { - var boundInstances = GetPlayer().GetBoundInstances((Difficulty)i); - foreach (var pair in boundInstances) + var boundInstances = _player.GetBoundInstances(i); + if (boundInstances != null) { - if (pair.Value.perm) + foreach (var boundInstance in boundInstances.Values) { - CalendarSendCalendarRaidLockoutInfo lockoutInfo; + if (boundInstance.perm) + { + CalendarSendCalendarRaidLockoutInfo lockoutInfo; - InstanceSave save = pair.Value.save; - lockoutInfo.MapID = (int)save.GetMapId(); - lockoutInfo.DifficultyID = (uint)save.GetDifficultyID(); - lockoutInfo.ExpireTime = save.GetResetTime() - currTime; - lockoutInfo.InstanceID = save.GetInstanceId(); // instance save id as unique instance copy id + InstanceSave save = boundInstance.save; + lockoutInfo.MapID = (int)save.GetMapId(); + lockoutInfo.DifficultyID = (uint)save.GetDifficultyID(); + lockoutInfo.ExpireTime = save.GetResetTime() - currTime; + lockoutInfo.InstanceID = save.GetInstanceId(); // instance save id as unique instance copy id - packet.RaidLockouts.Add(lockoutInfo); + packet.RaidLockouts.Add(lockoutInfo); + } } } } diff --git a/Source/Game/Maps/Map.cs b/Source/Game/Maps/Map.cs index c61637979..bfb9a599f 100644 --- a/Source/Game/Maps/Map.cs +++ b/Source/Game/Maps/Map.cs @@ -2980,16 +2980,11 @@ namespace Game.Maps return i_InstanceId; } - public Difficulty GetSpawnMode() - { - return i_spawnMode; - } - public virtual EnterState CannotEnter(Player player) { return EnterState.CanEnter; } public Difficulty GetDifficultyID() { - return GetSpawnMode(); + return i_spawnMode; } public MapDifficultyRecord GetMapDifficulty() @@ -4401,7 +4396,7 @@ namespace Game.Maps { if (player.GetMap() == this) { - Log.outError(LogFilter.Maps, "InstanceMap:CannotEnter - player {0} ({1}) already in map {2}, {3}, {4}!", player.GetName(), player.GetGUID().ToString(), GetId(), GetInstanceId(), GetSpawnMode()); + Log.outError(LogFilter.Maps, "InstanceMap:CannotEnter - player {0} ({1}) already in map {2}, {3}, {4}!", player.GetName(), player.GetGUID().ToString(), GetId(), GetInstanceId(), GetDifficultyID()); Cypher.Assert(false); return EnterState.CannotEnterAlreadyInMap; } @@ -4452,14 +4447,14 @@ namespace Game.Maps InstanceSave mapSave = Global.InstanceSaveMgr.GetInstanceSave(GetInstanceId()); if (mapSave == null) { - Log.outInfo(LogFilter.Maps, "InstanceMap.Add: creating instance save for map {0} spawnmode {1} with instance id {2}", GetId(), GetSpawnMode(), GetInstanceId()); - mapSave = Global.InstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), GetSpawnMode(), 0, 0, true); + Log.outInfo(LogFilter.Maps, "InstanceMap.Add: creating instance save for map {0} spawnmode {1} with instance id {2}", GetId(), GetDifficultyID(), GetInstanceId()); + mapSave = Global.InstanceSaveMgr.AddInstanceSave(GetId(), GetInstanceId(), GetDifficultyID(), 0, 0, true); } Cypher.Assert(mapSave != null); // check for existing instance binds - InstanceBind playerBind = player.GetBoundInstance(GetId(), GetSpawnMode()); + InstanceBind playerBind = player.GetBoundInstance(GetId(), GetDifficultyID()); if (playerBind != null && playerBind.perm) { // cannot enter other instances if bound permanently @@ -4780,11 +4775,11 @@ namespace Game.Maps InstanceSave save = Global.InstanceSaveMgr.GetInstanceSave(GetInstanceId()); if (save != null) Global.InstanceSaveMgr.ScheduleReset(on, save.GetResetTime(), - new InstanceSaveManager.InstResetEvent(0, GetId(), GetSpawnMode(), GetInstanceId())); + new InstanceSaveManager.InstResetEvent(0, GetId(), GetDifficultyID(), GetInstanceId())); else Log.outError(LogFilter.Maps, "InstanceMap.SetResetSchedule: cannot turn schedule {0}, there is no save information for instance (map [id: {1}, name: {2}], instance id: {3}, difficulty: {4})", - on ? "on" : "off", GetId(), GetMapName(), GetInstanceId(), GetSpawnMode()); + on ? "on" : "off", GetId(), GetMapName(), GetInstanceId(), GetDifficultyID()); } } diff --git a/Source/Game/Maps/ObjectGridLoader.cs b/Source/Game/Maps/ObjectGridLoader.cs index cd9e00063..4448a66c4 100644 --- a/Source/Game/Maps/ObjectGridLoader.cs +++ b/Source/Game/Maps/ObjectGridLoader.cs @@ -60,7 +60,7 @@ namespace Game.Maps public override void Visit(IList objs) { CellCoord cellCoord = i_cell.GetCellCoord(); - CellObjectGuids cellguids = Global.ObjectMgr.GetCellObjectGuids(i_map.GetId(), (byte)i_map.GetSpawnMode(), cellCoord.GetId()); + CellObjectGuids cellguids = Global.ObjectMgr.GetCellObjectGuids(i_map.GetId(), i_map.GetDifficultyID(), cellCoord.GetId()); if (cellguids == null) return; @@ -70,7 +70,7 @@ namespace Game.Maps public override void Visit(IList objs) { CellCoord cellCoord = i_cell.GetCellCoord(); - CellObjectGuids cellguids = Global.ObjectMgr.GetCellObjectGuids(i_map.GetId(), (byte)i_map.GetSpawnMode(), cellCoord.GetId()); + CellObjectGuids cellguids = Global.ObjectMgr.GetCellObjectGuids(i_map.GetId(), i_map.GetDifficultyID(), cellCoord.GetId()); if (cellguids == null) return; diff --git a/Source/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/TrialOfTheCrusader.cs b/Source/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/TrialOfTheCrusader.cs index 45bd27170..7b6ad7c4b 100644 --- a/Source/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/TrialOfTheCrusader.cs +++ b/Source/Scripts/Northrend/CrusadersColiseum/TrialOfTheCrusader/TrialOfTheCrusader.cs @@ -166,19 +166,19 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader switch (go.GetEntry()) { case GameObjectIds.CrusadersCache10: - if (instance.GetSpawnMode() == Difficulty.Raid10N) + if (instance.GetDifficultyID() == Difficulty.Raid10N) CrusadersCacheGUID = go.GetGUID(); break; case GameObjectIds.CrusadersCache25: - if (instance.GetSpawnMode() == Difficulty.Raid25N) + if (instance.GetDifficultyID() == Difficulty.Raid25N) CrusadersCacheGUID = go.GetGUID(); break; case GameObjectIds.CrusadersCache10H: - if (instance.GetSpawnMode() == Difficulty.Raid10HC) + if (instance.GetDifficultyID() == Difficulty.Raid10HC) CrusadersCacheGUID = go.GetGUID(); break; case GameObjectIds.CrusadersCache25H: - if (instance.GetSpawnMode() == Difficulty.Raid25HC) + if (instance.GetDifficultyID() == Difficulty.Raid25HC) CrusadersCacheGUID = go.GetGUID(); break; case GameObjectIds.ArgentColiseumFloor: @@ -298,7 +298,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader { EventStage = 6000; uint tributeChest = 0; - if (instance.GetSpawnMode() == Difficulty.Raid10HC) + if (instance.GetDifficultyID() == Difficulty.Raid10HC) { if (TrialCounter >= 50) tributeChest = GameObjectIds.TributeChest10h99; @@ -315,7 +315,7 @@ namespace Scripts.Northrend.CrusadersColiseum.TrialOfTheCrusader } } } - else if (instance.GetSpawnMode() == Difficulty.Raid25HC) + else if (instance.GetDifficultyID() == Difficulty.Raid25HC) { if (TrialCounter >= 50) tributeChest = GameObjectIds.TributeChest25h99; diff --git a/Source/Scripts/Northrend/IcecrownCitadel/InstanceIcecrownCitadel.cs b/Source/Scripts/Northrend/IcecrownCitadel/InstanceIcecrownCitadel.cs index 5d82240fe..5f5f778cf 100644 --- a/Source/Scripts/Northrend/IcecrownCitadel/InstanceIcecrownCitadel.cs +++ b/Source/Scripts/Northrend/IcecrownCitadel/InstanceIcecrownCitadel.cs @@ -362,7 +362,7 @@ namespace Scripts.Northrend.IcecrownCitadel { if (WeeklyQuestData[questIndex].creatureEntry == entry) { - byte diffIndex = (byte)((int)instance.GetSpawnMode() & 1); + byte diffIndex = (byte)((int)instance.GetDifficultyID() & 1); if (!Global.PoolMgr.IsSpawnedObject(WeeklyQuestData[questIndex].questId[diffIndex])) entry = 0; break; @@ -976,7 +976,7 @@ namespace Scripts.Northrend.IcecrownCitadel case Bosses.ValithriaDreamwalker: if (state == EncounterState.Done) { - if (Global.PoolMgr.IsSpawnedObject(WeeklyQuestData[8].questId[(int)instance.GetSpawnMode() & 1])) + if (Global.PoolMgr.IsSpawnedObject(WeeklyQuestData[8].questId[(int)instance.GetDifficultyID() & 1])) instance.SummonCreature(CreatureIds.ValithriaDreamwalkerQuest, ValithriaDreamwalker.ValithriaSpawnPos); GameObject teleporter = instance.GetGameObject(TeleporterSindragosaGUID); @@ -1106,7 +1106,7 @@ namespace Scripts.Northrend.IcecrownCitadel break; // 5 is the index of Blood Quickening - if (!Global.PoolMgr.IsSpawnedObject(WeeklyQuestData[5].questId[(int)instance.GetSpawnMode() & 1])) + if (!Global.PoolMgr.IsSpawnedObject(WeeklyQuestData[5].questId[(int)instance.GetDifficultyID() & 1])) break; switch ((EncounterState)data) diff --git a/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs b/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs index 48d12b498..3aee4a906 100644 --- a/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs +++ b/Source/Scripts/Northrend/IcecrownCitadel/LordMarrowgar.cs @@ -563,7 +563,7 @@ namespace Scripts.Northrend.IcecrownCitadel if (marrowgar) { CreatureAI marrowgarAI = marrowgar.GetAI(); - byte boneSpikeCount = (byte)(Convert.ToBoolean((int)GetCaster().GetMap().GetSpawnMode() & 1) ? 3 : 1); + byte boneSpikeCount = (byte)(Convert.ToBoolean((int)GetCaster().GetMap().GetDifficultyID() & 1) ? 3 : 1); List targets = marrowgarAI.SelectTargetList(new BoneSpikeTargetSelector(marrowgarAI), boneSpikeCount, SelectAggroTarget.Random); if (targets.Empty()) diff --git a/sql/updates/world/master/2018_09_15_00_world.sql b/sql/updates/world/master/2018_09_15_00_world.sql new file mode 100644 index 000000000..7a0b0d080 --- /dev/null +++ b/sql/updates/world/master/2018_09_15_00_world.sql @@ -0,0 +1,12 @@ +DELETE FROM `conditions` WHERE `ConditionTypeOrReference`=19 AND `SourceEntry` IN (13604,13817,50452,50453); +INSERT INTO `conditions` (`SourceTypeOrReferenceId`,`SourceGroup`,`SourceEntry`,`SourceId`,`ElseGroup`,`ConditionTypeOrReference`,`ConditionTarget`,`ConditionValue1`,`ConditionValue2`,`ConditionValue3`,`NegativeCondition`,`ErrorType`,`ErrorTextId`,`ScriptName`,`Comment`) VALUES +(10,34379,50453,0,0,49,0,6,0,0,0,0,0,'','Ring of Rotting Sinew only 25 heroic'), +(10,34379,50452,0,0,49,0,6,0,0,0,0,0,'','Wodin\'s Lucky Necklace only 25 heroic'); + +ALTER TABLE `creature` ADD `spawnDifficulties` VARCHAR(100) NOT NULL DEFAULT '0' AFTER `spawnMask`; +UPDATE `creature` SET `spawnDifficulties`=MAKE_SET(`spawnMask`,"0","1","2","3","4","5","6","7","8","9",NULL,"11","12",NULL,"14","15","16","17","18","19","20",NULL,NULL,"23","24","25","26","27",NULL,"29","30",NULL,"32","33","34"); +ALTER TABLE `creature` DROP `spawnMask`; + +ALTER TABLE `gameobject` ADD `spawnDifficulties` VARCHAR(100) NOT NULL DEFAULT '0' AFTER `spawnMask`; +UPDATE `gameobject` SET `spawnDifficulties`=MAKE_SET(`spawnMask`,"0","1","2","3","4","5","6","7","8","9",NULL,"11","12",NULL,"14","15","16","17","18","19","20",NULL,NULL,"23","24","25","26","27",NULL,"29","30",NULL,"32","33","34"); +ALTER TABLE `gameobject` DROP `spawnMask`;