Improvement world bosses;

Command to open all doors;
Do not show logs of colors
This commit is contained in:
Lucca Faria Ferri 2023-01-31 09:09:37 -08:00
parent b95ab45e62
commit 8c9dc3c9d5
10 changed files with 287 additions and 142 deletions

View File

@ -2,6 +2,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.IO; using System.IO;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
namespace DiIiS_NA.Core.Logging namespace DiIiS_NA.Core.Logging
@ -24,48 +25,55 @@ namespace DiIiS_NA.Core.Logging
/// <param name="reset">Reset log file on application startup?</param> /// <param name="reset">Reset log file on application startup?</param>
public FileTarget(string fileName, Logger.Level minLevel, Logger.Level maxLevel, bool includeTimeStamps, bool reset = false) public FileTarget(string fileName, Logger.Level minLevel, Logger.Level maxLevel, bool includeTimeStamps, bool reset = false)
{ {
this.MinimumLevel = minLevel; MinimumLevel = minLevel;
this.MaximumLevel = maxLevel; MaximumLevel = maxLevel;
this.IncludeTimeStamps = includeTimeStamps; IncludeTimeStamps = includeTimeStamps;
this._fileName = fileName; _fileName = fileName;
this._fileTimestamp = DateTime.Now.ToString("yyyyMMdd_HHmm"); _fileTimestamp = DateTime.Now.ToString("yyyy-MM-dd_HH-mm");
this._filePath = string.Format("{0}/{1}/{2}", LogConfig.Instance.LoggingRoot, this._fileTimestamp, _fileName); _filePath = $"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}/{_fileName}";
this._fileIndex = 0; _fileIndex = 0;
if (!Directory.Exists(LogConfig.Instance.LoggingRoot)) // create logging directory if it does not exist yet. if (!Directory.Exists(LogConfig.Instance.LoggingRoot)) // create logging directory if it does not exist yet.
Directory.CreateDirectory(LogConfig.Instance.LoggingRoot); 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. if (!Directory.Exists($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}")) // create logging directory if it does not exist yet.
Directory.CreateDirectory(string.Format("{0}/{1}", LogConfig.Instance.LoggingRoot, this._fileTimestamp)); Directory.CreateDirectory($"{LogConfig.Instance.LoggingRoot}/{_fileTimestamp}");
this._fileStream = new FileStream(_filePath, reset ? FileMode.Create : FileMode.Append, FileAccess.Write, FileShare.Read); // init the file stream. _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. _logStream = new StreamWriter(_fileStream) { AutoFlush = true }; // init the stream writer.
this.TaskQueue = new ConcurrentQueue<Action>(); TaskQueue = new ConcurrentQueue<Action>();
this.LoggerThread = new Thread(this.CheckQueue) { Name = "Logger", IsBackground = true }; LoggerThread = new Thread(CheckQueue) { Name = "Logger", IsBackground = true };
this.LoggerThread.Start(); LoggerThread.Start();
} }
public void CheckQueue() public void CheckQueue()
{ {
while (true) while (true)
{ {
Action action = null; if (TaskQueue.TryDequeue(out var action))
if (this.TaskQueue.TryDequeue(out action))
action.Invoke(); action.Invoke();
Thread.Sleep(1); Thread.Sleep(1);
} }
} }
/// <summary>
/// Replace the colors from AnsiColor so they do not appear in the log file.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
private string NoColors(string message) => Regex.Replace(message, @"\$\[[\w\W\d\s_\-\/]+\]\$", "");
/// <param name="level">Log level.</param> /// <param name="level">Log level.</param>
/// <param name="logger">Source of the log message.</param> /// <param name="logger">Source of the log message.</param>
/// <param name="message">Log message.</param> /// <param name="message">Log message.</param>
public override void LogMessage(Logger.Level level, string logger, string 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") + "] " : ""; message = NoColors(message);
if (!this._disposed) // make sure we're not disposed. 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 if (this._fileStream.Length >= 20971520) //20 MB limit
@ -77,9 +85,9 @@ namespace DiIiS_NA.Core.Logging
} }
//*/ //*/
if (level > Logger.Level.ChatMessage) 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 else
this._logStream.WriteLine(string.Format("{0}{1}", timeStamp, message)); _logStream.WriteLine($"{timeStamp}{message}");
} }
}); });
} }
@ -90,12 +98,13 @@ namespace DiIiS_NA.Core.Logging
/// <param name="exception">Exception to be included with log message.</param> /// <param name="exception">Exception to be included with log message.</param>
public override void LogException(Logger.Level level, string logger, string message, Exception exception) 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") + "] " : ""; message = NoColors(message);
if (!this._disposed) // make sure we're not disposed. 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}"); $"{timeStamp}[{level.ToString(),5}] [{logger}]: {message} - [Exception] {exception}");
} }
}); });
@ -109,23 +118,23 @@ namespace DiIiS_NA.Core.Logging
public void Dispose() public void Dispose()
{ {
Dispose(true); 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) 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. if (disposing) // only dispose managed resources if we're called from directly or in-directly from user code.
{ {
this._logStream.Close(); _logStream.Close();
this._logStream.Dispose(); _logStream.Dispose();
this._fileStream.Close(); _fileStream.Close();
this._fileStream.Dispose(); _fileStream.Dispose();
} }
this._logStream = null; _logStream = null;
this._fileStream = null; _fileStream = null;
_disposed = true; _disposed = true;
} }

