diff --git a/src/DiIiS-NA/Core/Logging/FileTarget.cs b/src/DiIiS-NA/Core/Logging/FileTarget.cs index efaf281..15c723e 100644 --- a/src/DiIiS-NA/Core/Logging/FileTarget.cs +++ b/src/DiIiS-NA/Core/Logging/FileTarget.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Concurrent; using System.IO; +using System.Text.RegularExpressions; using System.Threading; namespace DiIiS_NA.Core.Logging @@ -24,48 +25,55 @@ namespace DiIiS_NA.Core.Logging /// Reset log file on application startup? public FileTarget(string fileName, Logger.Level minLevel, Logger.Level maxLevel, bool includeTimeStamps, bool reset = false) { - this.MinimumLevel = minLevel; - this.MaximumLevel = maxLevel; - this.IncludeTimeStamps = includeTimeStamps; - this._fileName = fileName; - this._fileTimestamp = DateTime.Now.ToString("yyyyMMdd_HHmm"); - this._filePath = string.Format("{0}/{1}/{2}", LogConfig.Instance.LoggingRoot, this._fileTimestamp, _fileName); - this._fileIndex = 0; + MinimumLevel = minLevel; + MaximumLevel = maxLevel; + IncludeTimeStamps = includeTimeStamps; + _fileName = fileName; + _fileTimestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm"); + _filePath = $"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}/{_fileName}"; + _fileIndex = 0; if (!Directory.Exists(LogConfig.Instance.LoggingRoot)) // create logging directory if it does not exist yet. Directory.CreateDirectory(LogConfig.Instance.LoggingRoot); - if (!Directory.Exists(string.Format("{0}/{1}", LogConfig.Instance.LoggingRoot, this._fileTimestamp))) // create logging directory if it does not exist yet. - Directory.CreateDirectory(string.Format("{0}/{1}", LogConfig.Instance.LoggingRoot, this._fileTimestamp)); + if (!Directory.Exists($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}")) // create logging directory if it does not exist yet. + Directory.CreateDirectory($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}"); - this._fileStream = new FileStream(_filePath, reset ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.Read); // init the file stream. - this._logStream = new StreamWriter(this._fileStream) { AutoFlush = true }; // init the stream writer. - this.TaskQueue = new ConcurrentQueue(); - this.LoggerThread = new Thread(this.CheckQueue) { Name = "Logger", IsBackground = true }; - this.LoggerThread.Start(); + _fileStream = new FileStream(_filePath, reset ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.Read); // init the file stream. + _logStream = new StreamWriter(_fileStream) { AutoFlush = true }; // init the stream writer. + TaskQueue = new ConcurrentQueue(); + LoggerThread = new Thread(CheckQueue) { Name = "Logger", IsBackground = true }; + LoggerThread.Start(); } public void CheckQueue() { while (true) { - Action action = null; - if (this.TaskQueue.TryDequeue(out action)) + if (TaskQueue.TryDequeue(out var action)) action.Invoke(); Thread.Sleep(1); } } + /// + /// Replace the colors from AnsiColor so they do not appear in the log file. + /// + /// + /// + private string NoColors(string message) => Regex.Replace(message, @"\$\[[\w\W\d\s_\-\/]+\]\$", ""); + /// Log level. /// Source of the log message. /// Log message. public override void LogMessage(Logger.Level level, string logger, string message) { - this.TaskQueue.Enqueue(() => + TaskQueue.Enqueue(() => { - var timeStamp = this.IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : ""; - if (!this._disposed) // make sure we're not disposed. + message = NoColors(message); + var timeStamp = IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : ""; + if (!_disposed) // make sure we're not disposed. { /* if (this._fileStream.Length >= 20971520) //20 MB limit @@ -77,9 +85,9 @@ namespace DiIiS_NA.Core.Logging } //*/ if (level > Logger.Level.ChatMessage) - this._logStream.WriteLine(string.Format("{0}[{1}] [{2}]: {3}", timeStamp, level.ToString().PadLeft(5), logger, message)); + _logStream.WriteLine($"{timeStamp}[{level.ToString(),5}] [{logger}]: {message}"); else - this._logStream.WriteLine(string.Format("{0}{1}", timeStamp, message)); + _logStream.WriteLine($"{timeStamp}{message}"); } }); } @@ -90,12 +98,13 @@ namespace DiIiS_NA.Core.Logging /// Exception to be included with log message. public override void LogException(Logger.Level level, string logger, string message, Exception exception) { - this.TaskQueue.Enqueue(() => + TaskQueue.Enqueue(() => { - var timeStamp = this.IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : ""; - if (!this._disposed) // make sure we're not disposed. + message = NoColors(message); + var timeStamp = IncludeTimeStamps ? "[" + DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff") + "] " : ""; + if (!_disposed) // make sure we're not disposed. { - this._logStream.WriteLine( + _logStream.WriteLine( $"{timeStamp}[{level.ToString(),5}] [{logger}]: {message} - [Exception] {exception}"); } }); @@ -109,23 +118,23 @@ namespace DiIiS_NA.Core.Logging public void Dispose() { Dispose(true); - GC.SuppressFinalize(this); // Take object out the finalization queue to prevent finalization code for it from executing a second time. + GC.SuppressFinalize(this); // Take object out the finalization queue to prevent finalization code for it from executing (~FileTarget). } private void Dispose(bool disposing) { - if (this._disposed) return; // if already disposed, just return + if (_disposed) return; // if already disposed, just return if (disposing) // only dispose managed resources if we're called from directly or in-directly from user code. { - this._logStream.Close(); - this._logStream.Dispose(); - this._fileStream.Close(); - this._fileStream.Dispose(); + _logStream.Close(); + _logStream.Dispose(); + _fileStream.Close(); + _fileStream.Dispose(); } - this._logStream = null; - this._fileStream = null; + _logStream = null; + _fileStream = null; _disposed = true; } diff --git a/src/DiIiS-NA/D3-GameServer/CommandManager/GameCommands.cs b/src/DiIiS-NA/D3-GameServer/CommandManager/GameCommands.cs index 7377b6c..620f29e 100644 --- a/src/DiIiS-NA/D3-GameServer/CommandManager/GameCommands.cs +++ b/src/DiIiS-NA/D3-GameServer/CommandManager/GameCommands.cs @@ -16,6 +16,7 @@ using DiIiS_NA.LoginServer.Battle; using System; using System.Collections.Generic; using System.Linq; +using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations; using DiIiS_NA.GameServer.GSSystem.GameSystem; using DiIiS_NA.GameServer.GSSystem.ObjectsSystem; using DiIiS_NA.GameServer.GSSystem.PlayerSystem; @@ -25,6 +26,74 @@ using Actor = DiIiS_NA.Core.MPQ.FileFormats.Actor; namespace DiIiS_NA.GameServer.CommandManager; +[CommandGroup("doors", "Information about all doors in the vicinity. This is useful for testing purposes.. Useful for testing.", Account.UserLevels.Tester)] +public class OpenDoorCommand : CommandGroup +{ + [Command("all", "Activate all doors. This is useful for testing purposes.\nUsage: !open all", Account.UserLevels.Tester)] + public string OpenAllDoors(string[] @params, BattleClient invokerClient) + { + if (invokerClient?.InGameClient?.Player is not { } player) + return "You are not in game."; + var world = player.World; + var openedDoors = world.OpenAllDoors(); + if (openedDoors.Length == 0) + return "No doors found."; + return $"Opened {openedDoors.Length} doors: {string.Join(", ", openedDoors.Select(d => (int)d.SNO + " - " + d.SNO))}"; + } + + [Command("near", "Activate all nearby doors in the vicinity. This is useful for testing purposes.\nUsage: !open near [distance:50]", Account.UserLevels.Tester)] + public string OpenAllDoorsNear(string[] @params, BattleClient invokerClient) + { + if (invokerClient?.InGameClient?.Player is not { } player) + return "You are not in game."; + var world = player.World; + + var distance = 50f; + + if (@params.Length > 0) + { + if (!float.TryParse(@params[0], out distance) || distance < 1) + return "Invalid distance. Distance must be greater than 1."; + } + + var openedDoors = player.OpenNearDoors(distance); + if (openedDoors.Length == 0) + return "No doors found."; + return $"Opened {openedDoors.Count()} in a distance of {distance:0.0000} doors: {string.Join(", ", openedDoors)}"; + } + + [Command("info", "Retrieve all world doors in proximity, sorted in descending order.\nUsage: !open info [distance:50]", Account.UserLevels.Tester)] + public string InfoDoorsNear(string[] @params, BattleClient invokerClient) + { + if (invokerClient?.InGameClient?.Player is not { } player) + return "You are not in game."; + var world = player.World; + var distance = 50f; + + if (@params.Length > 0) + { + if (!float.TryParse(@params[0], out distance) || distance < 1) + return "Invalid distance. Distance must be greater than 1."; + } + + var doors = player.GetNearDoors(distance); + if (doors.Length == 0) + return "No doors found."; + return $"{doors.Length} doors in a distance of {distance:0.0000} doors: \n{string.Join("\n", doors.Select(s=> + { + var position = player.Position; + return s.Position.DistanceSquared(ref position) + " distance - [" + (int)s.SNO + "] " + s.SNO;; + }))}"; + } + + [DefaultCommand()] + public string DefaultCommand(string[] @params, BattleClient invokerClient) + { + return "!doors all - Activate all doors. This is useful for testing purposes.\n" + + "!doors near [distance:50] - Activate all nearby doors in the vicinity. This is useful for testing purposes.\n" + + "!doors info [distance:50] - Retrieve all world doors in proximity, sorted in descending order."; + } +} [CommandGroup("powerful", "Makes your character with absurd amount of damage. Useful for testing.", Account.UserLevels.Tester)] public class PowerfulCommand : CommandGroup diff --git a/src/DiIiS-NA/D3-GameServer/Config.cs b/src/DiIiS-NA/D3-GameServer/Config.cs index 9040f1f..dba074a 100644 --- a/src/DiIiS-NA/D3-GameServer/Config.cs +++ b/src/DiIiS-NA/D3-GameServer/Config.cs @@ -133,7 +133,25 @@ namespace DiIiS_NA.GameServer get => GetInt(nameof(ResurrectionCharges), 3); set => Set(nameof(ResurrectionCharges), value); } + + /// + /// Boss Health Multiplier + /// + public float BossHealthMultiplier + { + get => GetFloat(nameof(BossHealthMultiplier), 6f); + set => Set(nameof(BossHealthMultiplier), value); + } + /// + /// Boss Damage Multiplier + /// + public float BossDamageMultiplier + { + get => GetFloat(nameof(BossDamageMultiplier), 3f); + set => Set(nameof(BossDamageMultiplier), value); + } + public static Config Instance { get; } = new(); private Config() : base("Game-Server") diff --git a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs index e581c84..9bcdc55 100644 --- a/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs +++ b/src/DiIiS-NA/D3-GameServer/Core/Types/Math/Vector3D.cs @@ -104,7 +104,7 @@ namespace DiIiS_NA.GameServer.Core.Types.Math /// /// the second /// the distance squared between the vectors - public float DistanceSquared(ref Vector3D point) + public float DistanceSquared(ref Vector3D point) // todo: remove ref { float x = point.X - X, y = point.Y - Y, @@ -183,8 +183,6 @@ namespace DiIiS_NA.GameServer.Core.Types.Math public override string ToString() => $"X:{X:F4}, Y:{Y:F4} Z:{Z:F4}"; - public bool IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance * distance; - - public bool IsNearSquared(Vector3D other, float distanceSquared) => DistanceSquared(ref other) < distanceSquared; + public bool IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance; } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs index f29dd16..fe4ea7b 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Boss.cs @@ -69,6 +69,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations public sealed class Boss : Monster { private static readonly Logger Logger = LogManager.CreateLogger(nameof(Boss)); + public Boss(MapSystem.World world, ActorSno sno, TagMap tags) : base(world, sno, tags) { @@ -77,106 +78,113 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations //this.Attributes[GameAttribute.Immune_To_Charm] = true; Attributes[GameAttribute.using_Bossbar] = true; Attributes[GameAttribute.InBossEncounter] = true; - Attributes[GameAttribute.Hitpoints_Max] *= 4f; - Attributes[GameAttribute.Damage_Weapon_Min, 0] *= 3f; - Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= 3f; + Attributes[GameAttribute.Hitpoints_Max] *= Config.Instance.BossHealthMultiplier; + Attributes[GameAttribute.Damage_Weapon_Min, 0] *= Config.Instance.BossDamageMultiplier; + Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= Config.Instance.BossDamageMultiplier; Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total]; Attributes[GameAttribute.TeamID] = 10; - + WalkSpeed *= 0.5f; - MonsterBrain monsterBrain = (Brain as MonsterBrain); - switch (sno) + if (Brain is MonsterBrain monsterBrain) { - case ActorSno._diablo: //Diablo - //(Brain as MonsterBrain).RemovePresetPower(30592); - //(Brain as MonsterBrain).AddPresetPower(136189); //[136189] Diablo_ClawRip - monsterBrain.AddPresetPower(136223); //Diablo_RingOfFire - monsterBrain.AddPresetPower(136226); //Diablo_HellSpikes - ; + switch (sno) + { + case ActorSno._diablo: //Diablo + //(Brain as MonsterBrain).RemovePresetPower(30592); + //(Brain as MonsterBrain).AddPresetPower(136189); //[136189] Diablo_ClawRip + monsterBrain.AddPresetPower(136223); //Diablo_RingOfFire + monsterBrain.AddPresetPower(136226); //Diablo_HellSpikes + ; - /* - [199476] Diablo_StompAndStun - [219598] Diablo_Teleport - [167560] Diablo_LightningBreath_v2 - [185997] Diablo_ExpandingFireRing - [169212] Diablo_Smash_Puny_Destructible - [136828] Diablo_CurseOfAnguish - [136829] Diablo_CurseOfPain - [136830] Diablo_CurseOfHate - [136831] Diablo_CurseOfDestruction - - [439719] Diablo_LightningBreath_LR_TerrorDemon_Clone - [214831] Diablo_FireMeteor - [161174] Diablo_CorruptionShield - [136219] Diablo_LightningBreath - [136223] Diablo_RingOfFire - [136226] Diablo_HellSpikes - - [214668] Diablo_GetHit - - [136237] Diablo_ShadowVanish - [136281] Diablo_ShadowClones - [142582] Diablo_ShadowVanish_Charge - [136849] Diablo_ShadowVanish_Grab - - [141865] Diablo_Phase1Buff - [136850] Diablo_Phase2Buff - [136852] Diablo_Phase3Buff - [478072] Diablo_StompAndStunMB313 - - [478410] Diablo_LightningBreath_Turret_MB313 - [195816] Diablo_Charge - [428985] Diablo_LightningBreath_LR_TerrorDemon - [376396] Uber_Gluttony_Gas_Cloud_Diablo - [375473] Uber_SkeletonKing_Summon_Skeleton_Diablo - [375493] Uber_Maghda_Summon_Beserker_Diablo - [365978] Uber_Diablo_StompAndStun - [375537] Uber_Despair_SummonMinion_Diablo - [375929] UberDiablo_MirrorImage - [376039] Uber_Despair_TeleportEnrage_Diablo - [376043] Uber_ZoltunKulle_SlowTime_Diablo - [376056] Uber_Despair_Volley_Diablo - [375439] x1_Uber_Diablo_HellSpikes - [375904] Diablo_LightningBreath_Uber - [375905] Diablo_ClawRip_Uber - [375907] Diablo_RingOfFire_Uber - [375908] Diablo_ExpandingFireRing_Uber - - [453765] p43_d1_Diablo_ClawRip - - [328715] x1_Malthael_Diablo_AIState - [334760] x1_Malthael_Diablo_TeleportFireNovaLightning - - - */ - break; - case ActorSno._skeletonking://Leoric King - monsterBrain.RemovePresetPower(30592); - monsterBrain.AddPresetPower(30496); - monsterBrain.AddPresetPower(30504); - monsterBrain.AddPresetPower(73824); - monsterBrain.AddPresetPower(79334); - break; - case ActorSno._butcher://Butcher - monsterBrain.AddPresetPower(83008); - break; - case ActorSno._belial_trueform://Belial (small) - HasLoot = false; - break; - case ActorSno._belial://Belial (big) - monsterBrain.AddPresetPower(152540); - break; - case ActorSno._maghda://Maghda - monsterBrain.AddPresetPower(131744); //summon berserker - //(Brain as MonsterBrain).AddPresetPower(131745); //mothDust - monsterBrain.AddPresetPower(131749); //teleport - break; - case ActorSno._gluttony://Gluttony - monsterBrain.AddPresetPower(93676); //gas cloud - monsterBrain.AddPresetPower(211292); //slime spawn - break; - default: - break; + /* + [199476] Diablo_StompAndStun + [219598] Diablo_Teleport + [167560] Diablo_LightningBreath_v2 + [185997] Diablo_ExpandingFireRing + [169212] Diablo_Smash_Puny_Destructible + [136828] Diablo_CurseOfAnguish + [136829] Diablo_CurseOfPain + [136830] Diablo_CurseOfHate + [136831] Diablo_CurseOfDestruction + + [439719] Diablo_LightningBreath_LR_TerrorDemon_Clone + [214831] Diablo_FireMeteor + [161174] Diablo_CorruptionShield + [136219] Diablo_LightningBreath + [136223] Diablo_RingOfFire + [136226] Diablo_HellSpikes + + [214668] Diablo_GetHit + + [136237] Diablo_ShadowVanish + [136281] Diablo_ShadowClones + [142582] Diablo_ShadowVanish_Charge + [136849] Diablo_ShadowVanish_Grab + + [141865] Diablo_Phase1Buff + [136850] Diablo_Phase2Buff + [136852] Diablo_Phase3Buff + [478072] Diablo_StompAndStunMB313 + + [478410] Diablo_LightningBreath_Turret_MB313 + [195816] Diablo_Charge + [428985] Diablo_LightningBreath_LR_TerrorDemon + [376396] Uber_Gluttony_Gas_Cloud_Diablo + [375473] Uber_SkeletonKing_Summon_Skeleton_Diablo + [375493] Uber_Maghda_Summon_Beserker_Diablo + [365978] Uber_Diablo_StompAndStun + [375537] Uber_Despair_SummonMinion_Diablo + [375929] UberDiablo_MirrorImage + [376039] Uber_Despair_TeleportEnrage_Diablo + [376043] Uber_ZoltunKulle_SlowTime_Diablo + [376056] Uber_Despair_Volley_Diablo + [375439] x1_Uber_Diablo_HellSpikes + [375904] Diablo_LightningBreath_Uber + [375905] Diablo_ClawRip_Uber + [375907] Diablo_RingOfFire_Uber + [375908] Diablo_ExpandingFireRing_Uber + + [453765] p43_d1_Diablo_ClawRip + + [328715] x1_Malthael_Diablo_AIState + [334760] x1_Malthael_Diablo_TeleportFireNovaLightning + + + */ + break; + case ActorSno._skeletonking: //Leoric King + monsterBrain.RemovePresetPower(30592); + monsterBrain.AddPresetPower(30496); + monsterBrain.AddPresetPower(30504); + monsterBrain.AddPresetPower(73824); + monsterBrain.AddPresetPower(79334); + break; + case ActorSno._butcher: //Butcher + monsterBrain.AddPresetPower(83008); + break; + case ActorSno._belial_trueform: //Belial (small) + HasLoot = false; + break; + case ActorSno._belial: //Belial (big) + monsterBrain.AddPresetPower(152540); + break; + case ActorSno._maghda: //Maghda + monsterBrain.AddPresetPower(131744); //summon berserker + //(Brain as MonsterBrain).AddPresetPower(131745); //mothDust + monsterBrain.AddPresetPower(131749); //teleport + break; + case ActorSno._gluttony: //Gluttony + monsterBrain.AddPresetPower(93676); //gas cloud + monsterBrain.AddPresetPower(211292); //slime spawn + break; + default: + Logger.Warn($"Unhandled boss type {sno}"); + break; + } + } + else + { + Logger.Error($"Boss $[underline red]${GetType().Name}$[/]$ ({sno}) has no monster brain!"); } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Door.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Door.cs index 3bf4ada..4eca667 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Door.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/ActorSystem/Implementations/Door.cs @@ -16,7 +16,7 @@ using System.Threading.Tasks; namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations { [HandledSNO(ActorSno._caout_stingingwinds_khamsin_gate)] - class Door : Gizmo + public class Door : Gizmo { public bool isOpened = false; public Portal NearestPortal = null; @@ -75,12 +75,13 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations public void Open() { + Logger.MethodTrace($"Opening door $[underline green]${SNO}$[/]$ in world $[underline green]{World.SNO}$[/]$"); World.BroadcastIfRevealed(plr => new PlayAnimationMessage { ActorID = DynamicID(plr), AnimReason = 5, UnitAniimStartTime = 0, - tAnim = new PlayAnimationMessageSpec[] + tAnim = new[] { new PlayAnimationMessageSpec() { @@ -115,8 +116,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations TickerSystem.TickTimer Timeout = new TickerSystem.SecondsTickTimer(World.Game, 1.8f); if (NearestPortal != null) { - var Boom = Task.Factory.StartNew(() => WaitToSpawn(Timeout)); - Boom.ContinueWith(delegate + var nearestPortalOpen = Task.Factory.StartNew(() => WaitToSpawn(Timeout)); + nearestPortalOpen.ContinueWith(delegate { NearestPortal.SetVisible(true); foreach (var plr in World.Players.Values) diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs index 9b274c1..a2e744b 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/MapSystem/World.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Collections.Immutable; using System.Drawing; using System.Linq; using System.Reflection; @@ -1495,5 +1496,21 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem { return $"[World] SNOId: {WorldSNO.Id} GlobalId: {GlobalID} Name: {WorldSNO.Name}"; } + + public ImmutableArray GetAllDoors() => + Actors.Select(a => a.Value).Where(a => a is Door).Cast().ToImmutableArray(); + public ImmutableArray OpenAllDoors() + { + List openedDoors = new(); + var doors = GetAllDoors(); + + foreach (var door in doors) + { + openedDoors.Add(door); + door.Open(); + } + + return openedDoors.ToImmutableArray(); + } } } diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs index 45cd36c..2df5cf3 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/PlayerSystem/Player.cs @@ -3,6 +3,7 @@ using System; //Blizzless Project 2022 using System.Collections.Generic; +using System.Collections.Immutable; //Blizzless Project 2022 using System.Linq; //Blizzless Project 2022 @@ -6181,4 +6182,23 @@ public class Player : Actor, IMessageConsumer, IUpdateable Attributes[GameAttribute.Hitpoints_Total_From_Level] = Attributes[GameAttribute.Hitpoints_Max_Total]; Attributes.BroadcastChangedIfRevealed(); } + + public ImmutableArray GetNearDoors(float distance = 50f) + { + var doors = World.GetAllDoors(); + List doorList = doors.Where(door => door.Position.IsNear(Position, distance)).ToList(); + return doorList.ToImmutableArray(); + } + + public ImmutableArray OpenNearDoors(float distance = 50f) + { + List openedDoors = new(); + foreach (var door in GetNearDoors(distance)) + { + openedDoors.Add(door); + door.Open(); + } + + return openedDoors.ToImmutableArray(); + } } \ No newline at end of file diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs index b7e7361..8373087 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/ActI.cs @@ -1070,7 +1070,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem }); - ListenKill(ActorSno._skeletonking_shield_skeleton, 4, new Advance()); + ListenKill(ActorSno._skeletonking_shield_skeleton, 1, new Advance()); } }); @@ -1082,11 +1082,8 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem Objectives = new List { Objective.Default() }, OnAdvance = () => { //take crown on Leoric's head - Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () => - { - Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking); - }); - //Open(this.Game.GetWorld(73261), 172645); + + OpenAll(this.Game.GetWorld(WorldSno.a1trdun_king_level08)); ListenInteract(ActorSno._skeletonkinggizmo, 1, new Advance()); } }); @@ -1111,6 +1108,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem Objectives = new List { Objective.Default() }, OnAdvance = () => { //go to fallen star room + Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking); Game.CurrentEncounter.Activated = false; ListenTeleport(117411, new Advance()); Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () => diff --git a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs index 031ce79..c1ea0a0 100644 --- a/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs +++ b/src/DiIiS-NA/D3-GameServer/GSSystem/QuestSystem/QuestProgress.cs @@ -181,6 +181,13 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem (actor as Door).Open(); return true; } + + //opening all doors + protected void OpenAll(World world) + { + foreach (var actor in world.Actors.Select(s=>s.Value).Where(t=>t is Door).Cast()) + (actor).Open(); + } protected bool OpenAll(World world, ActorSno sno) {