diff --git a/Source/Framework/Database/Databases/WorldDatabase.cs b/Source/Framework/Database/Databases/WorldDatabase.cs index 12e6751ff..8f00f796b 100644 --- a/Source/Framework/Database/Databases/WorldDatabase.cs +++ b/Source/Framework/Database/Databases/WorldDatabase.cs @@ -14,8 +14,8 @@ namespace Framework.Database PrepareStatement(WorldStatements.SEL_SMART_SCRIPTS, "SELECT entryorguid, source_type, id, link, event_type, event_phase_mask, event_chance, event_flags, event_param1, event_param2, event_param3, event_param4, event_param5, event_param_string, action_type, action_param1, action_param2, action_param3, action_param4, action_param5, action_param6, action_param7, target_type, target_param1, target_param2, target_param3, target_param4, target_x, target_y, target_z, target_o FROM smart_scripts ORDER BY entryorguid, source_type, id, link"); PrepareStatement(WorldStatements.DEL_GAMEOBJECT, "DELETE FROM gameobject WHERE guid = ?"); PrepareStatement(WorldStatements.DEL_EVENT_GAMEOBJECT, "DELETE FROM game_event_gameobject WHERE guid = ?"); - PrepareStatement(WorldStatements.INS_GRAVEYARD_ZONE, "INSERT INTO graveyard_zone (ID, GhostZone, faction) VALUES (?, ?, ?)"); - PrepareStatement(WorldStatements.DEL_GRAVEYARD_ZONE, "DELETE FROM graveyard_zone WHERE ID = ? AND GhostZone = ? AND faction = ?"); + PrepareStatement(WorldStatements.INS_GRAVEYARD_ZONE, "INSERT INTO graveyard_zone (ID, GhostZone) VALUES (?, ?)"); + PrepareStatement(WorldStatements.DEL_GRAVEYARD_ZONE, "DELETE FROM graveyard_zone WHERE ID = ? AND GhostZone = ?"); PrepareStatement(WorldStatements.INS_GAME_TELE, "INSERT INTO game_tele (id, position_x, position_y, position_z, orientation, map, name) VALUES (?, ?, ?, ?, ?, ?, ?)"); PrepareStatement(WorldStatements.DEL_GAME_TELE, "DELETE FROM game_tele WHERE name = ?"); PrepareStatement(WorldStatements.INS_NPC_VENDOR, "INSERT INTO npc_vendor (entry, item, maxcount, incrtime, extendedcost, type) VALUES(?, ?, ?, ?, ?, ?)"); @@ -77,6 +77,7 @@ namespace Framework.Database PrepareStatement(WorldStatements.DEL_SPAWNGROUP_MEMBER, "DELETE FROM spawn_group WHERE spawnType = ? AND spawnId = ?"); PrepareStatement(WorldStatements.DEL_GAMEOBJECT_ADDON, "DELETE FROM gameobject_addon WHERE guid = ?"); PrepareStatement(WorldStatements.SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS, "SELECT AchievementRequired FROM guild_rewards_req_achievements WHERE ItemID = ?"); + PrepareStatement(WorldStatements.INS_CONDITION, "INSERT INTO conditions (SourceTypeOrReferenceId, SourceGroup, SourceEntry, SourceId, ElseGroup, ConditionTypeOrReference, ConditionTarget, ConditionValue1, ConditionValue2, ConditionValue3, NegativeCondition, ErrorType, ErrorTextId, ScriptName, Comment) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); } } @@ -153,6 +154,7 @@ namespace Framework.Database DEL_SPAWNGROUP_MEMBER, DEL_GAMEOBJECT_ADDON, SEL_GUILD_REWARDS_REQ_ACHIEVEMENTS, + INS_CONDITION, MAX_WORLDDATABASE_STATEMENTS } diff --git a/Source/Game/BattleFields/BattleField.cs b/Source/Game/BattleFields/BattleField.cs index caefc9d0e..7fec054f8 100644 --- a/Source/Game/BattleFields/BattleField.cs +++ b/Source/Game/BattleFields/BattleField.cs @@ -557,7 +557,7 @@ namespace Game.BattleFields return null; } - public WorldSafeLocsEntry GetClosestGraveYard(Player player) + public WorldSafeLocsEntry GetClosestGraveyard(Player player) { BfGraveyard closestGY = null; float maxdist = -1; diff --git a/Source/Game/BattleGrounds/BattleGround.cs b/Source/Game/BattleGrounds/BattleGround.cs index 4d38b2f36..5909d30ce 100644 --- a/Source/Game/BattleGrounds/BattleGround.cs +++ b/Source/Game/BattleGrounds/BattleGround.cs @@ -1714,9 +1714,9 @@ namespace Game.BattleGrounds m_BgRaids[GetTeamIndexByTeamId(team)] = bg_raid; } - public virtual WorldSafeLocsEntry GetClosestGraveYard(Player player) + public virtual WorldSafeLocsEntry GetClosestGraveyard(Player player) { - return Global.ObjectMgr.GetClosestGraveYard(player, GetPlayerTeam(player.GetGUID()), player); + return Global.ObjectMgr.GetClosestGraveyard(player, GetPlayerTeam(player.GetGUID()), player); } public override void TriggerGameEvent(uint gameEventId, WorldObject source = null, WorldObject target = null) diff --git a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs index 17139b4b9..0a79df4b8 100644 --- a/Source/Game/BattleGrounds/Zones/ArathiBasin.cs +++ b/Source/Game/BattleGrounds/Zones/ArathiBasin.cs @@ -614,7 +614,7 @@ namespace Game.BattleGrounds.Zones base.EndBattleground(winner); } - public override WorldSafeLocsEntry GetClosestGraveYard(Player player) + public override WorldSafeLocsEntry GetClosestGraveyard(Player player) { int teamIndex = GetTeamIndexByTeamId(GetPlayerTeam(player.GetGUID())); diff --git a/Source/Game/BattleGrounds/Zones/EyeofStorm.cs b/Source/Game/BattleGrounds/Zones/EyeofStorm.cs index fddc8b13a..f203a8fee 100644 --- a/Source/Game/BattleGrounds/Zones/EyeofStorm.cs +++ b/Source/Game/BattleGrounds/Zones/EyeofStorm.cs @@ -766,10 +766,10 @@ namespace Game.BattleGrounds.Zones if (!BgCreatures[Point].IsEmpty()) DelCreature(Point); - WorldSafeLocsEntry sg = Global.ObjectMgr.GetWorldSafeLoc(EotSMisc.m_CapturingPointTypes[Point].GraveYardId); + WorldSafeLocsEntry sg = Global.ObjectMgr.GetWorldSafeLoc(EotSMisc.m_CapturingPointTypes[Point].GraveyardId); if (sg == null || !AddSpiritGuide(Point, sg.Loc.GetPositionX(), sg.Loc.GetPositionY(), sg.Loc.GetPositionZ(), 3.124139f, GetTeamIndexByTeamId(Team))) Log.outError(LogFilter.Battleground, "BatteGroundEY: Failed to spawn spirit guide. point: {0}, team: {1}, graveyard_id: {2}", - Point, Team, EotSMisc.m_CapturingPointTypes[Point].GraveYardId); + Point, Team, EotSMisc.m_CapturingPointTypes[Point].GraveyardId); // SpawnBGCreature(Point, RESPAWN_IMMEDIATELY); @@ -847,7 +847,7 @@ namespace Game.BattleGrounds.Zones return true; } - public override WorldSafeLocsEntry GetClosestGraveYard(Player player) + public override WorldSafeLocsEntry GetClosestGraveyard(Player player) { uint g_id; Team team = GetPlayerTeam(player.GetGUID()); @@ -881,9 +881,9 @@ namespace Game.BattleGrounds.Zones { if (m_PointOwnedByTeam[i] == team && m_PointState[i] == EotSPointState.UnderControl) { - entry = Global.ObjectMgr.GetWorldSafeLoc(EotSMisc.m_CapturingPointTypes[i].GraveYardId); + entry = Global.ObjectMgr.GetWorldSafeLoc(EotSMisc.m_CapturingPointTypes[i].GraveyardId); if (entry == null) - Log.outError(LogFilter.Battleground, "BattlegroundEY: Graveyard {0} could not be found.", EotSMisc.m_CapturingPointTypes[i].GraveYardId); + Log.outError(LogFilter.Battleground, "BattlegroundEY: Graveyard {0} could not be found.", EotSMisc.m_CapturingPointTypes[i].GraveyardId); else { distance = (entry.Loc.GetPositionX() - plr_x) * (entry.Loc.GetPositionX() - plr_x) + (entry.Loc.GetPositionY() - plr_y) * (entry.Loc.GetPositionY() - plr_y) + (entry.Loc.GetPositionZ() - plr_z) * (entry.Loc.GetPositionZ() - plr_z); @@ -1011,14 +1011,14 @@ namespace Game.BattleGrounds.Zones struct BattlegroundEYCapturingPointStruct { - public BattlegroundEYCapturingPointStruct(int _DespawnNeutralObjectType, int _SpawnObjectTypeAlliance, uint _MessageIdAlliance, int _SpawnObjectTypeHorde, uint _MessageIdHorde, uint _GraveYardId) + public BattlegroundEYCapturingPointStruct(int _DespawnNeutralObjectType, int _SpawnObjectTypeAlliance, uint _MessageIdAlliance, int _SpawnObjectTypeHorde, uint _MessageIdHorde, uint _GraveyardId) { DespawnNeutralObjectType = _DespawnNeutralObjectType; SpawnObjectTypeAlliance = _SpawnObjectTypeAlliance; MessageIdAlliance = _MessageIdAlliance; SpawnObjectTypeHorde = _SpawnObjectTypeHorde; MessageIdHorde = _MessageIdHorde; - GraveYardId = _GraveYardId; + GraveyardId = _GraveyardId; } public int DespawnNeutralObjectType; @@ -1026,7 +1026,7 @@ namespace Game.BattleGrounds.Zones public uint MessageIdAlliance; public int SpawnObjectTypeHorde; public uint MessageIdHorde; - public uint GraveYardId; + public uint GraveyardId; } struct EotSMisc diff --git a/Source/Game/BattleGrounds/Zones/StrandofAncients.cs b/Source/Game/BattleGrounds/Zones/StrandofAncients.cs index 7b0ed6e89..c51fc7e78 100644 --- a/Source/Game/BattleGrounds/Zones/StrandofAncients.cs +++ b/Source/Game/BattleGrounds/Zones/StrandofAncients.cs @@ -640,7 +640,7 @@ namespace Game.BattleGrounds.Zones { } - public override WorldSafeLocsEntry GetClosestGraveYard(Player player) + public override WorldSafeLocsEntry GetClosestGraveyard(Player player) { uint safeloc; diff --git a/Source/Game/BattleGrounds/Zones/WarsongGluch.cs b/Source/Game/BattleGrounds/Zones/WarsongGluch.cs index dcb724240..01002ba14 100644 --- a/Source/Game/BattleGrounds/Zones/WarsongGluch.cs +++ b/Source/Game/BattleGrounds/Zones/WarsongGluch.cs @@ -797,7 +797,7 @@ namespace Game.BattleGrounds.Zones return true; } - public override WorldSafeLocsEntry GetClosestGraveYard(Player player) + public override WorldSafeLocsEntry GetClosestGraveyard(Player player) { //if status in progress, it returns main graveyards with spiritguides //else it will return the graveyard in the flagroom - this is especially good diff --git a/Source/Game/Chat/Commands/DebugCommands.cs b/Source/Game/Chat/Commands/DebugCommands.cs index 7c44f6c24..e6bc5ef22 100644 --- a/Source/Game/Chat/Commands/DebugCommands.cs +++ b/Source/Game/Chat/Commands/DebugCommands.cs @@ -684,14 +684,14 @@ namespace Game.Chat { Battleground bg = player.GetBattleground(); if (bg) - nearestLoc = bg.GetClosestGraveYard(player); + nearestLoc = bg.GetClosestGraveyard(player); else { BattleField bf = Global.BattleFieldMgr.GetBattlefieldToZoneId(player.GetMap(), player.GetZoneId()); if (bf != null) - nearestLoc = bf.GetClosestGraveYard(player); + nearestLoc = bf.GetClosestGraveyard(player); else - nearestLoc = Global.ObjectMgr.GetClosestGraveYard(player, player.GetTeam(), player); + nearestLoc = Global.ObjectMgr.GetClosestGraveyard(player, player.GetTeam(), player); } } else diff --git a/Source/Game/Chat/Commands/MiscCommands.cs b/Source/Game/Chat/Commands/MiscCommands.cs index 6167ba887..8e20c1fe1 100644 --- a/Source/Game/Chat/Commands/MiscCommands.cs +++ b/Source/Game/Chat/Commands/MiscCommands.cs @@ -790,7 +790,7 @@ namespace Game.Chat return false; } - if (Global.ObjectMgr.AddGraveYardLink(graveyardId, zoneId, team)) + if (Global.ObjectMgr.AddGraveyardLink(graveyardId, zoneId, team, true)) handler.SendSysMessage(CypherStrings.CommandGraveyardlinked, graveyardId, zoneId); else handler.SendSysMessage(CypherStrings.CommandGraveyardalrlinked, graveyardId, zoneId); @@ -1060,20 +1060,18 @@ namespace Game.Chat Player player = handler.GetSession().GetPlayer(); uint zoneId = player.GetZoneId(); - WorldSafeLocsEntry graveyard = Global.ObjectMgr.GetClosestGraveYard(player, team, null); + WorldSafeLocsEntry graveyard = Global.ObjectMgr.GetClosestGraveyard(player, team, null); if (graveyard != null) { uint graveyardId = graveyard.Id; - GraveYardData data = Global.ObjectMgr.FindGraveYardData(graveyardId, zoneId); + GraveyardData data = Global.ObjectMgr.FindGraveyardData(graveyardId, zoneId); if (data == null) { handler.SendSysMessage(CypherStrings.CommandGraveyarderror, graveyardId); return false; } - team = (Team)data.team; - string team_name = handler.GetCypherString(CypherStrings.CommandGraveyardNoteam); if (team == 0) diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index f6a82fc2c..4bea5e3d3 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -148,6 +148,7 @@ namespace Game sourceType == ConditionSourceType.SmartEvent || sourceType == ConditionSourceType.NpcVendor || sourceType == ConditionSourceType.Phase || + sourceType == ConditionSourceType.Graveyard || sourceType == ConditionSourceType.AreaTrigger || sourceType == ConditionSourceType.TrainerSpell || sourceType == ConditionSourceType.ObjectIdVisibility; @@ -561,6 +562,9 @@ namespace Game case ConditionSourceType.Phase: valid = AddToPhases(cond); break; + case ConditionSourceType.Graveyard: + valid = AddToGraveyardData(cond); + break; case ConditionSourceType.AreaTrigger: areaTriggerConditionContainerStorage.Add(Tuple.Create(cond.SourceGroup, cond.SourceEntry != 0), cond); ++count; @@ -807,6 +811,19 @@ namespace Game return false; } + bool AddToGraveyardData(Condition cond) + { + GraveyardData graveyard = Global.ObjectMgr.FindGraveyardData((uint)cond.SourceEntry, cond.SourceGroup); + if (graveyard != null) + { + graveyard.Conditions.Add(cond); + return true; + } + + Log.outError(LogFilter.Sql, $"{cond}, Graveyard {cond.SourceEntry} does not have ghostzone {cond.SourceGroup}."); + return false; + } + bool IsSourceTypeValid(Condition cond) { switch (cond.SourceType) @@ -1176,9 +1193,9 @@ namespace Game case ConditionSourceType.SmartEvent: break; case ConditionSourceType.Graveyard: - if (Global.ObjectMgr.GetWorldSafeLoc((uint)cond.SourceEntry) == null) + if (Global.ObjectMgr.FindGraveyardData((uint)cond.SourceEntry, cond.SourceGroup) == null) { - Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceEntry in `condition` table, does not exist in WorldSafeLocs.db2, ignoring."); + Log.outError(LogFilter.Sql, $"{cond.ToString()} SourceEntry in `condition` table, does not exist in `graveyard_zone`, ignoring."); return false; } break; diff --git a/Source/Game/Entities/Player/Player.DB.cs b/Source/Game/Entities/Player/Player.DB.cs index 01cd8691e..8c5272edb 100644 --- a/Source/Game/Entities/Player/Player.DB.cs +++ b/Source/Game/Entities/Player/Player.DB.cs @@ -632,7 +632,7 @@ namespace Game.Entities if (!ok) { - WorldSafeLocsEntry loc = Global.ObjectMgr.GetDefaultGraveYard(GetTeam()); + WorldSafeLocsEntry loc = Global.ObjectMgr.GetDefaultGraveyard(GetTeam()); if (loc == null && GetRace() == Race.PandarenNeutral) loc = Global.ObjectMgr.GetWorldSafeLoc(3295); // The Wandering Isle, Starting Area GY diff --git a/Source/Game/Entities/Player/Player.PvP.cs b/Source/Game/Entities/Player/Player.PvP.cs index 5f11c5ab9..8a8970682 100644 --- a/Source/Game/Entities/Player/Player.PvP.cs +++ b/Source/Game/Entities/Player/Player.PvP.cs @@ -562,7 +562,7 @@ namespace Game.Entities // If map is dungeon find linked graveyard if (GetMap().IsDungeon()) { - WorldSafeLocsEntry entry = Global.ObjectMgr.GetClosestGraveYard(this, GetTeam(), this); + WorldSafeLocsEntry entry = Global.ObjectMgr.GetClosestGraveyard(this, GetTeam(), this); if (entry != null) m_bgData.joinPos = entry.Loc; else diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 1ee50e42a..b893e85f2 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -4211,14 +4211,14 @@ namespace Game.Entities // Special handle for Battlegroundmaps Battleground bg = GetBattleground(); if (bg) - ClosestGrave = bg.GetClosestGraveYard(this); + ClosestGrave = bg.GetClosestGraveyard(this); else { BattleField bf = BattleFieldMgr.GetBattlefieldToZoneId(GetMap(), GetZoneId()); if (bf != null) - ClosestGrave = bf.GetClosestGraveYard(this); + ClosestGrave = bf.GetClosestGraveyard(this); else - ClosestGrave = ObjectMgr.GetClosestGraveYard(this, GetTeam(), this); + ClosestGrave = ObjectMgr.GetClosestGraveyard(this, GetTeam(), this); } // stop countdown until repop diff --git a/Source/Game/Globals/ObjectManager.cs b/Source/Game/Globals/ObjectManager.cs index d02d81828..377e89011 100644 --- a/Source/Game/Globals/ObjectManager.cs +++ b/Source/Game/Globals/ObjectManager.cs @@ -754,10 +754,10 @@ namespace Game { uint oldMSTime = Time.GetMSTime(); - GraveYardStorage.Clear(); // need for reload case + GraveyardStorage.Clear(); // need for reload case - // 0 1 2 - SQLResult result = DB.World.Query("SELECT ID, GhostZone, faction FROM graveyard_zone"); + // 0 1 + SQLResult result = DB.World.Query("SELECT ID, GhostZone FROM graveyard_zone"); if (result.IsEmpty()) { @@ -769,10 +769,8 @@ namespace Game do { - ++count; uint safeLocId = result.Read(0); uint zoneId = result.Read(1); - Team team = (Team)result.Read(2); WorldSafeLocsEntry entry = GetWorldSafeLoc(safeLocId); if (entry == null) @@ -788,18 +786,15 @@ namespace Game continue; } - if (team != 0 && team != Team.Horde && team != Team.Alliance) - { - Log.outError(LogFilter.Sql, "Table `graveyard_zone` has a record for non player faction ({0}), skipped.", team); - continue; - } - - if (!AddGraveYardLink(safeLocId, zoneId, team, false)) + if (!AddGraveyardLink(safeLocId, zoneId, 0, false)) Log.outError(LogFilter.Sql, "Table `graveyard_zone` has a duplicate record for Graveyard (ID: {0}) and Zone (ID: {1}), skipped.", safeLocId, zoneId); + + ++count; } while (result.NextRow()); Log.outInfo(LogFilter.ServerLoading, "Loaded {0} graveyard-zone links in {1} ms", count, Time.GetMSTimeDiffToNow(oldMSTime)); } + public void LoadWorldSafeLocs() { uint oldMSTime = Time.GetMSTime(); @@ -831,7 +826,7 @@ namespace Game Log.outInfo(LogFilter.ServerLoading, $"Loaded {_worldSafeLocs.Count} world locations {Time.GetMSTimeDiffToNow(oldMSTime)} ms"); } - public WorldSafeLocsEntry GetDefaultGraveYard(Team team) + public WorldSafeLocsEntry GetDefaultGraveyard(Team team) { if (team == Team.Horde) return GetWorldSafeLoc(10); @@ -840,7 +835,7 @@ namespace Game else return null; } - public WorldSafeLocsEntry GetClosestGraveYard(WorldLocation location, Team team, WorldObject conditionObject) + public WorldSafeLocsEntry GetClosestGraveyard(WorldLocation location, Team team, WorldObject conditionObject) { float x, y, z; location.GetPosition(out x, out y, out z); @@ -853,7 +848,7 @@ namespace Game if (z > -500) { Log.outError(LogFilter.Server, "ZoneId not found for map {0} coords ({1}, {2}, {3})", MapId, x, y, z); - return GetDefaultGraveYard(team); + return GetDefaultGraveyard(team); } } @@ -884,7 +879,7 @@ namespace Game // then check faction // if mapId != graveyard.mapId (ghost in instance) and search any graveyard associated // then check faction - var range = GraveYardStorage.LookupByKey(zoneId); + var range = GraveyardStorage.LookupByKey(zoneId); MapRecord mapEntry = CliDB.MapStorage.LookupByKey(MapId); ConditionSourceInfo conditionSource = new(conditionObject); @@ -894,7 +889,7 @@ namespace Game { if (zoneId != 0) // zone == 0 can't be fixed, used by bliz for bugged zones Log.outError(LogFilter.Sql, "Table `game_graveyard_zone` incomplete: Zone {0} Team {1} does not have a linked graveyard.", zoneId, team); - return GetDefaultGraveYard(team); + return GetDefaultGraveyard(team); } // at corpse map @@ -912,26 +907,38 @@ namespace Game foreach (var data in range) { - WorldSafeLocsEntry entry = GetWorldSafeLoc(data.safeLocId); + WorldSafeLocsEntry entry = GetWorldSafeLoc(data.SafeLocId); if (entry == null) { - Log.outError(LogFilter.Sql, "Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) {0}, skipped.", data.safeLocId); + Log.outError(LogFilter.Sql, "Table `game_graveyard_zone` has record for not existing graveyard (WorldSafeLocs.dbc id) {0}, skipped.", data.SafeLocId); continue; } - // skip enemy faction graveyard - // team == 0 case can be at call from .neargrave - if (data.team != 0 && team != 0 && data.team != (uint)team) - continue; - if (conditionObject) { - if (!Global.ConditionMgr.IsObjectMeetingNotGroupedConditions(ConditionSourceType.Graveyard, data.safeLocId, conditionSource)) + if (!Global.ConditionMgr.IsObjectMeetToConditions(conditionSource, data.Conditions)) continue; if (entry.Loc.GetMapId() == mapEntry.ParentMapID && !conditionObject.GetPhaseShift().HasVisibleMapId(entry.Loc.GetMapId())) continue; } + else if (team != 0) + { + bool teamConditionMet = true; + foreach (Condition cond in data.Conditions) + { + if (cond.ConditionType != ConditionTypes.Team) + continue; + + if (cond.ConditionValue1 == (uint)team) + continue; + + teamConditionMet = false; + } + + if (!teamConditionMet) + continue; + } // find now nearest graveyard at other map if (MapId != entry.Loc.GetMapId() && entry.Loc.GetMapId() != mapEntry.ParentMapID) @@ -995,12 +1002,12 @@ namespace Game return entryFar; } - public GraveYardData FindGraveYardData(uint id, uint zoneId) + public GraveyardData FindGraveyardData(uint id, uint zoneId) { - var range = GraveYardStorage.LookupByKey(zoneId); + var range = GraveyardStorage.LookupByKey(zoneId); foreach (var data in range) { - if (data.safeLocId == id) + if (data.SafeLocId == id) return data; } return null; @@ -1010,22 +1017,22 @@ namespace Game { return _worldSafeLocs.LookupByKey(id); } + public Dictionary GetWorldSafeLocs() { return _worldSafeLocs; } - public bool AddGraveYardLink(uint id, uint zoneId, Team team, bool persist = true) + public bool AddGraveyardLink(uint id, uint zoneId, Team team, bool persist = true) { - if (FindGraveYardData(id, zoneId) != null) + if (FindGraveyardData(id, zoneId) != null) return false; // add link to loaded data - GraveYardData data = new(); - data.safeLocId = id; - data.team = (uint)team; + GraveyardData data = new(); + data.SafeLocId = id; - GraveYardStorage.Add(zoneId, data); + GraveyardStorage.Add(zoneId, data); // add link to DB if (persist) @@ -1034,59 +1041,39 @@ namespace Game stmt.AddValue(0, id); stmt.AddValue(1, zoneId); - stmt.AddValue(2, (uint)team); DB.World.Execute(stmt); + + // Store graveyard condition if team is set + if (team != 0) + { + PreparedStatement conditionStmt = WorldDatabase.GetPreparedStatement(WorldStatements.INS_CONDITION); + conditionStmt.AddValue(0, (uint)ConditionSourceType.Graveyard); // SourceTypeOrReferenceId + conditionStmt.AddValue(1, zoneId); // SourceGroup + conditionStmt.AddValue(2, id); // SourceEntry + conditionStmt.AddValue(3, 0); // SourceId + conditionStmt.AddValue(4, 0); // ElseGroup + conditionStmt.AddValue(5, (uint)ConditionTypes.Team); // ConditionTypeOrReference + conditionStmt.AddValue(6, 0); // ConditionTarget + conditionStmt.AddValue(7, (uint)team); // ConditionValue1 + conditionStmt.AddValue(8, 0); // ConditionValue2 + conditionStmt.AddValue(9, 0); // ConditionValue3 + conditionStmt.AddValue(10, 0); // NegativeCondition + conditionStmt.AddValue(11, 0); // ErrorType + conditionStmt.AddValue(12, 0); // ErrorTextId + conditionStmt.AddValue(13, ""); // ScriptName + conditionStmt.AddValue(14, ""); // Comment + + DB.World.Execute(conditionStmt); + + // reload conditions to make sure everything is loaded as it should be + Global.ConditionMgr.LoadConditions(true); + //Global.ScriptMgr.NotifyScriptIDUpdate(); + } } return true; } - public void RemoveGraveYardLink(uint id, uint zoneId, Team team, bool persist = false) - { - var range = GraveYardStorage.LookupByKey(zoneId); - if (range.Empty()) - { - Log.outError(LogFilter.Sql, "Table `game_graveyard_zone` incomplete: Zone {0} Team {1} does not have a linked graveyard.", zoneId, team); - return; - } - - bool found = false; - - - foreach (var data in range) - { - // skip not matching safezone id - if (data.safeLocId != id) - continue; - - // skip enemy faction graveyard at same map (normal area, city, or Battleground) - // team == 0 case can be at call from .neargrave - if (data.team != 0 && team != 0 && data.team != (uint)team) - continue; - - found = true; - break; - } - - // no match, return - if (!found) - return; - - // remove from links - GraveYardStorage.Remove(zoneId); - - // remove link from DB - if (persist) - { - PreparedStatement stmt = WorldDatabase.GetPreparedStatement(WorldStatements.DEL_GRAVEYARD_ZONE); - - stmt.AddValue(0, id); - stmt.AddValue(1, zoneId); - stmt.AddValue(2, (uint)team); - - DB.World.Execute(stmt); - } - } //Scripts public void LoadAreaTriggerScripts() @@ -10893,7 +10880,7 @@ namespace Game Dictionary<(uint mapId, Difficulty difficulty), Dictionary> mapObjectGuidsStore = new(); Dictionary<(uint mapId, Difficulty diffuculty, uint phaseId), Dictionary> mapPersonalObjectGuidsStore = new(); Dictionary instanceTemplateStorage = new(); - public MultiMap GraveYardStorage = new(); + public MultiMap GraveyardStorage = new(); List _transportMaps = new(); Dictionary _spawnGroupDataStorage = new(); MultiMap _spawnGroupMapStorage = new(); @@ -11402,10 +11389,10 @@ namespace Game public WorldLocation Loc; } - public class GraveYardData + public class GraveyardData { - public uint safeLocId; - public uint team; + public uint SafeLocId; + public List Conditions; } public class QuestPOIBlobData diff --git a/Source/Game/Handlers/CharacterHandler.cs b/Source/Game/Handlers/CharacterHandler.cs index 3e3ff94c6..e60e3162b 100644 --- a/Source/Game/Handlers/CharacterHandler.cs +++ b/Source/Game/Handlers/CharacterHandler.cs @@ -5,6 +5,7 @@ using Framework.Collections; using Framework.Constants; using Framework.Database; using Game.Cache; +using Game.Conditions; using Game.DataStorage; using Game.Entities; using Game.Groups; @@ -2403,13 +2404,16 @@ namespace Game uint team = (uint)GetPlayer().GetTeam(); List graveyardIds = new(); - var range = Global.ObjectMgr.GraveYardStorage.LookupByKey(zoneId); + var range = Global.ObjectMgr.GraveyardStorage.LookupByKey(zoneId); for (uint i = 0; i < range.Count && graveyardIds.Count < 16; ++i) // client max { var gYard = range[(int)i]; - if (gYard.team == 0 || gYard.team == team) - graveyardIds.Add(i); + ConditionSourceInfo conditionSource = new(_player); + if (!Global.ConditionMgr.IsObjectMeetToConditions(conditionSource, gYard.Conditions)) + continue; + + graveyardIds.Add(i); } if (graveyardIds.Empty()) diff --git a/Source/Game/Handlers/NPCHandler.cs b/Source/Game/Handlers/NPCHandler.cs index 53403ee55..0174de3d8 100644 --- a/Source/Game/Handlers/NPCHandler.cs +++ b/Source/Game/Handlers/NPCHandler.cs @@ -260,7 +260,7 @@ namespace Game WorldLocation corpseLocation = GetPlayer().GetCorpseLocation(); if (GetPlayer().HasCorpse()) { - corpseGrave = Global.ObjectMgr.GetClosestGraveYard(corpseLocation, GetPlayer().GetTeam(), GetPlayer()); + corpseGrave = Global.ObjectMgr.GetClosestGraveyard(corpseLocation, GetPlayer().GetTeam(), GetPlayer()); } // now can spawn bones @@ -269,7 +269,7 @@ namespace Game // teleport to nearest from corpse graveyard, if different from nearest to player ghost if (corpseGrave != null) { - WorldSafeLocsEntry ghostGrave = Global.ObjectMgr.GetClosestGraveYard(GetPlayer(), GetPlayer().GetTeam(), GetPlayer()); + WorldSafeLocsEntry ghostGrave = Global.ObjectMgr.GetClosestGraveyard(GetPlayer(), GetPlayer().GetTeam(), GetPlayer()); if (corpseGrave != ghostGrave) GetPlayer().TeleportTo(corpseGrave.Loc); diff --git a/Source/Scripts/BattleField/WinterGrasp.cs b/Source/Scripts/BattleField/WinterGrasp.cs index e2dc648ee..b13e37508 100644 --- a/Source/Scripts/BattleField/WinterGrasp.cs +++ b/Source/Scripts/BattleField/WinterGrasp.cs @@ -67,7 +67,7 @@ namespace Game.BattleFields Global.WorldStateMgr.SetValue(WorldStates.BattlefieldWgAttacker, (int)GetAttackerTeam(), false, m_Map); Global.WorldStateMgr.SetValue(WGConst.ClockWorldState[1], (int)(GameTime.GetGameTime() + m_Timer / Time.InMilliseconds), false, m_Map); - foreach (var gy in WGConst.WGGraveYard) + foreach (var gy in WGConst.WGGraveyard) { BfGraveyardWG graveyard = new(this); diff --git a/Source/Scripts/BattleField/WinterGraspConst.cs b/Source/Scripts/BattleField/WinterGraspConst.cs index 3d54a1feb..905857321 100644 --- a/Source/Scripts/BattleField/WinterGraspConst.cs +++ b/Source/Scripts/BattleField/WinterGraspConst.cs @@ -16,7 +16,7 @@ namespace Game.BattleFields public const byte MaxWorkshops = 6; #region Data - public static BfWGCoordGY[] WGGraveYard = + public static BfWGCoordGY[] WGGraveyard = { new BfWGCoordGY(5104.750f, 2300.940f, 368.579f, 0.733038f, 1329, WGGossipText.GYNE, TeamId.Neutral), new BfWGCoordGY(5099.120f, 3466.036f, 368.484f, 5.317802f, 1330, WGGossipText.GYNW, TeamId.Neutral),