View File

@ -16,6 +16,7 @@ using DiIiS_NA.LoginServer.Battle;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations;
using DiIiS_NA.GameServer.GSSystem.GameSystem; using DiIiS_NA.GameServer.GSSystem.GameSystem;
using DiIiS_NA.GameServer.GSSystem.ObjectsSystem; using DiIiS_NA.GameServer.GSSystem.ObjectsSystem;
using DiIiS_NA.GameServer.GSSystem.PlayerSystem; using DiIiS_NA.GameServer.GSSystem.PlayerSystem;
@ -25,6 +26,74 @@ using Actor = DiIiS_NA.Core.MPQ.FileFormats.Actor;
namespace DiIiS_NA.GameServer.CommandManager; 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.", [CommandGroup("powerful", "Makes your character with absurd amount of damage. Useful for testing.",
Account.UserLevels.Tester)] Account.UserLevels.Tester)]
public class PowerfulCommand : CommandGroup public class PowerfulCommand : CommandGroup

View File

@ -133,7 +133,25 @@ namespace DiIiS_NA.GameServer
get => GetInt(nameof(ResurrectionCharges), 3); get => GetInt(nameof(ResurrectionCharges), 3);
set => Set(nameof(ResurrectionCharges), value); set => Set(nameof(ResurrectionCharges), value);
} }
/// <summary>
/// Boss Health Multiplier
/// </summary>
public float BossHealthMultiplier
{
get => GetFloat(nameof(BossHealthMultiplier), 6f);
set => Set(nameof(BossHealthMultiplier), value);
}
/// <summary>
/// Boss Damage Multiplier
/// </summary>
public float BossDamageMultiplier
{
get => GetFloat(nameof(BossDamageMultiplier), 3f);
set => Set(nameof(BossDamageMultiplier), value);
}
public static Config Instance { get; } = new(); public static Config Instance { get; } = new();
private Config() : base("Game-Server") private Config() : base("Game-Server")

View File

@ -104,7 +104,7 @@ namespace DiIiS_NA.GameServer.Core.Types.Math
/// </summary> /// </summary>
/// <param name="point">the second <see cref="Vector3" /></param> /// <param name="point">the second <see cref="Vector3" /></param>
/// <returns>the distance squared between the vectors</returns> /// <returns>the distance squared between the vectors</returns>
public float DistanceSquared(ref Vector3D point) public float DistanceSquared(ref Vector3D point) // todo: remove ref
{ {
float x = point.X - X, float x = point.X - X,
y = point.Y - Y, 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 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 IsNear(Vector3D other, float distance) => DistanceSquared(ref other) < distance;
public bool IsNearSquared(Vector3D other, float distanceSquared) => DistanceSquared(ref other) < distanceSquared;
} }
} }

View File

