PigPen

Member
ServUO Version
Publish Unknown
Ultima Expansion
Mondain's Legacy
I have a RunUO server that has been going for several years but still run into tings I don't understand.

I have been trying for the past few weeks to get a Champ style XML Spawner working like a Champion spawn should. But . . . every time I try adjusting it , players continue to have the same problem with it.

The spawner triggers fine if a player has the Trigger item in their pack but after that the troubles begin. The first two waves of the spawn go off as intended but that is the end of it. The third and following spawn waves never happen.

I am uploading screen shots of the XML Spawner setup and also the XML Spawner Properties.

It is a mystery to me because everything I see in the setup looks good. Can anyone in the community see where I have gone wrong?

Any guidance to help solve this is really appreciated.
 

Attachments

  • ChampSpawnerSetup.jpg
    ChampSpawnerSetup.jpg
    1.1 MB · Views: 9
  • ChampSpawnerProps.jpg
    ChampSpawnerProps.jpg
    926.5 KB · Views: 9
You might want to try a different approach. Its actually really easy to add new Champ Spawns to the champ spawns system, just check out ChampionSpawnType.cs and add your new champion type to the list. Then create a new champ spawner wherever you want and set the Props to your new type
 
I thought of that but also thought it might be easier using the XML Spawner system because I had believed it would work. If this is not possible then for sure I will be scripting it (or trying to) through the Champion system. Thank you for the good input.
 
I decided to forget the XMLSpawner approach because I just can't get comfortable I can make it work (after many tries).

I also decided not to mess with my Champion files so in the end I just made a script for a custom Champion style set up that gets triggered by a 'Quest Marker' given to a player by a NPC Quest Giver. In my case the 'Quest Marker' is a weightless Diamond that is invisible and does not count toward a player's backpack item count by inserting this in the Marker script:

public override bool IsVirtualItem { get { return true; } }

In thanks to the community for looking at this thread (and many others I have posted) . . .

