From 8eafdd7605f80b3c07715eced86c858b305b8aec Mon Sep 17 00:00:00 2001 From: Crome696 Date: Fri, 10 Jul 2026 16:16:47 +0200 Subject: [PATCH] test: harden Rising Colossus restrictions --- .../Mysticism/RisingColossusSpellTests.cs | 107 +++++++++++++++++- .../Spells/Mysticism/RisingColossusSpell.cs | 12 +- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/Projects/UOContent.Tests/Tests/Spells/Mysticism/RisingColossusSpellTests.cs b/Projects/UOContent.Tests/Tests/Spells/Mysticism/RisingColossusSpellTests.cs index ee51d4c08..8d34c811f 100644 --- a/Projects/UOContent.Tests/Tests/Spells/Mysticism/RisingColossusSpellTests.cs +++ b/Projects/UOContent.Tests/Tests/Spells/Mysticism/RisingColossusSpellTests.cs @@ -3,8 +3,11 @@ using System.Collections.Generic; using System.Reflection; using Server.Items; using Server.Mobiles; +using Server.Multis; +using Server.Regions; using Server.Spells; using Server.Spells.Mysticism; +using Server.Text; using Xunit; namespace Server.Tests.Spells.Mysticism; @@ -143,6 +146,34 @@ public class RisingColossusSpellTests caster.Delete(); } + [Fact] + public void Serialization_PreservesDispelDifficulty() + { + var caster = NewCaster(); + var original = new RisingColossus(caster, 120.0, 120.0); + var deserialized = new RisingColossus(caster, 83.0, 0.0); + + try + { + var writer = new BufferWriter(true); + original.Serialize(writer); + var buffer = new byte[writer.Position]; + writer.Buffer.AsSpan(0, (int)writer.Position).CopyTo(buffer); + + var reader = new BufferReader(buffer); + deserialized.Deserialize(reader); + + Assert.Equal(buffer.Length, reader.Position); + Assert.Equal(original.DispelDifficulty, deserialized.DispelDifficulty); + } + finally + { + original.Delete(); + deserialized.Delete(); + caster.Delete(); + } + } + [Fact] public void CheckCast_RejectsInsufficientSkillManaAndFollowerCapacity() { @@ -184,14 +215,26 @@ public class RisingColossusSpellTests } [Fact] - public void TargetLocation_RejectsHouseLocations() + public void TargetLocation_RejectsHouseLocationsForTargetAndCaster() { var caster = NewCaster(); - var outside = new Point3D(6200, 500, 0); + var houseLocation = FindSpawnLocation(); + var outside = new Point3D(houseLocation.X + 10, houseLocation.Y + 10, houseLocation.Z); + var house = new TestHouse(caster); + house.MoveToWorld(houseLocation, Map.Felucca); - Assert.False(RisingColossusSpell.IsHouseLocation(caster, outside, Map.Felucca)); + try + { + Assert.True(RisingColossusSpell.IsHouseLocation(caster, houseLocation, Map.Felucca)); - caster.Delete(); + caster.MoveToWorld(houseLocation, Map.Felucca); + Assert.True(RisingColossusSpell.IsHouseLocation(caster, outside, Map.Felucca)); + } + finally + { + house.Delete(); + caster.Delete(); + } } [Fact] @@ -235,6 +278,41 @@ public class RisingColossusSpellTests } } + [Fact] + public void TargetLocation_RejectsCustomNoSummonRegion() + { + var previousExpansion = Core.Expansion; + Core.Expansion = Expansion.SA; + + var caster = NewCaster(); + AddReagents(caster); + var summonLocation = FindSpawnLocation(); + caster.MoveToWorld(new Point3D(summonLocation.X - 1, summonLocation.Y, summonLocation.Z), Map.Felucca); + var region = new NoSummonRegion(summonLocation); + region.Register(); + var spell = new TestRisingColossusSpell(caster); + caster.Spell = spell; + spell.State = SpellState.Sequencing; + + try + { + Assert.True(RisingColossusSpell.IsNoSummonRegion(summonLocation, Map.Felucca)); + spell.Target(summonLocation); + + Assert.Equal(100, caster.Mana); + Assert.Equal(0, caster.Followers); + Assert.Equal(10, caster.Backpack.FindItemByType().Amount); + Assert.Null(FindSummon(caster)); + } + finally + { + region.Unregister(); + spell.FinishSequence(); + caster.Delete(); + Core.Expansion = previousExpansion; + } + } + [Fact] public void BlockedTarget_DoesNotConsumeResourcesOrCreateSummon() { @@ -370,6 +448,27 @@ public class RisingColossusSpellTests SpellRegistry.SpecialMoves.Clear(); } + private sealed class NoSummonRegion : BaseRegion + { + public NoSummonRegion(Point3D location) : + base("Rising Colossus NoSummon Test", Map.Felucca, 1000, + new Rectangle3D(location.X, location.Y, -128, 1, 1, 256)) + { + } + + public override bool AllowSpawn() => false; + } + + private sealed class TestHouse : BaseHouse + { + public TestHouse(Mobile owner) : base(0, owner, 0, 0) + { + } + + public override Rectangle2D[] Area => [new Rectangle2D(-2, -2, 5, 5)]; + public override Point3D BaseBanLocation => Point3D.Zero; + } + private sealed class TestRisingColossusSpell : RisingColossusSpell { public TestRisingColossusSpell(Mobile caster) : base(caster) diff --git a/Projects/UOContent/Spells/Mysticism/RisingColossusSpell.cs b/Projects/UOContent/Spells/Mysticism/RisingColossusSpell.cs index 833358d61..f570ad9f9 100644 --- a/Projects/UOContent/Spells/Mysticism/RisingColossusSpell.cs +++ b/Projects/UOContent/Spells/Mysticism/RisingColossusSpell.cs @@ -44,6 +44,9 @@ public class RisingColossusSpell : MysticSpell, ITargetingSpell return caster.Map != null && Region.Find(caster.Location, caster.Map).IsPartOf(); } + internal static bool IsNoSummonRegion(Point3D location, Map map) => + map == null || !Region.Find(location, map).AllowSpawn(); + public override bool CheckCast() { if (!base.CheckCast()) @@ -70,19 +73,22 @@ public class RisingColossusSpell : MysticSpell, ITargetingSpell var map = Caster.Map; SpellHelper.GetSurfaceTop(ref point); + var location = new Point3D(point); - if (map?.CanSpawnMobile(point.X, point.Y, point.Z) != true || IsHouseLocation(Caster, new Point3D(point), map)) + if (map?.CanSpawnMobile(location) != true || + IsNoSummonRegion(location, map) || + IsHouseLocation(Caster, location, map)) { Caster.SendLocalizedMessage(501942); // That location is blocked. } - else if (SpellHelper.CheckTown(point, Caster) && CheckSequence()) + else if (SpellHelper.CheckTown(location, Caster) && CheckSequence()) { var mysticism = GetBaseSkill(Caster); var supportSkill = GetDamageSkill(Caster); var duration = GetDuration(mysticism, supportSkill); var summon = new RisingColossus(Caster, mysticism, supportSkill); - if (BaseCreature.Summon(summon, false, Caster, new Point3D(point), 0x656, duration)) + if (BaseCreature.Summon(summon, false, Caster, location, 0x656, duration)) { Effects.SendTargetParticles(summon, 0x3728, 10, 10, 0x13AA, (EffectLayer)255); }