From 7819830628ddc7ad8ab72b25897232e9c90e298d Mon Sep 17 00:00:00 2001
From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com>
Date: Sun, 9 May 2021 00:20:43 -0700
Subject: [PATCH] feat(champs): Ports Casiopia champions (#584)
---
.../Engines/CannedEvil/CannedEvilTimer.cs | 107 ++
.../Engines/CannedEvil/ChampionAltar.cs | 35 +-
.../Engines/CannedEvil/ChampionCommands.cs | 83 ++
.../Engines/CannedEvil/ChampionPlatform.cs | 40 +-
.../Engines/CannedEvil/ChampionSkull.cs | 42 +-
.../CannedEvil/ChampionSkullBrazier.cs | 72 +-
.../CannedEvil/ChampionSkullPlatform.cs | 34 +-
.../Engines/CannedEvil/ChampionSkullType.cs | 18 +-
.../Engines/CannedEvil/ChampionSpawn.cs | 1115 ++++++++++-------
.../Engines/CannedEvil/ChampionSpawnType.cs | 222 ++--
.../CannedEvil/DungeonChampionSpawn.cs | 54 +
.../Engines/CannedEvil/GenChampEntry.cs | 49 +
.../UOContent/Engines/CannedEvil/GenChamps.cs | 116 ++
.../Engines/CannedEvil/LLChampionSpawn.cs | 55 +
.../Engines/CannedEvil/RestartTimer.cs | 20 -
.../Engines/CannedEvil/SliceTimer.cs | 20 -
Projects/UOContent/Items/Food/Cooking.cs | 4 +-
.../Items/Weapons/Staves/ShepherdsCrook.cs | 2 +-
.../UOContent/Spells/Necromancy/Exorcism.cs | 4 +-
19 files changed, 1402 insertions(+), 690 deletions(-)
create mode 100644 Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionAltar.cs
create mode 100644 Projects/UOContent/Engines/CannedEvil/ChampionCommands.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionPlatform.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSkull.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSkullBrazier.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSkullPlatform.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSkullType.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs
mode change 100644 => 100755 Projects/UOContent/Engines/CannedEvil/ChampionSpawnType.cs
create mode 100644 Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs
create mode 100644 Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs
create mode 100644 Projects/UOContent/Engines/CannedEvil/GenChamps.cs
create mode 100644 Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs
delete mode 100644 Projects/UOContent/Engines/CannedEvil/RestartTimer.cs
delete mode 100644 Projects/UOContent/Engines/CannedEvil/SliceTimer.cs
diff --git a/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs b/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs
new file mode 100644
index 000000000..a708b5969
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/CannedEvilTimer.cs
@@ -0,0 +1,107 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: CannedEvilTimer.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using Server.Misc;
+
+namespace Server.Engines.CannedEvil
+{
+ public class CannedEvilTimer : Timer
+ {
+ public static void Initialize()
+ {
+ // TODO: Needs configuration
+ Instance = new CannedEvilTimer();
+ Instance.Start();
+ Instance.OnTick();
+ }
+
+ private static readonly HashSet _dungeonSpawns = new();
+ private static readonly HashSet _lostLandsSpawns = new();
+ private static DateTime _sliceTime;
+
+ public static CannedEvilTimer Instance { get; private set; }
+
+ public static void AddSpawn(DungeonChampionSpawn spawn)
+ {
+ _dungeonSpawns.Add(spawn);
+ Instance?.OnSlice(_dungeonSpawns, false);
+ }
+
+ public static void AddSpawn(LLChampionSpawn spawn)
+ {
+ _lostLandsSpawns.Add(spawn);
+ Instance?.OnSlice(_lostLandsSpawns, false);
+ }
+
+ public static void RemoveSpawn(DungeonChampionSpawn spawn)
+ {
+ _dungeonSpawns.Remove(spawn);
+ Instance?.OnSlice(_dungeonSpawns, false);
+ }
+
+ public static void RemoveSpawn(LLChampionSpawn spawn)
+ {
+ _lostLandsSpawns.Remove(spawn);
+ Instance?.OnSlice(_lostLandsSpawns, false);
+ }
+
+ public CannedEvilTimer() : base(TimeSpan.Zero, TimeSpan.FromMinutes(1.0))
+ {
+ Priority = TimerPriority.OneMinute;
+ _sliceTime = Core.Now;
+ }
+
+ public void OnSlice(ICollection list, bool rotate = true) where T : ChampionSpawn
+ {
+ if (list.Count > 0)
+ {
+ List valid = new List();
+
+ foreach (T spawn in list)
+ {
+ if (spawn.AlwaysActive && !spawn.Active)
+ {
+ spawn.ReadyToActivate = true;
+ }
+ else if (rotate && (!spawn.Active || spawn.Kills == 0 && spawn.Level == 0))
+ {
+ spawn.Active = false;
+ spawn.ReadyToActivate = false;
+
+ valid.Add(spawn);
+ }
+ }
+
+ if (valid.Count > 0)
+ {
+ valid[Utility.Random(valid.Count)].ReadyToActivate = true;
+ }
+ }
+ }
+
+ protected override void OnTick()
+ {
+ if (!AutoRestart.Restarting && Core.Now >= _sliceTime)
+ {
+ OnSlice(_dungeonSpawns);
+ OnSlice(_lostLandsSpawns);
+
+ _sliceTime = Core.Now.Date + TimeSpan.FromDays(1.0);
+ }
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionAltar.cs b/Projects/UOContent/Engines/CannedEvil/ChampionAltar.cs
old mode 100644
new mode 100755
index afc5c9cb0..4094d4fd2
--- a/Projects/UOContent/Engines/CannedEvil/ChampionAltar.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionAltar.cs
@@ -1,22 +1,37 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionAltar.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using Server.Items;
namespace Server.Engines.CannedEvil
{
public class ChampionAltar : PentagramAddon
{
- private ChampionSpawn m_Spawn;
+ public ChampionSpawn Spawn { get; private set; }
- public ChampionAltar(ChampionSpawn spawn) => m_Spawn = spawn;
-
- public ChampionAltar(Serial serial) : base(serial)
- {
- }
+ public ChampionAltar(ChampionSpawn spawn) => Spawn = spawn;
public override void OnAfterDelete()
{
base.OnAfterDelete();
- m_Spawn?.Delete();
+ Spawn?.Delete();
+ }
+
+ public ChampionAltar(Serial serial) : base(serial)
+ {
}
public override void Serialize(IGenericWriter writer)
@@ -25,7 +40,7 @@ namespace Server.Engines.CannedEvil
writer.Write(0); // version
- writer.Write(m_Spawn);
+ writer.Write(Spawn);
}
public override void Deserialize(IGenericReader reader)
@@ -38,9 +53,9 @@ namespace Server.Engines.CannedEvil
{
case 0:
{
- m_Spawn = reader.ReadEntity();
+ Spawn = reader.ReadEntity();
- if (m_Spawn == null)
+ if (Spawn == null)
{
Delete();
}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionCommands.cs b/Projects/UOContent/Engines/CannedEvil/ChampionCommands.cs
new file mode 100644
index 000000000..a3a3d7e59
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionCommands.cs
@@ -0,0 +1,83 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionCommands.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+using Server.Targeting;
+
+namespace Server.Engines.CannedEvil
+{
+ public static class ChampionCommands
+ {
+ public static void Initialize()
+ {
+ CommandSystem.Register("ClearChampByTarget", AccessLevel.Administrator, KillByTarget_OnCommand);
+ CommandSystem.Register("ClearChampByRegion", AccessLevel.Administrator, KillByRegion_OnCommand);
+ }
+
+ [Usage("ClearChampByTarget")]
+ [Description("Kills all minions of a champion spawn.")]
+ private static void KillByTarget_OnCommand(CommandEventArgs e)
+ {
+ e.Mobile.Target = new KillTarget();
+ e.Mobile.SendMessage("Which champion spawn would you like to clear?");
+ }
+
+ private class KillTarget : Target
+ {
+ public KillTarget() : base(15, false, TargetFlags.None)
+ {
+ }
+
+ protected override void OnTarget(Mobile from, object targ)
+ {
+ if (from == null || from.AccessLevel < AccessLevel.Administrator)
+ {
+ return;
+ }
+
+ ChampionSpawn spawn = targ switch
+ {
+ ChampionSpawn championSpawn => championSpawn,
+ IdolOfTheChampion champion => champion.Spawn,
+ ChampionAltar altar => altar.Spawn,
+ ChampionPlatform platform => platform.Spawn,
+ _ => null
+ };
+
+ if (spawn == null)
+ {
+ from.SendMessage("That is not a valid target. Please target the champion, altar, platform, or idol.");
+ }
+
+ spawn?.DeleteCreatures();
+ spawn?.Champion?.Delete();
+ }
+ }
+
+ [Usage("ClearChampByRegion")]
+ [Description("Kills all minions of a champion spawn.")]
+ private static void KillByRegion_OnCommand(CommandEventArgs e)
+ {
+ if (e.Mobile.Region is ChampionSpawnRegion { Spawn: { } } region)
+ {
+ region.Spawn.DeleteCreatures();
+ region.Spawn.Champion?.Delete();
+ }
+ else
+ {
+ e.Mobile.SendMessage("You are not in a champion spawn region.");
+ }
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionPlatform.cs b/Projects/UOContent/Engines/CannedEvil/ChampionPlatform.cs
old mode 100644
new mode 100755
index 690c2926d..c68bd16bc
--- a/Projects/UOContent/Engines/CannedEvil/ChampionPlatform.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionPlatform.cs
@@ -1,14 +1,29 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionPlatform.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using Server.Items;
namespace Server.Engines.CannedEvil
{
public class ChampionPlatform : BaseAddon
{
- private ChampionSpawn m_Spawn;
+ public ChampionSpawn Spawn { get; private set; }
public ChampionPlatform(ChampionSpawn spawn)
{
- m_Spawn = spawn;
+ Spawn = spawn;
for (var x = -2; x <= 2; ++x)
{
@@ -41,16 +56,9 @@ namespace Server.Engines.CannedEvil
AddComponent(0x75C, 2, -2, 0);
}
- public ChampionPlatform(Serial serial) : base(serial)
- {
- }
-
public void AddComponent(int id, int x, int y, int z)
{
- var ac = new AddonComponent(id);
-
- ac.Hue = 0x497;
-
+ AddonComponent ac = new AddonComponent(id) { Hue = 0x497 };
AddComponent(ac, x, y, z);
}
@@ -58,7 +66,11 @@ namespace Server.Engines.CannedEvil
{
base.OnAfterDelete();
- m_Spawn?.Delete();
+ Spawn?.Delete();
+ }
+
+ public ChampionPlatform(Serial serial) : base(serial)
+ {
}
public override void Serialize(IGenericWriter writer)
@@ -67,7 +79,7 @@ namespace Server.Engines.CannedEvil
writer.Write(0); // version
- writer.Write(m_Spawn);
+ writer.Write(Spawn);
}
public override void Deserialize(IGenericReader reader)
@@ -80,9 +92,9 @@ namespace Server.Engines.CannedEvil
{
case 0:
{
- m_Spawn = reader.ReadEntity();
+ Spawn = reader.ReadEntity();
- if (m_Spawn == null)
+ if (Spawn == null)
{
Delete();
}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSkull.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSkull.cs
old mode 100644
new mode 100755
index 6d4159c29..37fa7d0db
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSkull.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSkull.cs
@@ -1,3 +1,18 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSkull.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using Server.Engines.CannedEvil;
namespace Server.Items
@@ -6,6 +21,19 @@ namespace Server.Items
{
private ChampionSkullType m_Type;
+ [CommandProperty(AccessLevel.GameMaster)]
+ public ChampionSkullType Type
+ {
+ get => m_Type;
+ set
+ {
+ m_Type = value;
+ InvalidateProperties();
+ }
+ }
+
+ public override int LabelNumber => 1049479 + (int)m_Type;
+
[Constructible]
public ChampionSkull(ChampionSkullType type) : base(0x1AE1)
{
@@ -28,19 +56,6 @@ namespace Server.Items
{
}
- [CommandProperty(AccessLevel.GameMaster)]
- public ChampionSkullType Type
- {
- get => m_Type;
- set
- {
- m_Type = value;
- InvalidateProperties();
- }
- }
-
- public override int LabelNumber => 1049479 + (int)m_Type;
-
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
@@ -62,7 +77,6 @@ namespace Server.Items
case 0:
{
m_Type = (ChampionSkullType)reader.ReadInt();
-
break;
}
}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSkullBrazier.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSkullBrazier.cs
old mode 100644
new mode 100755
index ca96884c2..70b6fcef2
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSkullBrazier.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSkullBrazier.cs
@@ -1,26 +1,28 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSkullBrazier.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using Server.Items;
-using Server.Mobiles;
using Server.Targeting;
+using Server.Mobiles;
namespace Server.Engines.CannedEvil
{
public class ChampionSkullBrazier : AddonComponent
{
- private Item m_Skull;
private ChampionSkullType m_Type;
-
- public ChampionSkullBrazier(ChampionSkullPlatform platform, ChampionSkullType type) : base(0x19BB)
- {
- Hue = 0x455;
- Light = LightType.Circle300;
-
- Platform = platform;
- m_Type = type;
- }
-
- public ChampionSkullBrazier(Serial serial) : base(serial)
- {
- }
+ private Item m_Skull;
[CommandProperty(AccessLevel.GameMaster)]
public ChampionSkullPlatform Platform { get; private set; }
@@ -49,6 +51,19 @@ namespace Server.Engines.CannedEvil
public override int LabelNumber => 1049489 + (int)m_Type;
+ public ChampionSkullBrazier(ChampionSkullPlatform platform, ChampionSkullType type) : base(0x19BB)
+ {
+ Hue = 0x455;
+ Light = LightType.Circle300;
+
+ Platform = platform;
+ m_Type = type;
+ }
+
+ public ChampionSkullBrazier(Serial serial) : base(serial)
+ {
+ }
+
public override void OnDoubleClick(Mobile from)
{
Platform?.Validate();
@@ -63,7 +78,7 @@ namespace Server.Engines.CannedEvil
return;
}
- if (m_Skull?.Deleted == true)
+ if (m_Skull is { Deleted: true })
{
Skull = null;
}
@@ -94,7 +109,7 @@ namespace Server.Engines.CannedEvil
return;
}
- if (m_Skull?.Deleted == true)
+ if (m_Skull is { Deleted: true })
{
Skull = null;
}
@@ -135,6 +150,17 @@ namespace Server.Engines.CannedEvil
}
}
+ private class SacrificeTarget : Target
+ {
+ private readonly ChampionSkullBrazier m_Brazier;
+
+ public SacrificeTarget(ChampionSkullBrazier brazier) : base(12, false, TargetFlags.None) =>
+ m_Brazier = brazier;
+
+ protected override void OnTarget(Mobile from, object targeted) =>
+ m_Brazier.EndSacrifice(from, targeted as ChampionSkull);
+ }
+
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
@@ -179,17 +205,5 @@ namespace Server.Engines.CannedEvil
Light = LightType.Circle300;
}
}
-
- private class SacrificeTarget : Target
- {
- private readonly ChampionSkullBrazier m_Brazier;
-
- public SacrificeTarget(ChampionSkullBrazier brazier) : base(12, false, TargetFlags.None) => m_Brazier = brazier;
-
- protected override void OnTarget(Mobile from, object targeted)
- {
- m_Brazier.EndSacrifice(from, targeted as ChampionSkull);
- }
- }
}
}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSkullPlatform.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSkullPlatform.cs
old mode 100644
new mode 100755
index 4c0902dfe..c6a3b2814
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSkullPlatform.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSkullPlatform.cs
@@ -1,3 +1,18 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSkullPlatform.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using Server.Items;
using Server.Mobiles;
@@ -38,23 +53,16 @@ namespace Server.Engines.CannedEvil
AddComponent(new AddonComponent(0x50F), 0, 1, 4);
AddComponent(m_Death = new ChampionSkullBrazier(this, ChampionSkullType.Death), 0, 1, 5);
- AddonComponent comp = new LocalizedAddonComponent(0x20D2, 1049495);
- comp.Hue = 0x482;
+ AddonComponent comp = new LocalizedAddonComponent(0x20D2, 1049495) { Hue = 0x482 };
AddComponent(comp, 0, 0, 5);
- comp = new LocalizedAddonComponent(0x0BCF, 1049496);
- comp.Hue = 0x482;
+ comp = new LocalizedAddonComponent(0x0BCF, 1049496) { Hue = 0x482 };
AddComponent(comp, 0, 2, -7);
- comp = new LocalizedAddonComponent(0x0BD0, 1049497);
- comp.Hue = 0x482;
+ comp = new LocalizedAddonComponent(0x0BD0, 1049497) { Hue = 0x482 };
AddComponent(comp, 2, 0, -7);
}
- public ChampionSkullPlatform(Serial serial) : base(serial)
- {
- }
-
public void Validate()
{
if (Validate(m_Power) && Validate(m_Enlightenment) && Validate(m_Venom) && Validate(m_Pain) &&
@@ -86,7 +94,11 @@ namespace Server.Engines.CannedEvil
}
}
- public bool Validate(ChampionSkullBrazier brazier) => brazier?.Skull?.Deleted == false;
+ public bool Validate(ChampionSkullBrazier brazier) => brazier is { Skull: { Deleted: false } };
+
+ public ChampionSkullPlatform(Serial serial) : base(serial)
+ {
+ }
public override void Serialize(IGenericWriter writer)
{
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSkullType.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSkullType.cs
old mode 100644
new mode 100755
index e48f02292..fe6f48b0b
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSkullType.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSkullType.cs
@@ -1,3 +1,18 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSkullType.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
namespace Server.Engines.CannedEvil
{
public enum ChampionSkullType
@@ -7,6 +22,7 @@ namespace Server.Engines.CannedEvil
Venom,
Pain,
Greed,
- Death
+ Death,
+ None
}
}
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs
old mode 100644
new mode 100755
index 6923057bf..96f21ecdf
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSpawn.cs
@@ -1,38 +1,78 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSpawn.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using System;
+using System.Net;
using System.Collections.Generic;
using Server.Gumps;
using Server.Items;
using Server.Mobiles;
using Server.Regions;
-using Server.Utilities;
namespace Server.Engines.CannedEvil
{
public class ChampionSpawn : Item
{
- private const int Level1 = 4; // First spawn level from 0-4 red skulls
- private const int Level2 = 8; // Second spawn level from 5-8 red skulls
- private const int Level3 = 12; // Third spawn level from 9-12 red skulls
-
private bool m_Active;
- private ChampionAltar m_Altar;
+ private ChampionSpawnType m_Type;
private List m_Creatures;
-
- private Dictionary m_DamageEntries;
-
- private IdolOfTheChampion m_Idol;
- private int m_Kills;
- private ChampionPlatform m_Platform;
private List- m_RedSkulls;
+ private List
- m_WhiteSkulls;
+ private ChampionPlatform m_Platform;
+ private ChampionAltar m_Altar;
+ private int m_Kills;
+ private int m_MaxLevel;
+ private int m_Level;
+
+ //private int m_SpawnRange;
+ private Rectangle2D m_SpawnArea;
private ChampionSpawnRegion m_Region;
- // private int m_SpawnRange;
- private Rectangle2D m_SpawnArea;
- private int m_SPawnSzMod;
+ //Goes back each level, below level 0 and it goes off!
- private Timer m_Timer, m_RestartTimer;
- private ChampionSpawnType m_Type;
- private List
- m_WhiteSkulls;
+ private Timer m_Timer;
+
+ private IdolOfTheChampion m_Idol;
+
+ public virtual string BroadcastMessage => "The Champion has sensed your presence! Beware its wrath!";
+ public virtual bool ProximitySpawn => false;
+ public virtual bool CanAdvanceByValor => true;
+ public virtual bool CanActivateByValor => true;
+ public virtual bool AlwaysActive => false;
+
+ public override TimeSpan DecayTime => TimeSpan.FromSeconds(180.0);
+
+ public virtual bool HasStarRoomGate => true;
+
+ public Dictionary DamageEntries { get; private set; }
+
+ public Timer RestartTimer { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool ConfinedRoaming { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool HasBeenAdvanced { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Point3D EjectLocation { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public Map EjectMap { get; set; }
+
+ public override int LabelNumber => 1041030; // Evil in a Can: Don't delete me!
[Constructible]
public ChampionSpawn() : base(0xBD2)
@@ -48,31 +88,32 @@ namespace Server.Engines.CannedEvil
m_Altar = new ChampionAltar(this);
m_Idol = new IdolOfTheChampion(this);
- ExpireDelay = TimeSpan.FromMinutes(10.0);
- RestartDelay = TimeSpan.FromMinutes(10.0);
+ ExpireDelay = TimeSpan.FromMinutes(30.0);
+ RestartDelay = TimeSpan.FromMinutes(30.0);
+ DamageEntries = new Dictionary();
- m_DamageEntries = new Dictionary();
-
- Timer.DelayCall(SetInitialSpawnArea);
+ Timer.DelayCall(TimeSpan.Zero, SetInitialSpawnArea);
}
- public ChampionSpawn(Serial serial) : base(serial)
+ public void SetInitialSpawnArea()
{
+ //Previous default used to be 24;
+ SpawnArea = new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24));
}
- [CommandProperty(AccessLevel.GameMaster)]
- public int SpawnSzMod
+ public virtual ChampionSpawnRegion GetRegion() => new(this);
+
+ public void UpdateRegion()
{
- get => m_SPawnSzMod < 1 || m_SPawnSzMod > 12 ? 12 : m_SPawnSzMod;
- set => m_SPawnSzMod = value < 1 || value > 12 ? 12 : value;
+ m_Region?.Unregister();
+
+ if (!Deleted && Map != Map.Internal)
+ {
+ m_Region = GetRegion();
+ m_Region.Register();
+ }
}
- [CommandProperty(AccessLevel.GameMaster)]
- public bool ConfinedRoaming { get; set; }
-
- [CommandProperty(AccessLevel.GameMaster)]
- public bool HasBeenAdvanced { get; set; }
-
[CommandProperty(AccessLevel.GameMaster)]
public bool RandomizeType { get; set; }
@@ -83,6 +124,15 @@ namespace Server.Engines.CannedEvil
set
{
m_Kills = value;
+
+ double n = m_Kills / (double)MaxKills;
+ int p = (int)(n * 100);
+
+ if (p < 90)
+ {
+ SetWhiteSkullCount(p / 20);
+ }
+
InvalidateProperties();
}
}
@@ -141,83 +191,80 @@ namespace Server.Engines.CannedEvil
}
}
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool ReadyToActivate { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool ActivatedByValor { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public bool ActivatedByProximity { get; set; }
+
+ [CommandProperty(AccessLevel.GameMaster)]
+ public DateTime NextProximityTime { get; set; }
+
[CommandProperty(AccessLevel.GameMaster)]
public Mobile Champion { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int Level
{
- get => m_RedSkulls.Count;
+ get => m_Level;
set
{
- for (var i = m_RedSkulls.Count - 1; i >= value; --i)
+ for (int i = m_RedSkulls.Count - 1; i >= value; --i)
{
m_RedSkulls[i].Delete();
m_RedSkulls.RemoveAt(i);
}
- for (var i = m_RedSkulls.Count; i < value; ++i)
+ for (int i = m_RedSkulls.Count; i < Math.Min(value, 16); ++i)
{
- var skull = new Item(0x1854);
-
- skull.Hue = 0x26;
- skull.Movable = false;
- skull.Light = LightType.Circle150;
-
+ Item skull = new Item(0x1854) { Hue = 0x26, Movable = false, Light = LightType.Circle150 };
skull.MoveToWorld(GetRedSkullLocation(i), Map);
-
m_RedSkulls.Add(skull);
}
+ m_Level = value;
+
InvalidateProperties();
}
}
- public int MaxKills => m_SPawnSzMod * (250 / 12) - Level * m_SPawnSzMod;
-
- public void SetInitialSpawnArea()
- {
- // Previous default used to be 24;
- SpawnArea = new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24));
- }
-
- public void UpdateRegion()
- {
- m_Region?.Unregister();
-
- if (!Deleted && Map != Map.Internal)
- {
- m_Region = new ChampionSpawnRegion(this);
- m_Region.Register();
- }
-
- /*
- if (m_Region == null)
- {
- m_Region = new ChampionSpawnRegion( this );
- }
- else
- {
- m_Region.Unregister();
- //Why doesn't Region allow me to set it's map/Area myself? ><
- m_Region = new ChampionSpawnRegion( this );
- }
- */
+ [CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
+ public int MaxLevel{ get => m_MaxLevel;
+ set => m_MaxLevel = Math.Max(Math.Min(value, 18), 0);
}
public bool IsChampionSpawn(Mobile m) => m_Creatures.Contains(m);
+ [CommandProperty(AccessLevel.GameMaster)]
+ public virtual int MaxKills
+ {
+ get
+ {
+ return Level switch
+ {
+ >= 16 => 16,
+ >= 12 => 32,
+ >= 8 => 64,
+ >= 4 => 128,
+ _ => 256
+ };
+ }
+ }
+
public void SetWhiteSkullCount(int val)
{
- for (var i = m_WhiteSkulls.Count - 1; i >= val; --i)
+ for (int i = m_WhiteSkulls.Count - 1; i >= val; --i)
{
m_WhiteSkulls[i].Delete();
m_WhiteSkulls.RemoveAt(i);
}
- for (var i = m_WhiteSkulls.Count; i < val; ++i)
+ for (int i = m_WhiteSkulls.Count; i < val; ++i)
{
- var skull = new Item(0x1854);
+ Item skull = new Item(0x1854);
skull.Movable = false;
skull.Light = LightType.Circle150;
@@ -238,77 +285,6 @@ namespace Server.Engines.CannedEvil
return;
}
- m_Active = true;
- HasBeenAdvanced = false;
-
- m_Timer?.Stop();
-
- m_Timer = new SliceTimer(this);
- m_Timer.Start();
-
- m_RestartTimer?.Stop();
-
- m_RestartTimer = null;
-
- if (m_Altar != null)
- {
- if (Champion != null)
- {
- m_Altar.Hue = 0x26;
- }
- else
- {
- m_Altar.Hue = 0;
- }
- }
-
- if (m_Platform != null)
- {
- m_Platform.Hue = 0x452;
- }
- }
-
- public void Stop()
- {
- if (!m_Active || Deleted)
- {
- return;
- }
-
- m_Active = false;
- HasBeenAdvanced = false;
-
- m_Timer?.Stop();
-
- m_Timer = null;
-
- m_RestartTimer?.Stop();
-
- m_RestartTimer = null;
-
- if (m_Altar != null)
- {
- m_Altar.Hue = 0;
- }
-
- if (m_Platform != null)
- {
- m_Platform.Hue = 0x497;
- }
- }
-
- public void BeginRestart(TimeSpan ts)
- {
- m_RestartTimer?.Stop();
-
- RestartTime = Core.Now + ts;
-
- m_RestartTimer = new RestartTimer(this, ts);
- m_RestartTimer.Start();
- }
-
- public void EndRestart()
- {
if (RandomizeType)
{
Type = Utility.Random(5) switch
@@ -322,63 +298,136 @@ namespace Server.Engines.CannedEvil
};
}
+ m_Active = true;
+ ReadyToActivate = false;
HasBeenAdvanced = false;
+ m_MaxLevel = 16 + Utility.Random(3);
- Start();
- }
+ m_Timer?.Stop();
- private ScrollofTranscendence CreateRandomSoT(bool felucca)
- {
- var level = Utility.RandomMinMax(1, 5);
+ m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), OnSlice);
+ m_Timer.Start();
- if (felucca)
+ RestartTimer?.Stop();
+ RestartTimer = null;
+
+ if (m_Altar != null)
{
- level += 5;
+ m_Altar.Hue = Champion != null ? 0x26 : 0;
}
- return ScrollofTranscendence.CreateRandom(level, level);
+ if (m_Platform != null)
+ {
+ m_Platform.Hue = 0x452;
+ }
+
+ ExpireTime = Core.Now + ExpireDelay;
}
- public static void GiveScrollTo(Mobile killer, SpecialScroll scroll)
+ public void Stop()
{
- if (scroll == null || killer == null) // sanity
+ if (!m_Active || Deleted)
{
return;
}
- if (scroll is ScrollofTranscendence)
+ m_Active = false;
+ ActivatedByValor = false;
+ HasBeenAdvanced = false;
+ m_MaxLevel = 0;
+
+ m_Timer?.Stop();
+
+ m_Timer = null;
+
+ RestartTimer?.Stop();
+ RestartTimer = null;
+
+ if (m_Altar != null)
{
- killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence!
+ m_Altar.Hue = 0;
}
- else
+
+ if (m_Platform != null)
{
- killer.SendLocalizedMessage(1049524); // You have received a scroll of power!
+ m_Platform.Hue = 0x497;
}
+ if (AlwaysActive)
+ {
+ BeginRestart(RestartDelay);
+ }
+ else if (ActivatedByProximity)
+ {
+ ActivatedByProximity = false;
+ NextProximityTime = Core.Now + TimeSpan.FromHours(6.0);
+ }
+
+ Timer.DelayCall(TimeSpan.FromMinutes(10.0), ExpireCreatures);
+ }
+
+ public void BeginRestart(TimeSpan ts)
+ {
+ RestartTimer?.Stop();
+
+ RestartTime = Core.Now + ts;
+
+ RestartTimer = Timer.DelayCall(ts, EndRestart);
+ RestartTimer.Start();
+ }
+
+ public void EndRestart()
+ {
+ HasBeenAdvanced = false;
+ ReadyToActivate = true;
+ }
+
+ private ScrollofTranscendence CreateRandomTramSoT()
+ {
+ int level = Utility.Random(5) + 1;
+ return ScrollofTranscendence.CreateRandom(level, level);
+ }
+
+ private ScrollofTranscendence CreateRandomFelSoT()
+ {
+ int level = Utility.Random(5) + 1;
+ return ScrollofTranscendence.CreateRandom(level, level);
+ }
+
+ private static PowerScroll CreateRandomFelPS() => PowerScroll.CreateRandomNoCraft(5, 5);
+
+ public static void GiveScrollOfTranscendenceFelTo (Mobile killer, ScrollofTranscendence SoTF)
+ {
+ if (SoTF == null || killer == null) //sanity
+ {
+ return;
+ }
+
+ killer.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence!
+
if (killer.Alive)
{
- killer.AddToBackpack(scroll);
+ killer.AddToBackpack(SoTF);
}
else
{
- if (killer.Corpse.Deleted == false)
+ if (killer.Corpse is { Deleted: false })
{
- killer.Corpse.DropItem(scroll);
+ killer.Corpse.DropItem(SoTF);
}
else
{
- killer.AddToBackpack(scroll);
+ killer.AddToBackpack(SoTF);
}
}
+
// Justice reward
var pm = (PlayerMobile)killer;
for (var j = 0; j < pm.JusticeProtectors.Count; ++j)
{
- var prot = pm.JusticeProtectors[j];
-
- if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal ||
- !JusticeVirtue.CheckMapRegion(killer, prot))
+ Mobile prot = pm.JusticeProtectors[j];
+ if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot))
{
continue;
}
@@ -393,22 +442,58 @@ namespace Server.Engines.CannedEvil
if (chance > Utility.Random(100))
{
- try
- {
- var scrollDupe = scroll.GetType().CreateEntityInstance();
+ prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
+ ScrollofTranscendence SoTFduplicate = new ScrollofTranscendence (SoTF.Skill, SoTF.Value);
+ prot.AddToBackpack(SoTFduplicate);
+ }
+ }
+ }
- if (scrollDupe != null)
- {
- prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
- scrollDupe.Skill = scroll.Skill;
- scrollDupe.Value = scroll.Value;
- prot.AddToBackpack(scrollDupe);
- }
- }
- catch
- {
- // ignored
- }
+ public static void GivePowerScrollFelTo (Mobile killer, PowerScroll PS)
+ {
+ if (PS == null || killer == null) //sanity
+ {
+ return;
+ }
+
+ killer.SendLocalizedMessage(1049524); // You have received a scroll of power!
+
+ if (killer.Alive)
+ {
+ killer.AddToBackpack(PS);
+ }
+ else if (killer.Corpse is { Deleted: false })
+ {
+ killer.Corpse.DropItem(PS);
+ }
+ else
+ {
+ killer.AddToBackpack(PS);
+ }
+
+ // Justice reward
+ var pm = (PlayerMobile)killer;
+ for (var j = 0; j < pm.JusticeProtectors.Count; ++j)
+ {
+ Mobile prot = pm.JusticeProtectors[j];
+ if (prot.Map != killer.Map || prot.Kills >= 5 || prot.Criminal || !JusticeVirtue.CheckMapRegion(killer, prot))
+ {
+ continue;
+ }
+
+ var chance = VirtueHelper.GetLevel(prot, VirtueName.Justice) switch
+ {
+ VirtueLevel.Seeker => 60,
+ VirtueLevel.Follower => 80,
+ VirtueLevel.Knight => 100,
+ _ => 0
+ };
+
+ if (chance > Utility.Random(100))
+ {
+ prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
+ //PowerScroll PSduplicate = new PowerScroll (PS.Skill, PS.Value);
+ prot.AddToBackpack(CreateRandomFelPS());
}
}
}
@@ -426,12 +511,10 @@ namespace Server.Engines.CannedEvil
{
RegisterDamageTo(Champion);
- if (Champion is BaseChampion champion)
- {
- AwardArtifact(champion.GetArtifact());
- }
+ //if (m_Champion is BaseChampion)
+ // AwardArtifact(((BaseChampion)m_Champion).GetArtifact());
- m_DamageEntries.Clear();
+ DamageEntries.Clear();
if (m_Platform != null)
{
@@ -442,7 +525,7 @@ namespace Server.Engines.CannedEvil
{
m_Altar.Hue = 0;
- if (!Core.ML || Map == Map.Felucca)
+ if (HasStarRoomGate && (!Core.ML || Map == Map.Felucca))
{
new StarRoomGate(m_Altar.Location, m_Altar.Map, true);
}
@@ -450,21 +533,19 @@ namespace Server.Engines.CannedEvil
Champion = null;
Stop();
-
- BeginRestart(RestartDelay);
}
}
else
{
- var kills = m_Kills;
+ int kills = m_Kills;
for (var i = 0; i < m_Creatures.Count; ++i)
{
- var m = m_Creatures[i];
+ Mobile m = m_Creatures[i];
if (m.Deleted)
{
- if (m.Corpse?.Deleted == false)
+ if (m.Corpse is { Deleted: false })
{
((Corpse)m.Corpse).BeginDecay(TimeSpan.FromMinutes(1));
}
@@ -473,13 +554,13 @@ namespace Server.Engines.CannedEvil
--i;
++m_Kills;
- var killer = m.FindMostRecentDamager(false);
+ Mobile killer = m.FindMostRecentDamager(false);
RegisterDamageTo(m);
- if (killer is BaseCreature bc)
+ if (killer is BaseCreature creature)
{
- killer = bc.GetMaster();
+ killer = creature.GetMaster();
}
if (killer is PlayerMobile pm)
@@ -490,39 +571,39 @@ namespace Server.Engines.CannedEvil
{
if (Utility.RandomDouble() < 0.001)
{
- double random = Utility.Random(49);
+ double random = Utility.Random (49);
if (random <= 24)
{
- var SoTF = CreateRandomSoT(true);
- GiveScrollTo(pm, SoTF);
+ ScrollofTranscendence SoTF = CreateRandomFelSoT();
+ GiveScrollOfTranscendenceFelTo (pm, SoTF);
}
else
{
- var PS = PowerScroll.CreateRandomNoCraft(5, 5);
- GiveScrollTo(pm, PS);
+ PowerScroll PS = CreateRandomFelPS();
+ GivePowerScrollFelTo (pm, PS);
}
}
}
- if (Map == Map.Ilshenar || Map == Map.Tokuno || Map == Map.Malas)
+ if (Map == Map.Ilshenar || Map == Map.Tokuno)
{
if (Utility.RandomDouble() < 0.0015)
{
pm.SendLocalizedMessage(1094936); // You have received a Scroll of Transcendence!
- var SoTT = CreateRandomSoT(false);
+ ScrollofTranscendence SoTT = CreateRandomTramSoT();
pm.AddToBackpack(SoTT);
}
}
}
- var mobSubLevel = GetSubLevelFor(m) + 1;
+ int mobSubLevel = GetSubLevelfor (m) + 1;
if (mobSubLevel >= 0)
{
- var gainedPath = false;
+ bool gainedPath = false;
- var pointsToGain = mobSubLevel * 40;
+ int pointsToGain = mobSubLevel * 40;
if (VirtueHelper.Award(pm, VirtueName.Valor, pointsToGain, ref gainedPath))
{
@@ -535,10 +616,10 @@ namespace Server.Engines.CannedEvil
m.SendLocalizedMessage(1054030); // You have gained in Valor!
}
- // No delay on Valor gains
+ //No delay on Valor gains
}
- var info = pm.ChampionTitles;
+ ChampionTitleInfo info = pm.ChampionTitles;
info.Award(m_Type, mobSubLevel);
}
@@ -552,10 +633,10 @@ namespace Server.Engines.CannedEvil
InvalidateProperties();
}
- var n = m_Kills / (double)MaxKills;
- var p = (int)(n * 100);
+ double n = m_Kills / (double)MaxKills;
+ int p = (int)(n * 100);
- if (p >= 90)
+ if (p >= 99)
{
AdvanceLevel();
}
@@ -577,7 +658,7 @@ namespace Server.Engines.CannedEvil
{
ExpireTime = Core.Now + ExpireDelay;
- if (Level < 16)
+ if (Level < m_MaxLevel)
{
m_Kills = 0;
++Level;
@@ -587,12 +668,7 @@ namespace Server.Engines.CannedEvil
if (m_Altar != null)
{
Effects.PlaySound(m_Altar.Location, m_Altar.Map, 0x29);
- Effects.SendLocationEffect(
- new Point3D(m_Altar.X + 1, m_Altar.Y + 1, m_Altar.Z),
- m_Altar.Map,
- 0x3728,
- 10
- );
+ Effects.SendLocationEffect(new Point3D(m_Altar.X + 1, m_Altar.Y + 1, m_Altar.Z), m_Altar.Map, 0x3728, 10);
}
}
else
@@ -620,16 +696,48 @@ namespace Server.Engines.CannedEvil
try
{
- Champion = ChampionSpawnInfo.GetInfo(m_Type).Champion.CreateInstance();
- }
- catch
- {
- // ignored
+ Champion = Activator.CreateInstance(ChampionSpawnInfo.GetInfo(m_Type).Champion) as Mobile;
}
+ catch (Exception e)
+ { Console.WriteLine($"Exception creating champion {m_Type}: {e}"); }
- Champion?.MoveToWorld(new Point3D(X, Y, Z - 15), Map);
+ if (Champion != null)
+ {
+ Champion.MoveToWorld(new Point3D(X, Y, Z - 15), Map);
+
+ if (Champion is BaseCreature bc)
+ {
+ if (ConfinedRoaming)
+ {
+ bc.Home = Location;
+ bc.HomeMap = Map;
+ bc.RangeHome = Math.Min(m_SpawnArea.Width / 2, m_SpawnArea.Height / 2);
+ }
+ else
+ {
+ bc.Home = bc.Location;
+ bc.HomeMap = bc.Map;
+
+ Point2D xWall1 = new Point2D(m_SpawnArea.X, bc.Y);
+ Point2D xWall2 = new Point2D(m_SpawnArea.X + m_SpawnArea.Width, bc.Y);
+ Point2D yWall1 = new Point2D(bc.X, m_SpawnArea.Y);
+ Point2D yWall2 = new Point2D(bc.X, m_SpawnArea.Y + m_SpawnArea.Height);
+
+ double minXDist = Math.Min(bc.GetDistanceToSqrt(xWall1), bc.GetDistanceToSqrt(xWall2));
+ double minYDist = Math.Min(bc.GetDistanceToSqrt(yWall1), bc.GetDistanceToSqrt(yWall2));
+
+ bc.RangeHome = (int)Math.Min(minXDist, minYDist);
+ }
+ }
+ else
+ {
+ throw new Exception("Champion Spawn is not inherited from BaseCreature");
+ }
+ }
}
+ public virtual int MaxSpawn => 250 - GetSubLevel() * 40;
+
public void Respawn()
{
if (!m_Active || Deleted || Champion != null)
@@ -637,16 +745,16 @@ namespace Server.Engines.CannedEvil
return;
}
- while (m_Creatures.Count < m_SPawnSzMod * (200 / 12) - GetSubLevel() * m_SPawnSzMod * (40 / 12))
+ while (m_Creatures.Count < MaxSpawn)
{
- var m = Spawn();
+ Mobile m = Spawn();
if (m == null)
{
return;
}
- var loc = GetSpawnLocation();
+ Point3D loc = GetSpawnLocation();
// Allow creatures to turn into Paragons at Ilshenar champions.
m.OnBeforeSpawn(loc, Map);
@@ -658,26 +766,24 @@ namespace Server.Engines.CannedEvil
{
bc.Tamable = false;
- if (!ConfinedRoaming)
+ if (ConfinedRoaming)
{
bc.Home = Location;
- bc.RangeHome =
- (int)(Math.Sqrt(
- m_SpawnArea.Width * m_SpawnArea.Width +
- m_SpawnArea.Height * m_SpawnArea.Height
- ) / 2);
+ bc.HomeMap = Map;
+ bc.RangeHome = Math.Min(m_SpawnArea.Width / 2, m_SpawnArea.Height / 2);
}
else
{
bc.Home = bc.Location;
+ bc.HomeMap = bc.Map;
- var xWall1 = new Point2D(m_SpawnArea.X, bc.Y);
- var xWall2 = new Point2D(m_SpawnArea.X + m_SpawnArea.Width, bc.Y);
- var yWall1 = new Point2D(bc.X, m_SpawnArea.Y);
- var yWall2 = new Point2D(bc.X, m_SpawnArea.Y + m_SpawnArea.Height);
+ Point2D xWall1 = new Point2D(m_SpawnArea.X, bc.Y);
+ Point2D xWall2 = new Point2D(m_SpawnArea.X + m_SpawnArea.Width, bc.Y);
+ Point2D yWall1 = new Point2D(bc.X, m_SpawnArea.Y);
+ Point2D yWall2 = new Point2D(bc.X, m_SpawnArea.Y + m_SpawnArea.Height);
- var minXDist = Math.Min(bc.GetDistanceToSqrt(xWall1), bc.GetDistanceToSqrt(xWall2));
- var minYDist = Math.Min(bc.GetDistanceToSqrt(yWall1), bc.GetDistanceToSqrt(yWall2));
+ double minXDist = Math.Min(bc.GetDistanceToSqrt(xWall1), bc.GetDistanceToSqrt(xWall2));
+ double minYDist = Math.Min(bc.GetDistanceToSqrt(yWall1), bc.GetDistanceToSqrt(yWall2));
bc.RangeHome = (int)Math.Min(minXDist, minYDist);
}
@@ -687,7 +793,7 @@ namespace Server.Engines.CannedEvil
public Point3D GetSpawnLocation()
{
- var map = Map;
+ Map map = Map;
if (map == null)
{
@@ -695,65 +801,43 @@ namespace Server.Engines.CannedEvil
}
// Try 20 times to find a spawnable location.
- for (var i = 0; i < 20; i++)
+ for (int i = 0; i < 20; i++)
{
- /*
- int x = Location.X + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange);
- int y = Location.Y + (Utility.Random( (m_SpawnRange * 2) + 1 ) - m_SpawnRange);
- */
+ int x = Utility.Random(m_SpawnArea.X, m_SpawnArea.Width);
+ int y = Utility.Random(m_SpawnArea.Y, m_SpawnArea.Height);
- var x = Utility.Random(m_SpawnArea.X, m_SpawnArea.Width);
- var y = Utility.Random(m_SpawnArea.Y, m_SpawnArea.Height);
-
- var z = Map.GetAverageZ(x, y);
+ int z = Map.GetAverageZ(x, y);
if (Map.CanSpawnMobile(new Point2D(x, y), z))
{
return new Point3D(x, y, z);
}
-
- /* try @ platform Z if map z fails */
- if (Map.CanSpawnMobile(new Point2D(x, y), m_Platform.Location.Z))
- {
- return new Point3D(x, y, m_Platform.Location.Z);
- }
}
return Location;
}
+ public int Level1 => 4;
+ public int Level2 => 8;
+ public int Level3 => 12;
+
public int GetSubLevel()
{
- var level = Level;
+ int level = Level;
- if (level <= Level1)
- {
- return 0;
- }
-
- if (level <= Level2)
- {
- return 1;
- }
-
- if (level <= Level3)
- {
- return 2;
- }
-
- return 3;
+ return level <= Level1 ? 0 : level <= Level2 ? 1 : level <= Level3 ? 2 : 3;
}
- public int GetSubLevelFor(Mobile m)
+ public int GetSubLevelfor (Mobile m)
{
- var types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
- var t = m.GetType();
+ Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
+ Type t = m.GetType();
- for (var i = 0; i < types.GetLength(0); i++)
+ for (int i = 0; i < types.GetLength(0); i++)
{
- var individualTypes = types[i];
+ Type[] individualTypes = types[i];
- for (var j = 0; j < individualTypes.Length; j++)
+ for (int j = 0; j < individualTypes.Length; j++)
{
if (t == individualTypes[j])
{
@@ -767,9 +851,9 @@ namespace Server.Engines.CannedEvil
public Mobile Spawn()
{
- var types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
+ Type[][] types = ChampionSpawnInfo.GetInfo(m_Type).SpawnTypes;
- var v = GetSubLevel();
+ int v = GetSubLevel();
if (v >= 0 && v < types.Length)
{
@@ -783,7 +867,7 @@ namespace Server.Engines.CannedEvil
{
try
{
- return types.RandomElement().CreateInstance();
+ return Activator.CreateInstance(types[Utility.Random(types.Length)]) as Mobile;
}
catch
{
@@ -804,6 +888,11 @@ namespace Server.Engines.CannedEvil
--Level;
}
+ if (!AlwaysActive && Level == 0)
+ {
+ Stop();
+ }
+
InvalidateProperties();
}
else
@@ -846,24 +935,12 @@ namespace Server.Engines.CannedEvil
{
int x, y;
- switch (index)
+ switch(index)
{
- default:
- x = -1;
- y = -1;
- break;
- case 1:
- x = 1;
- y = -1;
- break;
- case 2:
- x = 1;
- y = 1;
- break;
- case 3:
- x = -1;
- y = 1;
- break;
+ default: x = -1; y = -1; break;
+ case 1: x = 1; y = -1; break;
+ case 2: x = 1; y = 1; break;
+ case 3: x = -1; y = 1; break;
}
return new Point3D(X + x, Y + y, Z - 15);
@@ -880,17 +957,11 @@ namespace Server.Engines.CannedEvil
if (m_Active)
{
- list.Add(1060742); // active
+ list.Add(1060742); // active
list.Add(1060658, "Type\t{0}", m_Type); // ~1_val~: ~2_val~
list.Add(1060659, "Level\t{0}", Level); // ~1_val~: ~2_val~
-
- list.Add(
- 1060660, // ~1_val~: ~2_val~
- "Kills\t{0} of {1} ({2:0.#}%)",
- m_Kills,
- MaxKills,
- 100.0 * ((double)m_Kills / MaxKills)
- );
+ list.Add(1060660, "Kills\t{0} of {1} ({2:F1}%)", m_Kills, MaxKills, 100.0 * ((double)m_Kills / MaxKills)); // ~1_val~: ~2_val~
+ //list.Add(1060661, "Spawn Range\t{0}", m_SpawnRange); // ~1_val~: ~2_val~
}
else
{
@@ -939,7 +1010,7 @@ namespace Server.Engines.CannedEvil
if (m_RedSkulls != null)
{
- for (var i = 0; i < m_RedSkulls.Count; ++i)
+ for (var i = 0; i < Math.Min(m_RedSkulls.Count, 16); ++i)
{
m_RedSkulls[i].Location = GetRedSkullLocation(i);
}
@@ -947,7 +1018,7 @@ namespace Server.Engines.CannedEvil
if (m_WhiteSkulls != null)
{
- for (var i = 0; i < m_WhiteSkulls.Count; ++i)
+ for (int i = 0; i < m_WhiteSkulls.Count; ++i)
{
m_WhiteSkulls[i].Location = GetWhiteSkullLocation(i);
}
@@ -983,7 +1054,7 @@ namespace Server.Engines.CannedEvil
if (m_RedSkulls != null)
{
- for (var i = 0; i < m_RedSkulls.Count; ++i)
+ for (int i = 0; i < m_RedSkulls.Count; ++i)
{
m_RedSkulls[i].Map = Map;
}
@@ -991,7 +1062,7 @@ namespace Server.Engines.CannedEvil
if (m_WhiteSkulls != null)
{
- for (var i = 0; i < m_WhiteSkulls.Count; ++i)
+ for (int i = 0; i < m_WhiteSkulls.Count; ++i)
{
m_WhiteSkulls[i].Map = Map;
}
@@ -1012,7 +1083,7 @@ namespace Server.Engines.CannedEvil
if (m_RedSkulls != null)
{
- for (var i = 0; i < m_RedSkulls.Count; ++i)
+ for (int i = 0; i < m_RedSkulls.Count; ++i)
{
m_RedSkulls[i].Delete();
}
@@ -1022,7 +1093,7 @@ namespace Server.Engines.CannedEvil
if (m_WhiteSkulls != null)
{
- for (var i = 0; i < m_WhiteSkulls.Count; ++i)
+ for (int i = 0; i < m_WhiteSkulls.Count; ++i)
{
m_WhiteSkulls[i].Delete();
}
@@ -1030,22 +1101,9 @@ namespace Server.Engines.CannedEvil
m_WhiteSkulls.Clear();
}
- if (m_Creatures != null)
- {
- for (var i = 0; i < m_Creatures.Count; ++i)
- {
- var mob = m_Creatures[i];
+ DeleteCreatures();
- if (!mob.Player)
- {
- mob.Delete();
- }
- }
-
- m_Creatures.Clear();
- }
-
- if (Champion?.Player == false)
+ if (Champion is { Player: false })
{
Champion.Delete();
}
@@ -1055,6 +1113,36 @@ namespace Server.Engines.CannedEvil
UpdateRegion();
}
+ public void ExpireCreatures()
+ {
+ if (!m_Active && !ReadyToActivate && !AlwaysActive)
+ {
+ DeleteCreatures();
+ }
+ }
+
+ public void DeleteCreatures()
+ {
+ if (m_Creatures != null)
+ {
+ for (int i = 0; i < m_Creatures.Count; ++i)
+ {
+ Mobile mob = m_Creatures[i];
+
+ if (!mob.Player)
+ {
+ mob.Delete();
+ }
+ }
+
+ m_Creatures.Clear();
+ }
+ }
+
+ public ChampionSpawn(Serial serial) : base(serial)
+ {
+ }
+
public virtual void RegisterDamageTo(Mobile m)
{
if (m == null)
@@ -1062,16 +1150,15 @@ namespace Server.Engines.CannedEvil
return;
}
- foreach (var de in m.DamageEntries)
+ foreach (DamageEntry de in m.DamageEntries)
{
if (de.HasExpired)
{
continue;
}
- var damager = de.Damager;
-
- var master = damager.GetDamageMaster(m);
+ Mobile damager = de.Damager;
+ Mobile master = damager.GetDamageMaster(m);
if (master != null)
{
@@ -1084,85 +1171,123 @@ namespace Server.Engines.CannedEvil
public void RegisterDamage(Mobile from, int amount)
{
- if (from?.Player != true)
+ if (@from?.Player != true)
{
return;
}
- m_DamageEntries[from] = amount + (m_DamageEntries.TryGetValue(from, out var value) ? value : 0);
+ if (DamageEntries.ContainsKey(from))
+ {
+ DamageEntries[from] += amount;
+ }
+ else
+ {
+ DamageEntries.Add(from, amount);
+ }
}
- public void AwardArtifact(Item artifact)
+ public virtual void AwardArtifact(Item artifact)
{
if (artifact == null)
{
return;
}
- var totalDamage = 0;
-
- var validEntries = new Dictionary();
-
- foreach (var kvp in m_DamageEntries)
+ if (DamageEntries.Count > 0)
{
- if (IsEligible(kvp.Key, artifact))
+ int totalDamage = 0;
+
+ Dictionary validEntries = new Dictionary();
+
+ foreach (var (key, value) in DamageEntries)
{
- validEntries.Add(kvp.Key, kvp.Value);
- totalDamage += kvp.Value;
+ if (IsEligible(key, artifact))
+ {
+ validEntries.Add(key, value);
+ totalDamage += value;
+ }
}
- }
- var randomDamage = Utility.RandomMinMax(1, totalDamage);
+ bool artifactGiven = false;
- totalDamage = 0;
-
- foreach (var kvp in validEntries)
- {
- totalDamage += kvp.Value;
-
- if (totalDamage >= randomDamage)
+ do
{
- GiveArtifact(kvp.Key, artifact);
- return;
+ int randomDamage = Utility.RandomMinMax(1, totalDamage);
+
+ int checkDamage = 0;
+
+ foreach (var (key, value) in validEntries)
+ {
+ checkDamage += value;
+
+ if (checkDamage > randomDamage)
+ {
+ if (GiveArtifact(key, artifact))
+ {
+ artifactGiven = true;
+ }
+ else
+ {
+ validEntries.Remove(key);
+ }
+
+ break;
+ }
+ }
+
+ if (validEntries.Count == 0) //EVERYONE has a full backpack?!@
+ {
+ artifact.Delete();
+ break;
+ }
}
- }
-
- artifact.Delete();
- }
-
- public void GiveArtifact(Mobile to, Item artifact)
- {
- if (to == null || artifact == null)
- {
- return;
- }
-
- var pack = to.Backpack;
-
- if (pack?.TryDropItem(to, artifact, false) != true)
- {
- artifact.Delete();
+ while (!artifactGiven);
}
else
{
- // For your valor in combating the fallen beast, a special artifact has been bestowed on you.
- to.SendLocalizedMessage(1062317);
+ artifact.Delete();
}
}
- public bool IsEligible(Mobile m, Item artifact) =>
+ public bool GiveArtifact(Mobile to, Item artifact)
+ {
+ if (to == null || artifact == null)
+ {
+ return false;
+ }
+
+ Container pack = to.Backpack;
+
+ if (pack?.TryDropItem(to, artifact, false) != true)
+ {
+ return false;
+ }
+
+ to.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you.
+ return true;
+ }
+
+ public bool IsEligible(Mobile m, Item Artifact) =>
m.Player && m.Alive && m.Region != null && m.Region == m_Region &&
- m.Backpack?.CheckHold(m, artifact, false) == true;
+ m.Backpack?.CheckHold(m, Artifact, false) == true;
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
- writer.Write(6); // version
+ writer.Write(9); // version
- writer.Write(m_SPawnSzMod);
- writer.Write(m_DamageEntries.Count);
- foreach (var kvp in m_DamageEntries)
+ writer.Write(m_Level);
+
+ writer.Write(ActivatedByProximity);
+ writer.WriteDeltaTime(NextProximityTime);
+
+ writer.Write(m_MaxLevel); //This can change, based on how you use the champion spawn
+
+ writer.Write(ActivatedByValor);
+
+ writer.Write(DamageEntries.Count);
+ foreach (KeyValuePair kvp in DamageEntries)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value);
@@ -1175,16 +1300,12 @@ namespace Server.Engines.CannedEvil
writer.Write(RandomizeType);
- // writer.Write( m_SpawnRange );
writer.Write(m_Kills);
writer.Write(m_Active);
writer.Write((int)m_Type);
- m_Creatures.Tidy();
writer.Write(m_Creatures);
- m_RedSkulls.Tidy();
writer.Write(m_RedSkulls);
- m_WhiteSkulls.Tidy();
writer.Write(m_WhiteSkulls);
writer.Write(m_Platform);
writer.Write(m_Altar);
@@ -1193,9 +1314,9 @@ namespace Server.Engines.CannedEvil
writer.Write(Champion);
writer.Write(RestartDelay);
- writer.Write(m_RestartTimer != null);
+ writer.Write(RestartTimer != null);
- if (m_RestartTimer != null)
+ if (RestartTimer != null)
{
writer.WriteDeltaTime(RestartTime);
}
@@ -1205,33 +1326,53 @@ namespace Server.Engines.CannedEvil
{
base.Deserialize(reader);
- m_DamageEntries = new Dictionary();
+ DamageEntries = new Dictionary();
- var version = reader.ReadInt();
+ int version = reader.ReadInt();
- switch (version)
+ switch(version)
{
+ case 9:
+ {
+ m_Level = reader.ReadInt();
+
+ goto case 8;
+ }
+ case 8:
+ {
+ ActivatedByProximity = reader.ReadBool();
+ NextProximityTime = reader.ReadDeltaTime();
+ goto case 7;
+ }
+ case 7:
+ {
+ m_MaxLevel = reader.ReadInt();
+ goto case 6;
+ }
case 6:
{
- m_SPawnSzMod = reader.ReadInt();
+ if (version < 7)
+ {
+ m_MaxLevel = 16 + Utility.Random(3); //full levels
+ }
+
+ ActivatedByValor = reader.ReadBool();
goto case 5;
}
case 5:
{
- var entries = reader.ReadInt();
- for (var i = 0; i < entries; ++i)
+ int entries = reader.ReadInt();
+ Mobile m;
+ int damage;
+ for (int i = 0; i < entries; ++i)
{
- var m = reader.ReadEntity();
- var damage = reader.ReadInt();
-
- if (m == null)
+ m = reader.ReadEntity();
+ damage = reader.ReadInt();
+ if (m != null)
{
- continue;
+ DamageEntries.Add(m, damage);
}
-
- m_DamageEntries.Add(m, damage);
}
-
goto case 4;
}
case 4:
@@ -1258,12 +1399,9 @@ namespace Server.Engines.CannedEvil
{
if (version < 3)
{
- var oldRange = reader.ReadInt();
+ int oldRange = reader.ReadInt();
- m_SpawnArea = new Rectangle2D(
- new Point2D(X - oldRange, Y - oldRange),
- new Point2D(X + oldRange, Y + oldRange)
- );
+ m_SpawnArea = new Rectangle2D(new Point2D(X - oldRange, Y - oldRange), new Point2D(X + oldRange, Y + oldRange));
}
m_Kills = reader.ReadInt();
@@ -1274,11 +1412,10 @@ namespace Server.Engines.CannedEvil
{
if (version < 1)
{
- m_SpawnArea =
- new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24)); // Default was 24
+ m_SpawnArea = new Rectangle2D(new Point2D(X - 24, Y - 24), new Point2D(X + 24, Y + 24)); //Default was 24
}
- var active = reader.ReadBool();
+ bool active = reader.ReadBool();
m_Type = (ChampionSpawnType)reader.ReadInt();
m_Creatures = reader.ReadEntityList();
m_RedSkulls = reader.ReadEntityList
- ();
@@ -1310,57 +1447,163 @@ namespace Server.Engines.CannedEvil
{
Start();
}
+ else if (AlwaysActive)
+ {
+ ReadyToActivate = true;
+ }
break;
}
}
- Timer.DelayCall(UpdateRegion);
+ Timer.DelayCall(TimeSpan.Zero, UpdateRegion);
}
}
public class ChampionSpawnRegion : BaseRegion
{
- public ChampionSpawnRegion(ChampionSpawn spawn) : base(
- null,
- spawn.Map,
- Find(spawn.Location, spawn.Map),
- spawn.SpawnArea
- ) =>
- ChampionSpawn = spawn;
+ public ChampionSpawn Spawn { get; }
- public override bool YoungProtected => false;
-
- public ChampionSpawn ChampionSpawn { get; }
+ public ChampionSpawnRegion(ChampionSpawn spawn) :
+ base(null, spawn.Map, Find(spawn.Location, spawn.Map), spawn.SpawnArea) => Spawn = spawn;
public override bool AllowHousing(Mobile from, Point3D p) => false;
+ public bool CanSpawn() => Spawn.EjectLocation != new Point3D(0, 0, 0) && Spawn.EjectMap != null;
+
public override void AlterLightLevel(Mobile m, ref int global, ref int personal)
{
base.AlterLightLevel(m, ref global, ref personal);
+ global = Math.Max(global, 1 + Spawn.Level); //This is a guesstimate. TODO: Verify & get exact values // OSI testing: at 2 red skulls, light = 0x3 ; 1 red = 0x3.; 3 = 8; 9 = 0xD 8 = 0xD 12 = 0x12 10 = 0xD
+ }
- // TODO: Verify & get exact values
- // OSI testing: at 2 red skulls, light = 0x3 ; 1 red = 0x3.; 3 = 8; 9 = 0xD 8 = 0xD 12 = 0x12 10 = 0xD
- global = Math.Max(global, 1 + ChampionSpawn.Level);
+ public override void OnEnter(Mobile m)
+ {
+ if (m.Player && m.AccessLevel == AccessLevel.Player && !Spawn.Active)
+ {
+ Region parent = Parent ?? this;
+
+ if (Spawn.ReadyToActivate)
+ {
+ Spawn.Start();
+ }
+ else if (Spawn.ProximitySpawn && !Spawn.ActivatedByProximity && Core.Now >= Spawn.NextProximityTime)
+ {
+ List players = parent.GetPlayers();
+ List addresses = new List();
+ for (var i = 0; i < players.Count; i++)
+ {
+ if (players[i].AccessLevel == AccessLevel.Player && players[i].NetState != null &&
+ !addresses.Contains(players[i].NetState.Address) && !((PlayerMobile)players[i]).Young)
+ {
+ addresses.Add(players[i].NetState.Address);
+ }
+ }
+
+ if (addresses.Count >= 15)
+ {
+ foreach (Mobile player in players)
+ {
+ player.SendMessage(0x20, Spawn.BroadcastMessage);
+ }
+
+ Spawn.ActivatedByProximity = true;
+ Spawn.BeginRestart(TimeSpan.FromMinutes(5.0));
+ }
+ }
+ }
+ }
+
+ public override bool OnMoveInto(Mobile m, Direction d, Point3D newLocation, Point3D oldLocation)
+ {
+ if (base.OnMoveInto(m, d, newLocation, oldLocation))
+ {
+ if (m.Player)
+ {
+ if (((PlayerMobile)m).Young)
+ {
+ m.SendMessage("You decide against going here because of the danger.");
+ }
+ else if (!m.Alive)
+ {
+ m.SendMessage("A magical force prevents ghosts from entering this region.");
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public override bool OnBeforeDeath(Mobile m)
+ {
+ if (Parent?.OnBeforeDeath(m) == false)
+ {
+ return false;
+ }
+
+ if (m.Player) //Give them 5 minutes to resurrect, then they are booted.
+ {
+ m.SendMessage("A magical force encompasses you, attempting to force you out of the area.");
+ new EjectTimer(m, this).Start();
+ }
+
+ return true;
+ }
+
+ private class EjectTimer : Timer
+ {
+ private readonly Mobile m_From;
+ private readonly ChampionSpawnRegion m_Region;
+
+ public EjectTimer(Mobile from, ChampionSpawnRegion region) : base(TimeSpan.FromMinutes(5.0))
+ {
+ m_From = from;
+ m_Region = region;
+ }
+
+ protected override void OnTick()
+ {
+ //See if they are dead, or logged out!
+ if (m_Region.Spawn != null && m_Region.CanSpawn() && !m_From.Alive)
+ {
+ if (m_From.NetState != null)
+ {
+ if (m_From.Region.IsPartOf(m_Region))
+ {
+ m_From.MoveToWorld(m_Region.Spawn.EjectLocation, m_Region.Spawn.EjectMap);
+ m_From.SendMessage("A magical force forces you out of the area.");
+ }
+ }
+ else if (Find(m_From.LogoutLocation, m_From.LogoutMap).IsPartOf(m_Region))
+ {
+ m_From.LogoutLocation = m_Region.Spawn.EjectLocation;
+ m_From.LogoutMap = m_Region.Spawn.EjectMap;
+ }
+ }
+ }
}
}
public class IdolOfTheChampion : Item
{
- public IdolOfTheChampion(ChampionSpawn spawn) : base(0x1F18)
+ public ChampionSpawn Spawn { get; private set; }
+
+ public override string DefaultName => "Idol of the Champion";
+
+ public IdolOfTheChampion(ChampionSpawn spawn): base(0x1F18)
{
Spawn = spawn;
Movable = false;
}
- public IdolOfTheChampion(Serial serial) : base(serial)
- {
- }
-
- public ChampionSpawn Spawn { get; private set; }
-
- public override string DefaultName => "Idol of the Champion";
-
public override void OnAfterDelete()
{
base.OnAfterDelete();
@@ -1368,6 +1611,10 @@ namespace Server.Engines.CannedEvil
Spawn?.Delete();
}
+ public IdolOfTheChampion(Serial serial) : base(serial)
+ {
+ }
+
public override void Serialize(IGenericWriter writer)
{
base.Serialize(writer);
@@ -1381,7 +1628,7 @@ namespace Server.Engines.CannedEvil
{
base.Deserialize(reader);
- var version = reader.ReadInt();
+ int version = reader.ReadInt();
switch (version)
{
diff --git a/Projects/UOContent/Engines/CannedEvil/ChampionSpawnType.cs b/Projects/UOContent/Engines/CannedEvil/ChampionSpawnType.cs
old mode 100644
new mode 100755
index c6d999dc0..e1c70d7b9
--- a/Projects/UOContent/Engines/CannedEvil/ChampionSpawnType.cs
+++ b/Projects/UOContent/Engines/CannedEvil/ChampionSpawnType.cs
@@ -1,3 +1,18 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: ChampionSpawnType.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
using System;
using Server.Mobiles;
@@ -13,19 +28,12 @@ namespace Server.Engines.CannedEvil
UnholyTerror,
SleepingDragon,
Glade,
- Pestilence
+ Pestilence,
+ Graveyard
}
public class ChampionSpawnInfo
{
- public ChampionSpawnInfo(string name, Type champion, string[] levelNames, Type[][] spawnTypes)
- {
- Name = name;
- Champion = champion;
- LevelNames = levelNames;
- SpawnTypes = spawnTypes;
- }
-
public string Name { get; }
public Type Champion { get; }
@@ -34,131 +42,81 @@ namespace Server.Engines.CannedEvil
public string[] LevelNames { get; }
- public static ChampionSpawnInfo[] Table { get; } =
+ public ChampionSpawnInfo(string name, Type champion, string[] levelNames, Type[][] spawnTypes)
{
- new(
- "Abyss",
- typeof(Semidar),
- new[] { "Foe", "Assassin", "Conqueror" },
- new[] // Abyss
- {
- // Abyss
- new[] { typeof(GreaterMongbat), typeof(Imp) }, // Level 1
- new[] { typeof(Gargoyle), typeof(Harpy) }, // Level 2
- new[] { typeof(FireGargoyle), typeof(StoneGargoyle) }, // Level 3
- new[] { typeof(Daemon), typeof(Succubus) } // Level 4
- }
- ),
- new(
- "Arachnid",
- typeof(Mephitis),
- new[] { "Bane", "Killer", "Vanquisher" },
- new[] // Arachnid
- {
- // Arachnid
- new[] { typeof(Scorpion), typeof(GiantSpider) }, // Level 1
- new[] { typeof(TerathanDrone), typeof(TerathanWarrior) }, // Level 2
- new[] { typeof(DreadSpider), typeof(TerathanMatriarch) }, // Level 3
- new[] { typeof(PoisonElemental), typeof(TerathanAvenger) } // Level 4
- }
- ),
- new(
- "Cold Blood",
- typeof(Rikktor),
- new[] { "Blight", "Slayer", "Destroyer" },
- new[] // Cold Blood
- {
- // Cold Blood
- new[] { typeof(Lizardman), typeof(Snake) }, // Level 1
- new[] { typeof(LavaLizard), typeof(OphidianWarrior) }, // Level 2
- new[] { typeof(Drake), typeof(OphidianArchmage) }, // Level 3
- new[] { typeof(Dragon), typeof(OphidianKnight) } // Level 4
- }
- ),
- new(
- "Forest Lord",
- typeof(LordOaks),
- new[] { "Enemy", "Curse", "Slaughterer" },
- new[] // Forest Lord
- {
- // Forest Lord
- new[] { typeof(Pixie), typeof(ShadowWisp) }, // Level 1
- new[] { typeof(Kirin), typeof(Wisp) }, // Level 2
- new[] { typeof(Centaur), typeof(Unicorn) }, // Level 3
- new[] { typeof(EtherealWarrior), typeof(SerpentineDragon) } // Level 4
- }
- ),
- new(
- "Vermin Horde",
- typeof(Barracoon),
- new[] { "Adversary", "Subjugator", "Eradicator" },
- new[] // Vermin Horde
- {
- // Vermin Horde
- new[] { typeof(GiantRat), typeof(Slime) }, // Level 1
- new[] { typeof(DireWolf), typeof(Ratman) }, // Level 2
- new[] { typeof(HellHound), typeof(RatmanMage) }, // Level 3
- new[] { typeof(RatmanArcher), typeof(SilverSerpent) } // Level 4
- }
- ),
- new(
- "Unholy Terror",
- typeof(Neira),
- new[] { "Scourge", "Punisher", "Nemesis" },
- new[] // Unholy Terror
- {
- // Unholy Terror
- Core.AOS
- ? new[]
- {
- typeof(Bogle), typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith)
- } // Level 1 (Pre-AoS)
- : new[] { typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) }, // Level 1
+ Name = name;
+ Champion = champion;
+ LevelNames = levelNames;
+ SpawnTypes = spawnTypes;
+ }
- new[] { typeof(BoneMagi), typeof(Mummy), typeof(SkeletalMage) }, // Level 2
- new[] { typeof(BoneKnight), typeof(Lich), typeof(SkeletalKnight) }, // Level 3
- new[] { typeof(LichLord), typeof(RottingCorpse) } // Level 4
- }
- ),
- new(
- "Sleeping Dragon",
- typeof(Serado),
- new[] { "Rival", "Challenger", "Antagonist" },
- new[]
- {
- // Unholy Terror
- new[] { typeof(DeathwatchBeetleHatchling), typeof(Lizardman) },
- new[] { typeof(DeathwatchBeetle), typeof(Kappa) },
- new[] { typeof(LesserHiryu), typeof(RevenantLion) },
- new[] { typeof(Hiryu), typeof(Oni) }
- }
- ),
- new(
- "Glade",
- typeof(Twaulo),
- new[] { "Banisher", "Enforcer", "Eradicator" },
- new[]
- {
- // Glade
- new[] { typeof(Pixie), typeof(ShadowWisp) },
- new[] { typeof(Centaur), typeof(MLDryad) },
- new[] { typeof(Satyr), typeof(CuSidhe) },
- new[] { typeof(FeralTreefellow), typeof(RagingGrizzlyBear) }
- }
- ),
- new(
- "The Corrupt",
- typeof(Ilhenir),
- new[] { "Cleanser", "Expunger", "Depurator" },
- new[]
- {
- // Unholy Terror
- new[] { typeof(PlagueSpawn), typeof(Bogling) },
- new[] { typeof(PlagueBeast), typeof(BogThing) },
- new[] { typeof(PlagueBeastLord), typeof(InterredGrizzle) },
- new[] { typeof(FetidEssence), typeof(PestilentBandage) }
- }
- )
+ public static ChampionSpawnInfo[] Table { get; } = {
+ new("Abyss", typeof(Semidar), new[]{ "Foe", "Assassin", "Conqueror" }, new[]
+ {
+ new[]{ typeof(GreaterMongbat), typeof(Imp) }, // Level 1
+ new[]{ typeof(Gargoyle), typeof(Harpy) }, // Level 2
+ new[]{ typeof(FireGargoyle), typeof(StoneGargoyle) }, // Level 3
+ new[]{ typeof(Daemon), typeof(Succubus) } // Level 4
+ }),
+ new("Arachnid", typeof(Mephitis), new[]{ "Bane", "Killer", "Vanquisher" }, new[]
+ {
+ new[]{ typeof(Scorpion), typeof(GiantSpider) }, // Level 1
+ new[]{ typeof(TerathanDrone), typeof(TerathanWarrior) }, // Level 2
+ new[]{ typeof(DreadSpider), typeof(TerathanMatriarch) }, // Level 3
+ new[]{ typeof(PoisonElemental), typeof(TerathanAvenger) } // Level 4
+ }),
+ new("Cold Blood", typeof(Rikktor), new[]{ "Blight", "Slayer", "Destroyer" }, new[]
+ {
+ new[]{ typeof(Lizardman), typeof(GiantSerpent) }, // Level 1
+ new[]{ typeof(LavaLizard), typeof(OphidianWarrior) }, // Level 2
+ new[]{ typeof(Drake), typeof(OphidianArchmage) }, // Level 3
+ new[]{ typeof(Dragon), typeof(OphidianKnight) } // Level 4
+ }),
+ new("Forest Lord", typeof(LordOaks), new[]{ "Enemy", "Curse", "Slaughterer" }, new[]
+ {
+ new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
+ new[]{ typeof(Kirin), typeof(Wisp) }, // Level 2
+ new[]{ typeof(Centaur), typeof(Unicorn) }, // Level 3
+ new[]{ typeof(EtherealWarrior), typeof(SerpentineDragon) } // Level 4
+ }),
+ new("Vermin Horde", typeof(Barracoon), new[]{ "Adversary", "Subjugator", "Eradicator" }, new[]
+ {
+ new[]{ typeof(GiantRat), typeof(Slime) }, // Level 1
+ new[]{ typeof(DireWolf), typeof(Ratman) }, // Level 2
+ new[]{ typeof(HellHound), typeof(RatmanMage) }, // Level 3
+ new[]{ typeof(RatmanArcher), typeof(SilverSerpent) } // Level 4
+ }),
+ new("Unholy Terror", typeof(Neira), new[]{ "Scourge", "Punisher", "Nemesis" }, new[]
+ {
+ Core.AOS ? // Level 1
+ new[]{ typeof(Bogle), typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) }
+ : new[]{ typeof(Ghoul), typeof(Shade), typeof(Spectre), typeof(Wraith) },
+
+ new[]{ typeof(BoneMagi), typeof(Mummy), typeof(SkeletalMage) }, // Level 2
+ new[]{ typeof(BoneKnight), typeof(Lich), typeof(SkeletalKnight) }, // Level 3
+ new[]{ typeof(LichLord), typeof(RottingCorpse) } // Level 4
+ }),
+ new("Sleeping Dragon", typeof(Serado), new[]{ "Rival", "Challenger", "Antagonist" } , new[]
+ {
+ new[]{ typeof(DeathwatchBeetleHatchling), typeof(Lizardman) }, // Level 1
+ new[]{ typeof(DeathwatchBeetle), typeof(Kappa) }, // Level 2
+ new[]{ typeof(LesserHiryu), typeof(RevenantLion) }, // Level 3
+ new[]{ typeof(Hiryu), typeof(Oni) } // Level 4
+ }),
+ new("Glade", typeof(Twaulo), new[]{ "Banisher", "Enforcer", "Eradicator" } , new[]
+ {
+ new[]{ typeof(Pixie), typeof(ShadowWisp) }, // Level 1
+ new[]{ typeof(Centaur), typeof(MLDryad) }, // Level 2
+ new[]{ typeof(Satyr), typeof(CuSidhe) }, // Level 3
+ new[]{ typeof(FeralTreefellow), typeof(RagingGrizzlyBear) } // Level 4
+ }),
+ new("The Corrupt", typeof(Ilhenir), new[]{ "Cleanser", "Expunger", "Depurator" } , new[]
+ {
+ new[]{ typeof(PlagueSpawn), typeof(Bogling) }, // Level 1
+ new[]{ typeof(PlagueBeast), typeof(BogThing) }, // Level 2
+ new[]{ typeof(PlagueBeastLord), typeof(InterredGrizzle) }, // Level 3
+ new[]{ typeof(FetidEssence), typeof(PestilentBandage) } // Level 4
+ }),
};
public static ChampionSpawnInfo GetInfo(ChampionSpawnType type)
diff --git a/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs b/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs
new file mode 100644
index 000000000..20402cde1
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/DungeonChampionSpawn.cs
@@ -0,0 +1,54 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: DungeonChampionSpawn.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+namespace Server.Engines.CannedEvil
+{
+ public class DungeonChampionSpawn : ChampionSpawn
+ {
+ [Constructible]
+ public DungeonChampionSpawn() : base()
+ {
+ CannedEvilTimer.AddSpawn(this);
+ }
+
+ public DungeonChampionSpawn(Serial serial) : base(serial)
+ {
+ CannedEvilTimer.AddSpawn(this);
+ }
+
+ public override bool ProximitySpawn => true;
+ public override bool AlwaysActive => false;
+
+ public override void Serialize(IGenericWriter writer)
+ {
+ base.Serialize(writer);
+
+ writer.WriteEncodedInt(0); //version
+ }
+
+ public override void Deserialize(IGenericReader reader)
+ {
+ base.Deserialize(reader);
+
+ int version = reader.ReadEncodedInt();
+ }
+
+ public override void OnAfterDelete()
+ {
+ base.OnAfterDelete();
+ CannedEvilTimer.RemoveSpawn(this);
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs b/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs
new file mode 100644
index 000000000..ec697f2e3
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/GenChampEntry.cs
@@ -0,0 +1,49 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: GenChampEntry.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+using System;
+
+namespace Server.Engines.CannedEvil
+{
+ public record ChampionEntry
+ {
+ public readonly bool m_RandomizeType;
+ public readonly ChampionSpawnType m_Type;
+ public readonly Point3D m_SignLocation;
+ public readonly Type m_ChampType;
+ public readonly Map m_Map;
+ public readonly Point3D m_EjectLocation;
+ public readonly Map m_EjectMap;
+
+ public ChampionEntry(Type champtype, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap) :
+ this(champtype, ChampionSpawnType.Abyss, signloc, map, ejectloc, ejectmap, true)
+ {
+ }
+
+ public ChampionEntry(
+ Type champtype, ChampionSpawnType type, Point3D signloc, Map map, Point3D ejectloc, Map ejectmap,
+ bool randomizetype = false
+ )
+ {
+ m_ChampType = champtype;
+ m_RandomizeType = randomizetype;
+ m_Type = type;
+ m_SignLocation = signloc;
+ m_Map = map;
+ m_EjectLocation = ejectloc;
+ m_EjectMap = ejectmap;
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/GenChamps.cs b/Projects/UOContent/Engines/CannedEvil/GenChamps.cs
new file mode 100644
index 000000000..073c50411
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/GenChamps.cs
@@ -0,0 +1,116 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: GenChamps.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+using System;
+using System.Collections.Generic;
+using Server.Logging;
+
+namespace Server.Engines.CannedEvil
+{
+ public static class ChampionGenerator
+ {
+ private static readonly ILogger logger = LogFactory.GetLogger(typeof(ChampionGenerator));
+
+ public static void Initialize()
+ {
+ CommandSystem.Register("GenChamps", AccessLevel.Owner, ChampGen_OnCommand);
+ }
+
+ private static readonly ChampionEntry[] LLLocations = {
+ new(typeof(LLChampionSpawn), new Point3D(5511, 2360, 42), Map.Felucca, new Point3D(5439, 2323, 26 ), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(6038, 2401, 47), Map.Felucca, new Point3D(5988, 2340, 24), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5549, 2640, 16), Map.Felucca, new Point3D(5645, 2696, -8), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5636, 2916, 37), Map.Felucca, new Point3D(5721, 2949, 28), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(6035, 2943, 50), Map.Felucca, new Point3D(6098, 2997, 17), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5265, 3171, 105), Map.Felucca, new Point3D(5314, 3232, 2), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5282, 3368, 50), Map.Felucca, new Point3D(5215, 3318, 3), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5207, 3637, 20), Map.Felucca, new Point3D(5263, 3687, 0), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5954, 3475, 25), Map.Felucca, new Point3D(6013, 3529, 0), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5982, 3882, 20), Map.Felucca, new Point3D(5929, 3820, -1), Map.Felucca),
+ new(typeof(LLChampionSpawn), new Point3D(5724, 3991, 41), Map.Felucca, new Point3D(5774, 4041, 26), Map.Felucca),
+ new(typeof(LLChampionSpawn), ChampionSpawnType.ForestLord, new Point3D(5559, 3757, 21), Map.Felucca, new Point3D(5513, 3878, 3), Map.Felucca),
+ };
+
+ private static readonly ChampionEntry[] DungeonLocations = {
+ new(typeof(DungeonChampionSpawn), ChampionSpawnType.UnholyTerror, new Point3D(5179, 709, 20), Map.Felucca, new Point3D(4111, 432, 5), Map.Felucca),
+ new(typeof(DungeonChampionSpawn), ChampionSpawnType.VerminHorde, new Point3D(5557, 827, 65), Map.Felucca, new Point3D(5580, 632, 30), Map.Felucca),
+ new(typeof(DungeonChampionSpawn), ChampionSpawnType.ColdBlood, new Point3D(5259, 837, 64), Map.Felucca, new Point3D(1176, 2637, 0), Map.Felucca),
+ new(typeof(DungeonChampionSpawn), ChampionSpawnType.Abyss, new Point3D(5815, 1352, 5), Map.Felucca, new Point3D(2923, 3406, 8), Map.Felucca),
+ new(typeof(DungeonChampionSpawn), ChampionSpawnType.Arachnid, new Point3D(5190, 1607, 20), Map.Felucca, new Point3D(5482, 3161, -54), Map.Felucca),
+ };
+
+ [Usage("GenChamps")]
+ [Description("Generates champions for Felucca Dungeons & Lost Lands.")]
+ private static void ChampGen_OnCommand(CommandEventArgs e)
+ {
+ /*
+ //We take the assumption that we are spawning managed champions
+ for (int i = CannedEvilTimer.DungeonSpawns.Count - 1; i >= 0; i--)
+ CannedEvilTimer.DungeonSpawns[i].Delete();
+
+ for (int i = CannedEvilTimer.LLSpawns.Count - 1; i >= 0; i--)
+ CannedEvilTimer.LLSpawns[i].Delete();
+ */
+
+ //We assume that all champion spawns are generated here.
+ List spawns = new List();
+ foreach (Item item in World.Items.Values)
+ {
+ if (item is ChampionSpawn spawn)
+ {
+ spawns.Add(spawn);
+ }
+ }
+
+ for (int i = spawns.Count - 1; i >= 0; i--)
+ {
+ spawns[i].Delete();
+ }
+
+ Process(DungeonLocations);
+ Process(LLLocations);
+ //ProcessIlshenar();
+ //ProcessTokuno();
+ }
+
+ private static void Process(ChampionEntry[] entries)
+ {
+ for (int i = 0; i < entries.Length; i++)
+ {
+ ChampionEntry entry = entries[i];
+
+ try
+ {
+ if (Activator.CreateInstance(entry.m_ChampType) is ChampionSpawn spawn)
+ {
+ spawn.RandomizeType = entry.m_RandomizeType;
+ spawn.Type = entry.m_Type;
+ spawn.MoveToWorld(entry.m_SignLocation, entry.m_Map);
+ spawn.EjectLocation = entry.m_EjectLocation;
+ spawn.EjectMap = entry.m_EjectMap;
+ if (spawn.AlwaysActive)
+ {
+ spawn.ReadyToActivate = true;
+ }
+ }
+ }
+ catch
+ {
+ logger.Warning($"Failed to generate champion spawn {entry.m_ChampType.FullName} at {entry.m_SignLocation} ({entry.m_Map})");
+ }
+ }
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs b/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs
new file mode 100644
index 000000000..b4144bad4
--- /dev/null
+++ b/Projects/UOContent/Engines/CannedEvil/LLChampionSpawn.cs
@@ -0,0 +1,55 @@
+/*************************************************************************
+ * ModernUO *
+ * Copyright 2019-2021 - ModernUO Development Team *
+ * Email: hi@modernuo.com *
+ * File: LLChampionSpawn.cs *
+ * *
+ * This program is free software: you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation, either version 3 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see . *
+ *************************************************************************/
+
+namespace Server.Engines.CannedEvil
+{
+ public class LLChampionSpawn : ChampionSpawn
+ {
+ public override bool HasStarRoomGate => false;
+
+ [Constructible]
+ public LLChampionSpawn()
+ {
+ CannedEvilTimer.AddSpawn(this);
+ }
+
+ public LLChampionSpawn(Serial serial) : base(serial)
+ {
+ }
+
+ public override bool AlwaysActive => false;
+
+ public override void Serialize(IGenericWriter writer)
+ {
+ base.Serialize(writer);
+
+ writer.WriteEncodedInt(0); //version
+ }
+
+ public override void Deserialize(IGenericReader reader)
+ {
+ base.Deserialize(reader);
+
+ int version = reader.ReadEncodedInt();
+ CannedEvilTimer.AddSpawn(this);
+ }
+
+ public override void OnAfterDelete()
+ {
+ base.OnAfterDelete();
+ CannedEvilTimer.RemoveSpawn(this);
+ }
+ }
+}
diff --git a/Projects/UOContent/Engines/CannedEvil/RestartTimer.cs b/Projects/UOContent/Engines/CannedEvil/RestartTimer.cs
deleted file mode 100644
index 494066791..000000000
--- a/Projects/UOContent/Engines/CannedEvil/RestartTimer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Server.Engines.CannedEvil
-{
- public class RestartTimer : Timer
- {
- private readonly ChampionSpawn m_Spawn;
-
- public RestartTimer(ChampionSpawn spawn, TimeSpan delay) : base(delay)
- {
- m_Spawn = spawn;
- Priority = TimerPriority.FiveSeconds;
- }
-
- protected override void OnTick()
- {
- m_Spawn.EndRestart();
- }
- }
-}
diff --git a/Projects/UOContent/Engines/CannedEvil/SliceTimer.cs b/Projects/UOContent/Engines/CannedEvil/SliceTimer.cs
deleted file mode 100644
index 8a9abc2a1..000000000
--- a/Projects/UOContent/Engines/CannedEvil/SliceTimer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System;
-
-namespace Server.Engines.CannedEvil
-{
- public class SliceTimer : Timer
- {
- private readonly ChampionSpawn m_Spawn;
-
- public SliceTimer(ChampionSpawn spawn) : base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
- {
- m_Spawn = spawn;
- Priority = TimerPriority.OneSecond;
- }
-
- protected override void OnTick()
- {
- m_Spawn.OnSlice();
- }
- }
-}
diff --git a/Projects/UOContent/Items/Food/Cooking.cs b/Projects/UOContent/Items/Food/Cooking.cs
index f165e7d02..8b17e5a8f 100644
--- a/Projects/UOContent/Items/Food/Cooking.cs
+++ b/Projects/UOContent/Items/Food/Cooking.cs
@@ -314,14 +314,14 @@ namespace Server.Items
{
}
- public override void Serialize( GenericWriter writer )
+ public override void Serialize(IGenericWriter writer)
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
}
- public override void Deserialize( GenericReader reader )
+ public override void Deserialize(IGenericReader reader)
{
base.Deserialize( reader );
diff --git a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs
index 390162a07..57f5c5b93 100644
--- a/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs
+++ b/Projects/UOContent/Items/Weapons/Staves/ShepherdsCrook.cs
@@ -121,7 +121,7 @@ namespace Server.Items
if (Region.Find(bc.Home, map) is ChampionSpawnRegion region)
{
- var spawn = region.ChampionSpawn;
+ var spawn = region.Spawn;
if (spawn?.IsChampionSpawn(bc) == true)
{
diff --git a/Projects/UOContent/Spells/Necromancy/Exorcism.cs b/Projects/UOContent/Spells/Necromancy/Exorcism.cs
index 996d74849..37602bf04 100644
--- a/Projects/UOContent/Spells/Necromancy/Exorcism.cs
+++ b/Projects/UOContent/Spells/Necromancy/Exorcism.cs
@@ -84,7 +84,7 @@ namespace Server.Spells.Necromancy
public override void OnCast()
{
var r = Caster.Region.GetRegion();
- if (r == null || !Caster.InRange(r.ChampionSpawn, Range))
+ if (r == null || !Caster.InRange(r.Spawn, Range))
{
Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region.
}
@@ -95,7 +95,7 @@ namespace Server.Spells.Necromancy
if (map != null)
{
// Surprisingly, no sparkle type effects
- foreach (var m in r.ChampionSpawn.GetMobilesInRange(Range))
+ foreach (var m in r.Spawn.GetMobilesInRange(Range))
{
if (IsValidTarget(m))
{