Here is my custom Champ script (Note: made for RunUO with C#):
Code:
using System;
using System.Collections.Generic;
using Server;
using Server.Network;
using Server.Items;
using Server.Mobiles;
using Timer = Server.Timer;

namespace Server
{
    public static class LadyGreySeradoController
    {
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        // change the three (coords/map/radius) for Test or for Live server
        private static readonly Point3D SpawnCenter = new Point3D(7128, 641, 1);
        private static readonly Map     SpawnMap    = Map.Felucca;
        private const double            Radius      = 30.0;
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        private static bool               EventActive;
        private static int                CurrentWave;
        private static SeradoTimeoutTimer Timeout;
        private static SeradoWaveTimer    WaveTimer;
        private static readonly List<Mobile> Spawned    = new List<Mobile>();
        private static readonly List<Mobile> CurrentList = new List<Mobile>();

        private struct WaveInfo
        {
            public Type CreatureType;
            public int  SpawnCount;
            public int  KillThreshold;

            public WaveInfo(Type t, int c, int k)
            {
                CreatureType  = t;
                SpawnCount    = c;
                KillThreshold = k;
            }
        }

    /*
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        // Below are Test wave values (edit as you like for testing)
        // Note: WaveInfo(typeof(LGreyChampGorilla), MaxSpawn, ToKill)
        // MaxSpawn = total number in spawn wave
        // ToKill = number to kill in order to spawn the next wave
        private static readonly WaveInfo[] Waves = new WaveInfo[]
        {
            new WaveInfo(typeof(LGreyChampGorilla),    10, 4),
            new WaveInfo(typeof(LGreyChampWaterEl),    8,  3),
            new WaveInfo(typeof(LGreyChampHarrower),   5,  3),
            new WaveInfo(typeof(LGreyChampWhiteWolf),  3,  2),
            new WaveInfo(typeof(LGreyChampSilverSerp), 3,  2),
            new WaveInfo(typeof(LGreyChampDrake),      3,  1),
            new WaveInfo(typeof(LGreyChampBogling),    2,  1),
            new WaveInfo(typeof(LGreyChampSuccubus),   2,  1),
            new WaveInfo(typeof(LGreyChampSatyr),      2,  1),
            new WaveInfo(typeof(LGSeradoChamp),        1,  1),
            new WaveInfo(typeof(LGreyChampWisp),       1,  1)//dummy to assue that the Boss spawns
        };
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    */

        // Actual Live Server 9 spawn waves + final Boss:
        private static readonly WaveInfo[] Waves = new WaveInfo[]                      {
            new WaveInfo(typeof(LGreyChampGorilla),    30, 20),
            new WaveInfo(typeof(LGreyChampWaterEl),    25, 17),
            new WaveInfo(typeof(LGreyChampHarrower),   25, 16),
            new WaveInfo(typeof(LGreyChampWhiteWolf),  20, 14),
            new WaveInfo(typeof(LGreyChampSilverSerp), 20, 14),
            new WaveInfo(typeof(LGreyChampDrake),      15, 11),
            new WaveInfo(typeof(LGreyChampBogling),    15, 10),
            new WaveInfo(typeof(LGreyChampSuccubus),   10,  6),
            new WaveInfo(typeof(LGreyChampSatyr),      10,  6),
            new WaveInfo(typeof(LGSeradoChamp),         1,  1),
            new WaveInfo(typeof(LGreyChampWisp),        1,  1) //dummy to assue that the Boss spawns
        };

        public static void Initialize()
        {
            EventSink.Movement += new MovementEventHandler(OnMovement);
        }

        private static void OnMovement(MovementEventArgs e)
        {
            if (EventActive)
                return;

            PlayerMobile pm = e.Mobile as PlayerMobile;
            if (pm == null)
                return;

            if (pm.Map != SpawnMap)
                return;

            if (!pm.InRange(SpawnCenter, (int)Radius))
                return;

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        // Consume quest trigger within the radius range and send message
            if (pm.Backpack.ConsumeTotal(typeof(LadyGreyChampMarker01), 1))
            {
                pm.SendMessage(0x21, "You ground trembles around you.");
                StartEvent();
            }
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        }

        private static void StartEvent()
        {
            EventActive = true;
            CurrentWave = 0;
            Spawned.Clear();
            CurrentList.Clear();

            SpawnWave();

            // auto-cleanup
            Timeout = new SeradoTimeoutTimer();
            Timeout.Start();

            // start polling to advance waves
            WaveTimer = new SeradoWaveTimer();
            WaveTimer.Start();
        }

        private static void SpawnWave()
        {
            WaveInfo info = Waves[CurrentWave];

            CurrentList.Clear();
            for (int i = 0; i < info.SpawnCount; i++)
            {
                for (int tries = 0; tries < 10; tries++)
                {
                    int dx = Utility.RandomMinMax(-(int)Radius, (int)Radius);
                    int dy = Utility.RandomMinMax(-(int)Radius, (int)Radius);

                    if ((dx * dx + dy * dy) > (Radius * Radius))
                        continue;

                    int x = SpawnCenter.X + dx;
                    int y = SpawnCenter.Y + dy;
                    int z = SpawnMap.GetAverageZ(x, y);

                    if (!SpawnMap.CanFit(x, y, z, 16, false, false))
                        continue;

                    Mobile m = (Mobile)Activator.CreateInstance(info.CreatureType);
                    m.MoveToWorld(new Point3D(x, y, z), SpawnMap);
                    Spawned.Add(m);
                    CurrentList.Add(m);
                    break;
                }
            }
        }

        private static void CheckWave()
        {
            if (!EventActive)
                return;

            WaveInfo wave = Waves[CurrentWave];
            int deadCount = 0;

            foreach (Mobile m in CurrentList)
            {
                if (m == null || m.Deleted || !m.Alive)
                    deadCount++;
            }

            if (deadCount < wave.KillThreshold)
                return;

            CurrentWave++;
            if (CurrentWave < Waves.Length)
            {
                SpawnWave();
            }

        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        // Message when Boss is slain - Then cleans up remaining live ones
            else
            {
                World.Broadcast(0x21, true, "The King's revenge has been delivered!");
                //Cleanup();
            }
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        }

        private static void Cleanup()
        {
            if (!EventActive)
                return;

            EventActive = false;

            if (Timeout != null)
                Timeout.Stop();

            if (WaveTimer != null)
                WaveTimer.Stop();

            for (int i = 0; i < Spawned.Count; i++)
            {
                Mobile m = Spawned[i];
                if (m != null && !m.Deleted && m.Alive)
                    m.Delete();
            }

            Spawned.Clear();
            CurrentList.Clear();
        }

        private class SeradoTimeoutTimer : Timer
        {
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        // Change 'Duration' of activity here if needed for Testing:
        // ie.  change the 250 to 5 for a 5 minute duration
            public SeradoTimeoutTimer()
                : base(TimeSpan.FromMinutes(250), TimeSpan.Zero)
            {
                Priority = TimerPriority.OneSecond;
            }
        // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

            protected override void OnTick()
            {
                Cleanup();
            }
        }

        private class SeradoWaveTimer : Timer
        {
            public SeradoWaveTimer()
                : base(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(5))
            {
                Priority = TimerPriority.TwoFiftyMS;
            }

            protected override void OnTick()
            {
                CheckWave();
            }
        }
    }
}

NOTE: If anyone decides to use this . . read the comments I have inserted and make your own creatures for the Spawn waves and the Boss.

Thanks again and Cheers!
 

Active Shards

Donations

Total amount
$0.00
Goal
$500.00
Back