@ -69,6 +69,7 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
public sealed class Boss : Monster public sealed class Boss : Monster
{ {
private static readonly Logger Logger = LogManager.CreateLogger(nameof(Boss)); private static readonly Logger Logger = LogManager.CreateLogger(nameof(Boss));
public Boss(MapSystem.World world, ActorSno sno, TagMap tags) public Boss(MapSystem.World world, ActorSno sno, TagMap tags)
: base(world, sno, tags) : base(world, sno, tags)
{ {
@ -77,106 +78,113 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
//this.Attributes[GameAttribute.Immune_To_Charm] = true; //this.Attributes[GameAttribute.Immune_To_Charm] = true;
Attributes[GameAttribute.using_Bossbar] = true; Attributes[GameAttribute.using_Bossbar] = true;
Attributes[GameAttribute.InBossEncounter] = true; Attributes[GameAttribute.InBossEncounter] = true;
Attributes[GameAttribute.Hitpoints_Max] *= 4f; Attributes[GameAttribute.Hitpoints_Max] *= Config.Instance.BossHealthMultiplier;
Attributes[GameAttribute.Damage_Weapon_Min, 0] *= 3f; Attributes[GameAttribute.Damage_Weapon_Min, 0] *= Config.Instance.BossDamageMultiplier;
Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= 3f; Attributes[GameAttribute.Damage_Weapon_Delta, 0] *= Config.Instance.BossDamageMultiplier;
Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total]; Attributes[GameAttribute.Hitpoints_Cur] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes[GameAttribute.TeamID] = 10; Attributes[GameAttribute.TeamID] = 10;
WalkSpeed *= 0.5f; WalkSpeed *= 0.5f;
MonsterBrain monsterBrain = (Brain as MonsterBrain); if (Brain is MonsterBrain monsterBrain)
switch (sno)
{ {
case ActorSno._diablo: //Diablo switch (sno)
//(Brain as MonsterBrain).RemovePresetPower(30592); {
//(Brain as MonsterBrain).AddPresetPower(136189); //[136189] Diablo_ClawRip case ActorSno._diablo: //Diablo
monsterBrain.AddPresetPower(136223); //Diablo_RingOfFire //(Brain as MonsterBrain).RemovePresetPower(30592);
monsterBrain.AddPresetPower(136226); //Diablo_HellSpikes //(Brain as MonsterBrain).AddPresetPower(136189); //[136189] Diablo_ClawRip
; monsterBrain.AddPresetPower(136223); //Diablo_RingOfFire
monsterBrain.AddPresetPower(136226); //Diablo_HellSpikes
;
/* /*
[199476] Diablo_StompAndStun [199476] Diablo_StompAndStun
[219598] Diablo_Teleport [219598] Diablo_Teleport
[167560] Diablo_LightningBreath_v2 [167560] Diablo_LightningBreath_v2
[185997] Diablo_ExpandingFireRing [185997] Diablo_ExpandingFireRing
[169212] Diablo_Smash_Puny_Destructible [169212] Diablo_Smash_Puny_Destructible
[136828] Diablo_CurseOfAnguish [136828] Diablo_CurseOfAnguish
[136829] Diablo_CurseOfPain [136829] Diablo_CurseOfPain
[136830] Diablo_CurseOfHate [136830] Diablo_CurseOfHate
[136831] Diablo_CurseOfDestruction [136831] Diablo_CurseOfDestruction
[439719] Diablo_LightningBreath_LR_TerrorDemon_Clone [439719] Diablo_LightningBreath_LR_TerrorDemon_Clone
[214831] Diablo_FireMeteor [214831] Diablo_FireMeteor
[161174] Diablo_CorruptionShield [161174] Diablo_CorruptionShield
[136219] Diablo_LightningBreath [136219] Diablo_LightningBreath
[136223] Diablo_RingOfFire [136223] Diablo_RingOfFire
[136226] Diablo_HellSpikes [136226] Diablo_HellSpikes
[214668] Diablo_GetHit [214668] Diablo_GetHit
[136237] Diablo_ShadowVanish [136237] Diablo_ShadowVanish
[136281] Diablo_ShadowClones [136281] Diablo_ShadowClones
[142582] Diablo_ShadowVanish_Charge [142582] Diablo_ShadowVanish_Charge
[136849] Diablo_ShadowVanish_Grab [136849] Diablo_ShadowVanish_Grab
[141865] Diablo_Phase1Buff [141865] Diablo_Phase1Buff
[136850] Diablo_Phase2Buff [136850] Diablo_Phase2Buff
[136852] Diablo_Phase3Buff [136852] Diablo_Phase3Buff
[478072] Diablo_StompAndStunMB313 [478072] Diablo_StompAndStunMB313
[478410] Diablo_LightningBreath_Turret_MB313 [478410] Diablo_LightningBreath_Turret_MB313
[195816] Diablo_Charge [195816] Diablo_Charge
[428985] Diablo_LightningBreath_LR_TerrorDemon [428985] Diablo_LightningBreath_LR_TerrorDemon
[376396] Uber_Gluttony_Gas_Cloud_Diablo [376396] Uber_Gluttony_Gas_Cloud_Diablo
[375473] Uber_SkeletonKing_Summon_Skeleton_Diablo [375473] Uber_SkeletonKing_Summon_Skeleton_Diablo
[375493] Uber_Maghda_Summon_Beserker_Diablo [375493] Uber_Maghda_Summon_Beserker_Diablo
[365978] Uber_Diablo_StompAndStun [365978] Uber_Diablo_StompAndStun
[375537] Uber_Despair_SummonMinion_Diablo [375537] Uber_Despair_SummonMinion_Diablo
[375929] UberDiablo_MirrorImage [375929] UberDiablo_MirrorImage
[376039] Uber_Despair_TeleportEnrage_Diablo [376039] Uber_Despair_TeleportEnrage_Diablo
[376043] Uber_ZoltunKulle_SlowTime_Diablo [376043] Uber_ZoltunKulle_SlowTime_Diablo
[376056] Uber_Despair_Volley_Diablo [376056] Uber_Despair_Volley_Diablo
[375439] x1_Uber_Diablo_HellSpikes [375439] x1_Uber_Diablo_HellSpikes
[375904] Diablo_LightningBreath_Uber [375904] Diablo_LightningBreath_Uber
[375905] Diablo_ClawRip_Uber [375905] Diablo_ClawRip_Uber
[375907] Diablo_RingOfFire_Uber [375907] Diablo_RingOfFire_Uber
[375908] Diablo_ExpandingFireRing_Uber [375908] Diablo_ExpandingFireRing_Uber
[453765] p43_d1_Diablo_ClawRip [453765] p43_d1_Diablo_ClawRip
[328715] x1_Malthael_Diablo_AIState [328715] x1_Malthael_Diablo_AIState
[334760] x1_Malthael_Diablo_TeleportFireNovaLightning [334760] x1_Malthael_Diablo_TeleportFireNovaLightning
*/ */
break; break;
case ActorSno._skeletonking://Leoric King case ActorSno._skeletonking: //Leoric King
monsterBrain.RemovePresetPower(30592); monsterBrain.RemovePresetPower(30592);
monsterBrain.AddPresetPower(30496); monsterBrain.AddPresetPower(30496);
monsterBrain.AddPresetPower(30504); monsterBrain.AddPresetPower(30504);
monsterBrain.AddPresetPower(73824); monsterBrain.AddPresetPower(73824);
monsterBrain.AddPresetPower(79334); monsterBrain.AddPresetPower(79334);
break; break;
case ActorSno._butcher://Butcher case ActorSno._butcher: //Butcher
monsterBrain.AddPresetPower(83008); monsterBrain.AddPresetPower(83008);
break; break;
case ActorSno._belial_trueform://Belial (small) case ActorSno._belial_trueform: //Belial (small)
HasLoot = false; HasLoot = false;
break; break;
case ActorSno._belial://Belial (big) case ActorSno._belial: //Belial (big)
monsterBrain.AddPresetPower(152540); monsterBrain.AddPresetPower(152540);
break; break;
case ActorSno._maghda://Maghda case ActorSno._maghda: //Maghda
monsterBrain.AddPresetPower(131744); //summon berserker monsterBrain.AddPresetPower(131744); //summon berserker
//(Brain as MonsterBrain).AddPresetPower(131745); //mothDust //(Brain as MonsterBrain).AddPresetPower(131745); //mothDust
monsterBrain.AddPresetPower(131749); //teleport monsterBrain.AddPresetPower(131749); //teleport
break; break;
case ActorSno._gluttony://Gluttony case ActorSno._gluttony: //Gluttony
monsterBrain.AddPresetPower(93676); //gas cloud monsterBrain.AddPresetPower(93676); //gas cloud
monsterBrain.AddPresetPower(211292); //slime spawn monsterBrain.AddPresetPower(211292); //slime spawn
break; break;
default: default:
break; Logger.Warn($"Unhandled boss type {sno}");
break;
}
}
else
{
Logger.Error($"Boss $[underline red]${GetType().Name}$[/]$ ({sno}) has no monster brain!");
} }
} }

