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();
}
}
}
}