#W# New: Portal Spawner that spawns a mob. if the mob doesn't have a combatant after 3 mins it despawns.

This commit is contained in:
WarrentyExpired 2026-10-30 21:04:26 -04:00
parent 21a4cc1ce5
commit 00c25cd506
3 changed files with 175 additions and 0 deletions

View file

@ -0,0 +1,89 @@
using System;
using ModernUO.Serialization;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Custom.Events
{
[SerializationGenerator(0)]
public partial class PortalSpawner : Item
{
private bool _triggered;
[Constructible]
public PortalSpawner() : base(0x0F6C)
{
Name = "a horrific tear";
Hue = 1157;
Movable = false;
Light = LightType.Circle300;
}
public PortalSpawner(Serial serial) : base(serial)
{
}
public override bool HandlesOnMovement => true;
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (_triggered || Deleted)
return;
if (m.AccessLevel > AccessLevel.Player || !m.Alive || !(m is PlayerMobile))
return;
if (Utility.InRange(Location, m.Location, 8))
{
TriggerAmbush(m);
}
}
private void TriggerAmbush(Mobile target)
{
_triggered = true;
Effects.PlaySound(Location, Map, 0x20F);
Effects.SendLocationEffect(Location, Map, 0x3728, 10, 10);
Effects.SendLocationEffect(Location, Map, 0x3709, 10, 30, 1153, 0);
try
{
BaseCreature ambushMonster = null;
string ambushMessage = "A terrifying creature bursts from the portal!";
switch (Utility.Random(2))
{
case 0:
ambushMonster = new PortalDaemon();
ambushMessage = "A daemon tears through the portal to ambush you!";
break;
case 1:
ambushMonster = new PortalWyvern();
ambushMessage = "A furious dragon bursts through the portal to ambush you!";
break;
}
if (ambushMonster != null)
{
ambushMonster.MoveToWorld(Location, Map);
ambushMonster.PlaySound(ambushMonster.GetAngerSound());
ambushMonster.Combatant = target;
target.SendMessage(89, ambushMessage);
}
}
catch (Exception e)
{
Console.WriteLine($"Error spawning portal monster: {e.Message}");
}
Delete();
}
}
}

View file

@ -0,0 +1,45 @@
using System;
using Server;
using ModernUO.Serialization;
using Server.Items;
namespace Server.Mobiles
{
[SerializationGenerator(0, false)]
public partial class PortalDaemon : Daemon
{
// Removed [Save] - it will now self-clean automatically on server restarts!
private DateTime _DespawnTime;
[Constructible]
public PortalDaemon() : base()
{
// Give it 3 minutes of inactivity before it despawns
_DespawnTime = DateTime.UtcNow + TimeSpan.FromMinutes(3);
}
public override void OnThink()
{
base.OnThink();
if (Deleted) return;
if (Combatant != null)
{
// As long as it is fighting a player or pet, constantly reset the clock
_DespawnTime = DateTime.UtcNow + TimeSpan.FromMinutes(3);
}
else if (DateTime.UtcNow > _DespawnTime)
{
// The clock ran out and it has no combatant. Clean it up!
Effects.SendLocationEffect(Location, Map, 0x3728, 10, 10); // Smoke puff
PlaySound(0x1FD); // Eerie fade out sound
Delete();
}
}
public PortalDaemon(Serial serial) : base(serial)
{
}
}
}

View file

@ -0,0 +1,41 @@
using System;
using Server;
using ModernUO.Serialization;
using Server.Items;
namespace Server.Mobiles
{
[SerializationGenerator(0, false)]
public partial class PortalWyvern : AncientWyvern
{
private DateTime _DespawnTime;
[Constructible]
public PortalWyvern() : base()
{
_DespawnTime = DateTime.UtcNow + TimeSpan.FromMinutes(3);
}
public override void OnThink()
{
base.OnThink();
if (Deleted) return;
if (Combatant != null)
{
_DespawnTime = DateTime.UtcNow + TimeSpan.FromMinutes(3);
}
else if (DateTime.UtcNow > _DespawnTime)
{
Effects.SendLocationEffect(Location, Map, 0x3728, 10, 10);
PlaySound(0x1FD);
Delete();
}
}
public PortalWyvern(Serial serial) : base(serial)
{
}
}
}