View File

@ -16,7 +16,7 @@ using System.Threading.Tasks;
namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
{ {
[HandledSNO(ActorSno._caout_stingingwinds_khamsin_gate)] [HandledSNO(ActorSno._caout_stingingwinds_khamsin_gate)]
class Door : Gizmo public class Door : Gizmo
{ {
public bool isOpened = false; public bool isOpened = false;
public Portal NearestPortal = null; public Portal NearestPortal = null;
@ -75,12 +75,13 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
public void Open() public void Open()
{ {
Logger.MethodTrace($"Opening door $[underline green]${SNO}$[/]$ in world $[underline green]{World.SNO}$[/]$");
World.BroadcastIfRevealed(plr => new PlayAnimationMessage World.BroadcastIfRevealed(plr => new PlayAnimationMessage
{ {
ActorID = DynamicID(plr), ActorID = DynamicID(plr),
AnimReason = 5, AnimReason = 5,
UnitAniimStartTime = 0, UnitAniimStartTime = 0,
tAnim = new PlayAnimationMessageSpec[] tAnim = new[]
{ {
new PlayAnimationMessageSpec() new PlayAnimationMessageSpec()
{ {
@ -115,8 +116,8 @@ namespace DiIiS_NA.GameServer.GSSystem.ActorSystem.Implementations
TickerSystem.TickTimer Timeout = new TickerSystem.SecondsTickTimer(World.Game, 1.8f); TickerSystem.TickTimer Timeout = new TickerSystem.SecondsTickTimer(World.Game, 1.8f);
if (NearestPortal != null) if (NearestPortal != null)
{ {
var Boom = Task<bool>.Factory.StartNew(() => WaitToSpawn(Timeout)); var nearestPortalOpen = Task<bool>.Factory.StartNew(() => WaitToSpawn(Timeout));
Boom.ContinueWith(delegate nearestPortalOpen.ContinueWith(delegate
{ {
NearestPortal.SetVisible(true); NearestPortal.SetVisible(true);
foreach (var plr in World.Players.Values) foreach (var plr in World.Players.Values)

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
@ -1495,5 +1496,21 @@ namespace DiIiS_NA.GameServer.GSSystem.MapSystem
{ {
return $"[World] SNOId: {WorldSNO.Id} GlobalId: {GlobalID} Name: {WorldSNO.Name}"; return $"[World] SNOId: {WorldSNO.Id} GlobalId: {GlobalID} Name: {WorldSNO.Name}";
} }
public ImmutableArray<Door> GetAllDoors() =>
Actors.Select(a => a.Value).Where(a => a is Door).Cast<Door>().ToImmutableArray();
public ImmutableArray<Door> OpenAllDoors()
{
List<Door> openedDoors = new();
var doors = GetAllDoors();
foreach (var door in doors)
{
openedDoors.Add(door);
door.Open();
}
return openedDoors.ToImmutableArray();
}
} }
} }

View File

@ -3,6 +3,7 @@
using System; using System;
//Blizzless Project 2022 //Blizzless Project 2022
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable;
//Blizzless Project 2022 //Blizzless Project 2022
using System.Linq; using System.Linq;
//Blizzless Project 2022 //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[GameAttribute.Hitpoints_Total_From_Level] = Attributes[GameAttribute.Hitpoints_Max_Total];
Attributes.BroadcastChangedIfRevealed(); Attributes.BroadcastChangedIfRevealed();
} }
public ImmutableArray<Door> GetNearDoors(float distance = 50f)
{
var doors = World.GetAllDoors();
List<Door> doorList = doors.Where(door => door.Position.IsNear(Position, distance)).ToList();
return doorList.ToImmutableArray();
}
public ImmutableArray<Door> OpenNearDoors(float distance = 50f)
{
List<Door> openedDoors = new();
foreach (var door in GetNearDoors(distance))
{
openedDoors.Add(door);
door.Open();
}
return openedDoors.ToImmutableArray();
}
} }

View File

@ -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> { Objective.Default() }, Objectives = new List<Objective> { Objective.Default() },
OnAdvance = () => OnAdvance = () =>
{ //take crown on Leoric's head { //take crown on Leoric's head
Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () =>
{ OpenAll(this.Game.GetWorld(WorldSno.a1trdun_king_level08));
Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking);
});
//Open(this.Game.GetWorld(73261), 172645);
ListenInteract(ActorSno._skeletonkinggizmo, 1, new Advance()); ListenInteract(ActorSno._skeletonkinggizmo, 1, new Advance());
} }
}); });
@ -1111,6 +1108,7 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
Objectives = new List<Objective> { Objective.Default() }, Objectives = new List<Objective> { Objective.Default() },
OnAdvance = () => OnAdvance = () =>
{ //go to fallen star room { //go to fallen star room
Open(Game.GetWorld(WorldSno.a1trdun_king_level08), ActorSno._trdun_cath_gate_b_skeletonking);
Game.CurrentEncounter.Activated = false; Game.CurrentEncounter.Activated = false;
ListenTeleport(117411, new Advance()); ListenTeleport(117411, new Advance());
Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () => Game.AddOnLoadWorldAction(WorldSno.a1trdun_king_level08, () =>

View File

@ -181,6 +181,13 @@ namespace DiIiS_NA.GameServer.GSSystem.QuestSystem
(actor as Door).Open(); (actor as Door).Open();
return true; 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<Door>())
(actor).Open();
}
protected bool OpenAll(World world, ActorSno sno) protected bool OpenAll(World world, ActorSno sno)
{ {