From daa154d6de3669a31a2a90e739aaa412eca6a567 Mon Sep 17 00:00:00 2001
From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com>
Date: Fri, 25 Aug 2023 20:59:11 -0700
Subject: [PATCH] fix: Codegens guards (#1474)
---
.../Server.Mobiles.ArcherGuard.v0.json | 11 +
.../Server.Mobiles.BaseGuard.v0.json | 4 +
.../Server.Mobiles.WarriorGuard.v0.json | 11 +
.../UOContent/Mobiles/Guards/ArcherGuard.cs | 713 +++++++++---------
.../UOContent/Mobiles/Guards/BaseGuard.cs | 135 ++--
.../UOContent/Mobiles/Guards/WarriorGuard.cs | 670 ++++++++--------
6 files changed, 752 insertions(+), 792 deletions(-)
create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.ArcherGuard.v0.json
create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.BaseGuard.v0.json
create mode 100644 Projects/UOContent/Migrations/Server.Mobiles.WarriorGuard.v0.json
diff --git a/Projects/UOContent/Migrations/Server.Mobiles.ArcherGuard.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.ArcherGuard.v0.json
new file mode 100644
index 000000000..1afc1a5e8
--- /dev/null
+++ b/Projects/UOContent/Migrations/Server.Mobiles.ArcherGuard.v0.json
@@ -0,0 +1,11 @@
+{
+ "version": 0,
+ "type": "Server.Mobiles.ArcherGuard",
+ "properties": [
+ {
+ "name": "Focus",
+ "type": "Server.Mobile",
+ "rule": "SerializableInterfaceMigrationRule"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Projects/UOContent/Migrations/Server.Mobiles.BaseGuard.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.BaseGuard.v0.json
new file mode 100644
index 000000000..8aba12a10
--- /dev/null
+++ b/Projects/UOContent/Migrations/Server.Mobiles.BaseGuard.v0.json
@@ -0,0 +1,4 @@
+{
+ "version": 0,
+ "type": "Server.Mobiles.BaseGuard"
+}
\ No newline at end of file
diff --git a/Projects/UOContent/Migrations/Server.Mobiles.WarriorGuard.v0.json b/Projects/UOContent/Migrations/Server.Mobiles.WarriorGuard.v0.json
new file mode 100644
index 000000000..484cf1b00
--- /dev/null
+++ b/Projects/UOContent/Migrations/Server.Mobiles.WarriorGuard.v0.json
@@ -0,0 +1,11 @@
+{
+ "version": 0,
+ "type": "Server.Mobiles.WarriorGuard",
+ "properties": [
+ {
+ "name": "Focus",
+ "type": "Server.Mobile",
+ "rule": "SerializableInterfaceMigrationRule"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs b/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs
index 0d22eec97..e682ba9d2 100644
--- a/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs
+++ b/Projects/UOContent/Mobiles/Guards/ArcherGuard.cs
@@ -1,415 +1,388 @@
using System;
+using ModernUO.Serialization;
using Server.Items;
-namespace Server.Mobiles
+namespace Server.Mobiles;
+
+[SerializationGenerator(0, false)]
+public partial class ArcherGuard : BaseGuard
{
- public class ArcherGuard : BaseGuard
+ private Timer _attackTimer;
+ private Timer _idleTimer;
+
+ [Constructible]
+ public ArcherGuard(Mobile target = null) : base(target)
{
- private Timer m_AttackTimer, m_IdleTimer;
+ InitStats(100, 125, 25);
+ Title = "the guard";
- private Mobile m_Focus;
+ SpeechHue = Utility.RandomDyedHue();
- [Constructible]
- public ArcherGuard(Mobile target = null) : base(target)
+ Hue = Race.Human.RandomSkinHue();
+
+ if (Female = Utility.RandomBool())
{
- InitStats(100, 125, 25);
- Title = "the guard";
+ Body = 0x191;
+ Name = NameList.RandomName("female");
+ }
+ else
+ {
+ Body = 0x190;
+ Name = NameList.RandomName("male");
+ }
- SpeechHue = Utility.RandomDyedHue();
+ new Horse().Rider = this;
- Hue = Race.Human.RandomSkinHue();
+ AddItem(new StuddedChest());
+ AddItem(new StuddedArms());
+ AddItem(new StuddedGloves());
+ AddItem(new StuddedGorget());
+ AddItem(new StuddedLegs());
+ AddItem(new Boots());
+ AddItem(new SkullCap());
- if (Female = Utility.RandomBool())
+ var bow = new Bow();
+
+ bow.Movable = false;
+ bow.Crafter = this;
+ bow.Quality = WeaponQuality.Exceptional;
+
+ AddItem(bow);
+
+ Container pack = new Backpack();
+
+ pack.Movable = false;
+
+ var arrows = new Arrow(250);
+
+ arrows.LootType = LootType.Newbied;
+
+ pack.DropItem(arrows);
+ pack.DropItem(new Gold(10, 25));
+
+ AddItem(pack);
+
+ Skills.Anatomy.Base = 120.0;
+ Skills.Tactics.Base = 120.0;
+ Skills.Archery.Base = 120.0;
+ Skills.MagicResist.Base = 120.0;
+ Skills.DetectHidden.Base = 100.0;
+
+ NextCombatTime = Core.TickCount + 500;
+ Focus = target;
+ }
+
+ [SerializableProperty(0)]
+ [CommandProperty(AccessLevel.GameMaster)]
+ public override Mobile Focus
+ {
+ get => _focus;
+ set
+ {
+ if (Deleted)
{
- Body = 0x191;
- Name = NameList.RandomName("female");
+ return;
+ }
+
+ var oldFocus = _focus;
+
+ if (oldFocus != value)
+ {
+ _focus = value;
+
+ if (value != null)
+ {
+ AggressiveAction(value);
+ }
+
+ Combatant = value;
+
+ if (oldFocus?.Alive == false)
+ {
+ Say("Thou hast suffered thy punishment, scoundrel.");
+ }
+
+ if (value != null)
+ {
+ Say(500131); // Thou wilt regret thine actions, swine!
+ }
+
+ if (_attackTimer != null)
+ {
+ _attackTimer.Stop();
+ _attackTimer = null;
+ }
+
+ if (_idleTimer != null)
+ {
+ _idleTimer.Stop();
+ _idleTimer = null;
+ }
+
+ if (_focus != null)
+ {
+ _attackTimer = new AttackTimer(this);
+ _attackTimer.Start();
+ ((AttackTimer)_attackTimer).DoOnTick();
+ }
+ else
+ {
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
+ }
+ }
+ else if (_focus == null && _idleTimer == null)
+ {
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
+ }
+
+ this.MarkDirty();
+ }
+ }
+
+ public override bool OnBeforeDeath()
+ {
+ if (_focus?.Alive == true)
+ {
+ new AvengeTimer(_focus).Start(); // If a guard dies, three more guards will spawn
+ }
+
+ return base.OnBeforeDeath();
+ }
+
+ [AfterDeserialization]
+ private void AfterDeserialization()
+ {
+ if (_focus != null)
+ {
+ _attackTimer = new AttackTimer(this);
+ _attackTimer.Start();
+ }
+ else
+ {
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
+ }
+ }
+
+ public override void OnAfterDelete()
+ {
+ if (_attackTimer != null)
+ {
+ _attackTimer.Stop();
+ _attackTimer = null;
+ }
+
+ if (_idleTimer != null)
+ {
+ _idleTimer.Stop();
+ _idleTimer = null;
+ }
+
+ base.OnAfterDelete();
+ }
+
+ private class AvengeTimer : Timer
+ {
+ private readonly Mobile m_Focus;
+
+ // After 2.5 seconds, one guard will spawn every 1.0 second, three times
+ public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3) =>
+ m_Focus = focus;
+
+ protected override void OnTick()
+ {
+ Spawn(m_Focus, m_Focus, 1, true);
+ }
+ }
+
+ private class AttackTimer : Timer
+ {
+ private readonly ArcherGuard m_Owner;
+ // private bool m_Shooting;
+
+ public AttackTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) =>
+ m_Owner = owner;
+
+ public void DoOnTick()
+ {
+ OnTick();
+ }
+
+ protected override void OnTick()
+ {
+ if (m_Owner.Deleted)
+ {
+ Stop();
+ return;
+ }
+
+ m_Owner.Criminal = false;
+ m_Owner.Kills = 0;
+ m_Owner.Stam = m_Owner.StamMax;
+
+ var target = m_Owner.Focus;
+
+ if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target)))
+ {
+ m_Owner.Focus = null;
+ Stop();
+ return;
+ }
+
+ if (m_Owner.Weapon is Fists)
+ {
+ m_Owner.Kill();
+ Stop();
+ return;
+ }
+
+ if (target != null && m_Owner.Combatant != target)
+ {
+ m_Owner.Combatant = target;
+ }
+
+ if (target == null)
+ {
+ Stop();
}
else
{
- Body = 0x190;
- Name = NameList.RandomName("male");
- }
+ //
+ TeleportTo(target);
+ target.BoltEffect(0);
- new Horse().Rider = this;
+ if (target is BaseCreature creature)
+ {
+ creature.NoKillAwards = true;
+ }
- AddItem(new StuddedChest());
- AddItem(new StuddedArms());
- AddItem(new StuddedGloves());
- AddItem(new StuddedGorget());
- AddItem(new StuddedLegs());
- AddItem(new Boots());
- AddItem(new SkullCap());
+ target.Damage(target.HitsMax, m_Owner);
+ target.Kill(); // just in case, maybe Damage is overridden on some shard
- var bow = new Bow();
+ if (target.Corpse != null && !target.Player)
+ {
+ target.Corpse.Delete();
+ }
- bow.Movable = false;
- bow.Crafter = this;
- bow.Quality = WeaponQuality.Exceptional;
+ m_Owner.Focus = null;
+ Stop();
+ } //
- AddItem(bow);
-
- Container pack = new Backpack();
-
- pack.Movable = false;
-
- var arrows = new Arrow(250);
-
- arrows.LootType = LootType.Newbied;
-
- pack.DropItem(arrows);
- pack.DropItem(new Gold(10, 25));
-
- AddItem(pack);
-
- Skills.Anatomy.Base = 120.0;
- Skills.Tactics.Base = 120.0;
- Skills.Archery.Base = 120.0;
- Skills.MagicResist.Base = 120.0;
- Skills.DetectHidden.Base = 100.0;
-
- NextCombatTime = Core.TickCount + 500;
- Focus = target;
- }
-
- public ArcherGuard(Serial serial) : base(serial)
- {
- }
-
- [CommandProperty(AccessLevel.GameMaster)]
- public override Mobile Focus
- {
- get => m_Focus;
- set
+ /*else if (!m_Owner.InRange( target, 20 ))
{
- if (Deleted)
- {
- return;
- }
-
- var oldFocus = m_Focus;
-
- if (oldFocus != value)
- {
- m_Focus = value;
-
- if (value != null)
- {
- AggressiveAction(value);
- }
-
- Combatant = value;
-
- if (oldFocus?.Alive == false)
- {
- Say("Thou hast suffered thy punishment, scoundrel.");
- }
-
- if (value != null)
- {
- Say(500131); // Thou wilt regret thine actions, swine!
- }
-
- if (m_AttackTimer != null)
- {
- m_AttackTimer.Stop();
- m_AttackTimer = null;
- }
-
- if (m_IdleTimer != null)
- {
- m_IdleTimer.Stop();
- m_IdleTimer = null;
- }
-
- if (m_Focus != null)
- {
- m_AttackTimer = new AttackTimer(this);
- m_AttackTimer.Start();
- ((AttackTimer)m_AttackTimer).DoOnTick();
- }
- else
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
- }
- else if (m_Focus == null && m_IdleTimer == null)
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
+ m_Shooting = false;
+ m_Owner.Focus = null;
}
- }
-
- public override bool OnBeforeDeath()
- {
- if (m_Focus?.Alive == true)
+ else if (!m_Owner.InLOS( target ))
{
- new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn
+ m_Shooting = false;
+ TeleportTo( target );
}
-
- return base.OnBeforeDeath();
- }
-
- public override void Serialize(IGenericWriter writer)
- {
- base.Serialize(writer);
-
- writer.Write(0); // version
-
- writer.Write(m_Focus);
- }
-
- public override void Deserialize(IGenericReader reader)
- {
- base.Deserialize(reader);
-
- var version = reader.ReadInt();
-
- switch (version)
+ else if (!m_Owner.CanSee( target ))
{
- case 0:
- {
- m_Focus = reader.ReadEntity();
+ m_Shooting = false;
- if (m_Focus != null)
- {
- m_AttackTimer = new AttackTimer(this);
- m_AttackTimer.Start();
- }
- else
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
-
- break;
- }
- }
- }
-
- public override void OnAfterDelete()
- {
- if (m_AttackTimer != null)
- {
- m_AttackTimer.Stop();
- m_AttackTimer = null;
- }
-
- if (m_IdleTimer != null)
- {
- m_IdleTimer.Stop();
- m_IdleTimer = null;
- }
-
- base.OnAfterDelete();
- }
-
- private class AvengeTimer : Timer
- {
- private readonly Mobile m_Focus;
-
- public AvengeTimer(Mobile focus) : base(
- TimeSpan.FromSeconds(2.5),
- TimeSpan.FromSeconds(1.0),
- 3
- ) // After 2.5 seconds, one guard will spawn every 1.0 second, three times
- =>
- m_Focus = focus;
-
- protected override void OnTick()
- {
- Spawn(m_Focus, m_Focus, 1, true);
- }
- }
-
- private class AttackTimer : Timer
- {
- private readonly ArcherGuard m_Owner;
- // private bool m_Shooting;
-
- public AttackTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) =>
- m_Owner = owner;
-
- public void DoOnTick()
- {
- OnTick();
- }
-
- protected override void OnTick()
- {
- if (m_Owner.Deleted)
- {
- Stop();
- return;
- }
-
- m_Owner.Criminal = false;
- m_Owner.Kills = 0;
- m_Owner.Stam = m_Owner.StamMax;
-
- var target = m_Owner.Focus;
-
- if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target)))
- {
- m_Owner.Focus = null;
- Stop();
- return;
- }
-
- if (m_Owner.Weapon is Fists)
- {
- m_Owner.Kill();
- Stop();
- return;
- }
-
- if (target != null && m_Owner.Combatant != target)
- {
- m_Owner.Combatant = target;
- }
-
- if (target == null)
- {
- Stop();
- }
- else
- {
- //
- TeleportTo(target);
- target.BoltEffect(0);
-
- if (target is BaseCreature creature)
- {
- creature.NoKillAwards = true;
- }
-
- target.Damage(target.HitsMax, m_Owner);
- target.Kill(); // just in case, maybe Damage is overridden on some shard
-
- if (target.Corpse != null && !target.Player)
- {
- target.Corpse.Delete();
- }
-
- m_Owner.Focus = null;
- Stop();
- } //
-
- /*else if (!m_Owner.InRange( target, 20 ))
- {
- m_Shooting = false;
- m_Owner.Focus = null;
- }
- else if (!m_Owner.InLOS( target ))
- {
- m_Shooting = false;
+ if (!m_Owner.InRange( target, 2 ))
+ {
+ if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ))
TeleportTo( target );
- }
- else if (!m_Owner.CanSee( target ))
- {
- m_Shooting = false;
+ }
+ else
+ {
+ if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0)
+ m_Owner.Say( "Reveal!" );
+ }
+ }
+ else
+ {
+ if (m_Shooting && (TimeToSpare() || OutOfMaxDistance( target )))
+ m_Shooting = false;
+ else if (!m_Shooting && InMinDistance( target ))
+ m_Shooting = true;
- if (!m_Owner.InRange( target, 2 ))
- {
- if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ))
- TeleportTo( target );
- }
- else
- {
- if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0)
- m_Owner.Say( "Reveal!" );
- }
- }
- else
+ if (!m_Shooting)
+ {
+ if (m_Owner.InRange( target, 1 ))
{
- if (m_Shooting && (TimeToSpare() || OutOfMaxDistance( target )))
- m_Shooting = false;
- else if (!m_Shooting && InMinDistance( target ))
- m_Shooting = true;
+ if (!m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target ))
+ TeleportTo( target ); // Too close, move away
+ }
+ else if (!m_Owner.InRange( target, 2 ))
+ {
+ if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ))
+ TeleportTo( target );
+ }
+ }
+ }*/
+ }
- if (!m_Shooting)
- {
- if (m_Owner.InRange( target, 1 ))
- {
- if (!m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target ))
- TeleportTo( target ); // Too close, move away
- }
- else if (!m_Owner.InRange( target, 2 ))
- {
- if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ))
- TeleportTo( target );
- }
- }
- }*/
+ private bool TimeToSpare() => m_Owner.NextCombatTime - Core.TickCount > 1000;
+
+ private bool OutOfMaxDistance(IPoint2D target) => !m_Owner.InRange(target, m_Owner.Weapon.MaxRange);
+
+ private bool InMinDistance(IPoint2D target) => m_Owner.InRange(target, 4);
+
+ private void TeleportTo(IEntity target)
+ {
+ var from = m_Owner.Location;
+ var to = target.Location;
+
+ m_Owner.Location = to;
+
+ Effects.SendLocationParticles(
+ EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration),
+ 0x3728,
+ 10,
+ 10,
+ 2023
+ );
+ Effects.SendLocationParticles(
+ EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration),
+ 0x3728,
+ 10,
+ 10,
+ 5023
+ );
+
+ m_Owner.PlaySound(0x1FE);
+ }
+ }
+
+ private class IdleTimer : Timer
+ {
+ private readonly ArcherGuard m_Owner;
+ private int m_Stage;
+
+ public IdleTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) =>
+ m_Owner = owner;
+
+ protected override void OnTick()
+ {
+ if (m_Owner.Deleted)
+ {
+ Stop();
+ return;
}
- private bool TimeToSpare() => m_Owner.NextCombatTime - Core.TickCount > 1000;
-
- private bool OutOfMaxDistance(IPoint2D target) => !m_Owner.InRange(target, m_Owner.Weapon.MaxRange);
-
- private bool InMinDistance(IPoint2D target) => m_Owner.InRange(target, 4);
-
- private void TeleportTo(IEntity target)
+ if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction))
{
- var from = m_Owner.Location;
- var to = target.Location;
-
- m_Owner.Location = to;
+ m_Owner.Direction = (Direction)Utility.Random(8);
+ }
+ if (m_Stage > 16)
+ {
Effects.SendLocationParticles(
- EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration),
+ EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration),
0x3728,
10,
10,
2023
);
- Effects.SendLocationParticles(
- EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration),
- 0x3728,
- 10,
- 10,
- 5023
- );
-
m_Owner.PlaySound(0x1FE);
- }
- }
- private class IdleTimer : Timer
- {
- private readonly ArcherGuard m_Owner;
- private int m_Stage;
-
- public IdleTimer(ArcherGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) =>
- m_Owner = owner;
-
- protected override void OnTick()
- {
- if (m_Owner.Deleted)
- {
- Stop();
- return;
- }
-
- if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction))
- {
- m_Owner.Direction = (Direction)Utility.Random(8);
- }
-
- if (m_Stage > 16)
- {
- Effects.SendLocationParticles(
- EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration),
- 0x3728,
- 10,
- 10,
- 2023
- );
- m_Owner.PlaySound(0x1FE);
-
- m_Owner.Delete();
- }
+ m_Owner.Delete();
}
}
}
diff --git a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs
index bfce8e083..25d302394 100644
--- a/Projects/UOContent/Mobiles/Guards/BaseGuard.cs
+++ b/Projects/UOContent/Mobiles/Guards/BaseGuard.cs
@@ -1,91 +1,74 @@
+using ModernUO.Serialization;
using Server.Items;
-namespace Server.Mobiles
+namespace Server.Mobiles;
+
+[SerializationGenerator(0)]
+public abstract partial class BaseGuard : Mobile
{
- public abstract class BaseGuard : Mobile
+ public BaseGuard(Mobile target)
{
- public BaseGuard(Mobile target)
+ if (target != null)
{
- if (target != null)
- {
- Location = target.Location;
- Map = target.Map;
+ Location = target.Location;
+ Map = target.Map;
- Effects.SendLocationParticles(
- EffectItem.Create(Location, Map, EffectItem.DefaultDuration),
- 0x3728,
- 10,
- 10,
- 5023
- );
- }
- }
-
- public BaseGuard(Serial serial) : base(serial)
- {
- }
-
- public abstract Mobile Focus { get; set; }
-
- public static void Spawn(Mobile caller, Mobile target, int amount = 1, bool onlyAdditional = false)
- {
- if (target?.Deleted != false)
- {
- return;
- }
-
- foreach (var m in target.GetMobilesInRange(15))
- {
- if (m is BaseGuard g)
- {
- if (g.Focus == null) // idling
- {
- g.Focus = target;
-
- --amount;
- }
- else if (g.Focus == target && !onlyAdditional)
- {
- --amount;
- }
- }
- }
-
- while (amount-- > 0)
- {
- caller.Region.MakeGuard(target);
- }
- }
-
- public override bool OnBeforeDeath()
- {
Effects.SendLocationParticles(
EffectItem.Create(Location, Map, EffectItem.DefaultDuration),
0x3728,
10,
10,
- 2023
+ 5023
);
-
- PlaySound(0x1FE);
-
- Delete();
-
- return false;
- }
-
- public override void Serialize(IGenericWriter writer)
- {
- base.Serialize(writer);
-
- writer.Write(0); // version
- }
-
- public override void Deserialize(IGenericReader reader)
- {
- base.Deserialize(reader);
-
- var version = reader.ReadInt();
}
}
+
+ public abstract Mobile Focus { get; set; }
+
+ public static void Spawn(Mobile caller, Mobile target, int amount = 1, bool onlyAdditional = false)
+ {
+ if (target?.Deleted != false)
+ {
+ return;
+ }
+
+ foreach (var m in target.GetMobilesInRange(15))
+ {
+ if (m is BaseGuard g)
+ {
+ if (g.Focus == null) // idling
+ {
+ g.Focus = target;
+
+ --amount;
+ }
+ else if (g.Focus == target && !onlyAdditional)
+ {
+ --amount;
+ }
+ }
+ }
+
+ while (amount-- > 0)
+ {
+ caller.Region.MakeGuard(target);
+ }
+ }
+
+ public override bool OnBeforeDeath()
+ {
+ Effects.SendLocationParticles(
+ EffectItem.Create(Location, Map, EffectItem.DefaultDuration),
+ 0x3728,
+ 10,
+ 10,
+ 2023
+ );
+
+ PlaySound(0x1FE);
+
+ Delete();
+
+ return false;
+ }
}
diff --git a/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs b/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs
index 59c1e23ff..9c8457a11 100644
--- a/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs
+++ b/Projects/UOContent/Mobiles/Guards/WarriorGuard.cs
@@ -1,393 +1,371 @@
using System;
+using ModernUO.Serialization;
using Server.Items;
-namespace Server.Mobiles
+namespace Server.Mobiles;
+
+[SerializationGenerator(0, false)]
+public partial class WarriorGuard : BaseGuard
{
- public class WarriorGuard : BaseGuard
+ private Timer _attackTimer;
+ private Timer _idleTimer;
+
+ [Constructible]
+ public WarriorGuard(Mobile target = null) : base(target)
{
- private Timer m_AttackTimer, m_IdleTimer;
+ InitStats(1000, 1000, 1000);
+ Title = "the guard";
- private Mobile m_Focus;
+ SpeechHue = Utility.RandomDyedHue();
- [Constructible]
- public WarriorGuard(Mobile target = null) : base(target)
+ Hue = Race.Human.RandomSkinHue();
+
+ if (Female = Utility.RandomBool())
{
- InitStats(1000, 1000, 1000);
- Title = "the guard";
+ Body = 0x191;
+ Name = NameList.RandomName("female");
- SpeechHue = Utility.RandomDyedHue();
+ AddItem(Utility.RandomBool() ? new LeatherSkirt() : new LeatherShorts());
- Hue = Race.Human.RandomSkinHue();
-
- if (Female = Utility.RandomBool())
- {
- Body = 0x191;
- Name = NameList.RandomName("female");
-
- AddItem(Utility.RandomBool() ? new LeatherSkirt() : new LeatherShorts());
-
- AddItem(
- Utility.Random(5) switch
- {
- 0 => new FemaleLeatherChest(),
- 1 => new FemaleStuddedChest(),
- 2 => new LeatherBustierArms(),
- 3 => new StuddedBustierArms(),
- _ => new FemalePlateChest() // 4
- }
- );
- }
- else
- {
- Body = 0x190;
- Name = NameList.RandomName("male");
-
- AddItem(new PlateChest());
- AddItem(new PlateArms());
- AddItem(new PlateLegs());
-
- AddItem(
- Utility.Random(3) switch
- {
- 0 => new Doublet(Utility.RandomNondyedHue()),
- 1 => new Tunic(Utility.RandomNondyedHue()),
- _ => new BodySash(Utility.RandomNondyedHue()) // 3
- }
- );
- }
-
- Utility.AssignRandomHair(this);
-
- if (Utility.RandomBool())
- {
- Utility.AssignRandomFacialHair(this, HairHue);
- }
-
- var weapon = new Halberd();
-
- weapon.Movable = false;
- weapon.Crafter = this;
- weapon.Quality = WeaponQuality.Exceptional;
-
- AddItem(weapon);
-
- Container pack = new Backpack();
-
- pack.Movable = false;
-
- pack.DropItem(new Gold(10, 25));
-
- AddItem(pack);
-
- Skills.Anatomy.Base = 120.0;
- Skills.Tactics.Base = 120.0;
- Skills.Swords.Base = 120.0;
- Skills.MagicResist.Base = 120.0;
- Skills.DetectHidden.Base = 100.0;
-
- NextCombatTime = Core.TickCount + 500;
- Focus = target;
- }
-
- public WarriorGuard(Serial serial) : base(serial)
- {
- }
-
- [CommandProperty(AccessLevel.GameMaster)]
- public override Mobile Focus
- {
- get => m_Focus;
- set
- {
- if (Deleted)
+ AddItem(
+ Utility.Random(5) switch
{
- return;
+ 0 => new FemaleLeatherChest(),
+ 1 => new FemaleStuddedChest(),
+ 2 => new LeatherBustierArms(),
+ 3 => new StuddedBustierArms(),
+ _ => new FemalePlateChest() // 4
+ }
+ );
+ }
+ else
+ {
+ Body = 0x190;
+ Name = NameList.RandomName("male");
+
+ AddItem(new PlateChest());
+ AddItem(new PlateArms());
+ AddItem(new PlateLegs());
+
+ AddItem(
+ Utility.Random(3) switch
+ {
+ 0 => new Doublet(Utility.RandomNondyedHue()),
+ 1 => new Tunic(Utility.RandomNondyedHue()),
+ _ => new BodySash(Utility.RandomNondyedHue()) // 3
+ }
+ );
+ }
+
+ Utility.AssignRandomHair(this);
+
+ if (Utility.RandomBool())
+ {
+ Utility.AssignRandomFacialHair(this, HairHue);
+ }
+
+ var weapon = new Halberd
+ {
+ Movable = false,
+ Crafter = this,
+ Quality = WeaponQuality.Exceptional
+ };
+
+ AddItem(weapon);
+
+ Container pack = new Backpack();
+
+ pack.Movable = false;
+
+ pack.DropItem(new Gold(10, 25));
+
+ AddItem(pack);
+
+ Skills.Anatomy.Base = 120.0;
+ Skills.Tactics.Base = 120.0;
+ Skills.Swords.Base = 120.0;
+ Skills.MagicResist.Base = 120.0;
+ Skills.DetectHidden.Base = 100.0;
+
+ NextCombatTime = Core.TickCount + 500;
+ Focus = target;
+ }
+
+ [SerializableProperty(0)]
+ [CommandProperty(AccessLevel.GameMaster)]
+ public override Mobile Focus
+ {
+ get => _focus;
+ set
+ {
+ if (Deleted)
+ {
+ return;
+ }
+
+ var oldFocus = _focus;
+
+ if (oldFocus != value)
+ {
+ _focus = value;
+
+ if (value != null)
+ {
+ AggressiveAction(value);
}
- var oldFocus = m_Focus;
+ Combatant = value;
- if (oldFocus != value)
+ if (oldFocus?.Alive == false)
{
- m_Focus = value;
-
- if (value != null)
- {
- AggressiveAction(value);
- }
-
- Combatant = value;
-
- if (oldFocus?.Alive == false)
- {
- Say("Thou hast suffered thy punishment, scoundrel.");
- }
-
- if (value != null)
- {
- Say(500131); // Thou wilt regret thine actions, swine!
- }
-
- if (m_AttackTimer != null)
- {
- m_AttackTimer.Stop();
- m_AttackTimer = null;
- }
-
- if (m_IdleTimer != null)
- {
- m_IdleTimer.Stop();
- m_IdleTimer = null;
- }
-
- if (m_Focus != null)
- {
- m_AttackTimer = new AttackTimer(this);
- m_AttackTimer.Start();
- ((AttackTimer)m_AttackTimer).DoOnTick();
- }
- else
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
- }
- else if (m_Focus == null && m_IdleTimer == null)
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
- }
- }
-
- public override bool OnBeforeDeath()
- {
- if (m_Focus?.Alive == true)
- {
- new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn
- }
-
- return base.OnBeforeDeath();
- }
-
- public override void Serialize(IGenericWriter writer)
- {
- base.Serialize(writer);
-
- writer.Write(0); // version
-
- writer.Write(m_Focus);
- }
-
- public override void Deserialize(IGenericReader reader)
- {
- base.Deserialize(reader);
-
- var version = reader.ReadInt();
-
- switch (version)
- {
- case 0:
- {
- m_Focus = reader.ReadEntity();
-
- if (m_Focus != null)
- {
- m_AttackTimer = new AttackTimer(this);
- m_AttackTimer.Start();
- }
- else
- {
- m_IdleTimer = new IdleTimer(this);
- m_IdleTimer.Start();
- }
-
- break;
- }
- }
- }
-
- public override void OnAfterDelete()
- {
- if (m_AttackTimer != null)
- {
- m_AttackTimer.Stop();
- m_AttackTimer = null;
- }
-
- if (m_IdleTimer != null)
- {
- m_IdleTimer.Stop();
- m_IdleTimer = null;
- }
-
- base.OnAfterDelete();
- }
-
- private class AvengeTimer : Timer
- {
- private readonly Mobile m_Focus;
-
- public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3) =>
- m_Focus = focus;
-
- protected override void OnTick()
- {
- Spawn(m_Focus, m_Focus, 1, true);
- }
- }
-
- private class AttackTimer : Timer
- {
- private readonly WarriorGuard m_Owner;
-
- public AttackTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) =>
- m_Owner = owner;
-
- public void DoOnTick()
- {
- OnTick();
- }
-
- protected override void OnTick()
- {
- if (m_Owner.Deleted)
- {
- Stop();
- return;
+ Say("Thou hast suffered thy punishment, scoundrel.");
}
- m_Owner.Criminal = false;
- m_Owner.Kills = 0;
- m_Owner.Stam = m_Owner.StamMax;
-
- var target = m_Owner.Focus;
-
- if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target)))
+ if (value != null)
{
- m_Owner.Focus = null;
- Stop();
- return;
+ Say(500131); // Thou wilt regret thine actions, swine!
}
- if (m_Owner.Weapon is Fists)
+ if (_attackTimer != null)
{
- m_Owner.Kill();
- Stop();
- return;
+ _attackTimer.Stop();
+ _attackTimer = null;
}
- if (target != null && m_Owner.Combatant != target)
+ if (_idleTimer != null)
{
- m_Owner.Combatant = target;
+ _idleTimer.Stop();
+ _idleTimer = null;
}
- if (target == null)
+ if (_focus != null)
{
- Stop();
+ _attackTimer = new AttackTimer(this);
+ _attackTimer.Start();
+ ((AttackTimer)_attackTimer).DoOnTick();
}
else
{
- //
- TeleportTo(target);
- target.BoltEffect(0);
-
- if (target is BaseCreature creature)
- {
- creature.NoKillAwards = true;
- }
-
- target.Damage(target.HitsMax, m_Owner);
- target.Kill(); // just in case, maybe Damage is overridden on some shard
-
- if (target.Corpse != null && !target.Player)
- {
- target.Corpse.Delete();
- }
-
- m_Owner.Focus = null;
- Stop();
- } //
-
- /*else if (!m_Owner.InRange( target, 20 ))
- {
- m_Owner.Focus = null;
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
}
- else if (!m_Owner.InRange( target, 10 ) || !m_Owner.InLOS( target ))
- {
- TeleportTo( target );
- }
- else if (!m_Owner.InRange( target, 1 ))
- {
- if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ))
- TeleportTo( target );
- }
- else if (!m_Owner.CanSee( target ))
- {
- if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0)
- m_Owner.Say( "Reveal!" );
- }*/
+ }
+ else if (_focus == null && _idleTimer == null)
+ {
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
}
- private void TeleportTo(Mobile target)
+ this.MarkDirty();
+ }
+ }
+
+ public override bool OnBeforeDeath()
+ {
+ if (_focus?.Alive == true)
+ {
+ new AvengeTimer(_focus).Start(); // If a guard dies, three more guards will spawn
+ }
+
+ return base.OnBeforeDeath();
+ }
+
+ [AfterDeserialization]
+ private void AfterDeserialization()
+ {
+ if (_focus != null)
+ {
+ _attackTimer = new AttackTimer(this);
+ _attackTimer.Start();
+ }
+ else
+ {
+ _idleTimer = new IdleTimer(this);
+ _idleTimer.Start();
+ }
+ }
+
+ public override void OnAfterDelete()
+ {
+ if (_attackTimer != null)
+ {
+ _attackTimer.Stop();
+ _attackTimer = null;
+ }
+
+ if (_idleTimer != null)
+ {
+ _idleTimer.Stop();
+ _idleTimer = null;
+ }
+
+ base.OnAfterDelete();
+ }
+
+ private class AvengeTimer : Timer
+ {
+ private readonly Mobile m_Focus;
+
+ public AvengeTimer(Mobile focus) : base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3) =>
+ m_Focus = focus;
+
+ protected override void OnTick()
+ {
+ Spawn(m_Focus, m_Focus, 1, true);
+ }
+ }
+
+ private class AttackTimer : Timer
+ {
+ private readonly WarriorGuard m_Owner;
+
+ public AttackTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1)) =>
+ m_Owner = owner;
+
+ public void DoOnTick()
+ {
+ OnTick();
+ }
+
+ protected override void OnTick()
+ {
+ if (m_Owner.Deleted)
{
- var from = m_Owner.Location;
- var to = target.Location;
+ Stop();
+ return;
+ }
- m_Owner.Location = to;
+ m_Owner.Criminal = false;
+ m_Owner.Kills = 0;
+ m_Owner.Stam = m_Owner.StamMax;
+ var target = m_Owner.Focus;
+
+ if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target)))
+ {
+ m_Owner.Focus = null;
+ Stop();
+ return;
+ }
+
+ if (m_Owner.Weapon is Fists)
+ {
+ m_Owner.Kill();
+ Stop();
+ return;
+ }
+
+ if (target != null && m_Owner.Combatant != target)
+ {
+ m_Owner.Combatant = target;
+ }
+
+ if (target == null)
+ {
+ Stop();
+ }
+ else
+ {
+ //
+ TeleportTo(target);
+ target.BoltEffect(0);
+
+ if (target is BaseCreature creature)
+ {
+ creature.NoKillAwards = true;
+ }
+
+ target.Damage(target.HitsMax, m_Owner);
+ target.Kill(); // just in case, maybe Damage is overridden on some shard
+
+ if (target.Corpse != null && !target.Player)
+ {
+ target.Corpse.Delete();
+ }
+
+ m_Owner.Focus = null;
+ Stop();
+ } //
+
+ /*else if (!m_Owner.InRange( target, 20 ))
+ {
+ m_Owner.Focus = null;
+ }
+ else if (!m_Owner.InRange( target, 10 ) || !m_Owner.InLOS( target ))
+ {
+ TeleportTo( target );
+ }
+ else if (!m_Owner.InRange( target, 1 ))
+ {
+ if (!m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ))
+ TeleportTo( target );
+ }
+ else if (!m_Owner.CanSee( target ))
+ {
+ if (!m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0)
+ m_Owner.Say( "Reveal!" );
+ }*/
+ }
+
+ private void TeleportTo(Mobile target)
+ {
+ var from = m_Owner.Location;
+ var to = target.Location;
+
+ m_Owner.Location = to;
+
+ Effects.SendLocationParticles(
+ EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration),
+ 0x3728,
+ 10,
+ 10,
+ 2023
+ );
+ Effects.SendLocationParticles(
+ EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration),
+ 0x3728,
+ 10,
+ 10,
+ 5023
+ );
+
+ m_Owner.PlaySound(0x1FE);
+ }
+ }
+
+ private class IdleTimer : Timer
+ {
+ private readonly WarriorGuard m_Owner;
+ private int m_Stage;
+
+ public IdleTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) =>
+ m_Owner = owner;
+
+ protected override void OnTick()
+ {
+ if (m_Owner.Deleted)
+ {
+ Stop();
+ return;
+ }
+
+ if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction))
+ {
+ m_Owner.Direction = (Direction)Utility.Random(8);
+ }
+
+ if (m_Stage > 16)
+ {
Effects.SendLocationParticles(
- EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration),
+ EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration),
0x3728,
10,
10,
2023
);
- Effects.SendLocationParticles(
- EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration),
- 0x3728,
- 10,
- 10,
- 5023
- );
-
m_Owner.PlaySound(0x1FE);
- }
- }
- private class IdleTimer : Timer
- {
- private readonly WarriorGuard m_Owner;
- private int m_Stage;
-
- public IdleTimer(WarriorGuard owner) : base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5)) =>
- m_Owner = owner;
-
- protected override void OnTick()
- {
- if (m_Owner.Deleted)
- {
- Stop();
- return;
- }
-
- if (m_Stage++ % 4 == 0 || !m_Owner.Move(m_Owner.Direction))
- {
- m_Owner.Direction = (Direction)Utility.Random(8);
- }
-
- if (m_Stage > 16)
- {
- Effects.SendLocationParticles(
- EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration),
- 0x3728,
- 10,
- 10,
- 2023
- );
- m_Owner.PlaySound(0x1FE);
-
- m_Owner.Delete();
- }
+ m_Owner.Delete();
}
}
}