338 lines
9.4 KiB
C#
338 lines
9.4 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
|
|
using Server;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
using Server.Engines.CityLoyalty;
|
|
using Server.Spells;
|
|
using Server.Network;
|
|
using Server.Commands;
|
|
using Server.Gumps;
|
|
|
|
namespace Server.Engines.SeasonalEvents
|
|
{
|
|
[PropertyObject]
|
|
public class KrampusEncounter
|
|
{
|
|
public static string FilePath = Path.Combine("Saves/Misc", "KrampusEncounter.bin");
|
|
|
|
public static bool Enabled { get { return SeasonalEventSystem.IsActive(EventType.KrampusEncounter); } }
|
|
public static KrampusEncounter Encounter { get; set; }
|
|
|
|
public static readonly int MinComplete = 20;
|
|
|
|
public static void Configure()
|
|
{
|
|
EventSink.WorldSave += OnSave;
|
|
EventSink.WorldLoad += OnLoad;
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
CommandSystem.Register("KrampusEncounter", AccessLevel.Administrator, e =>
|
|
{
|
|
if (Encounter != null)
|
|
{
|
|
e.Mobile.SendGump(new PropertiesGump(e.Mobile, Encounter));
|
|
}
|
|
else
|
|
{
|
|
e.Mobile.SendMessage("Encounter null");
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void OnSave(WorldSaveEventArgs e)
|
|
{
|
|
CheckEnabled();
|
|
|
|
Persistence.Serialize(
|
|
FilePath,
|
|
writer =>
|
|
{
|
|
writer.Write(0);
|
|
|
|
if (Encounter != null)
|
|
{
|
|
writer.Write(1);
|
|
Encounter.Serialize(writer);
|
|
}
|
|
else
|
|
{
|
|
writer.Write(0);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void OnLoad()
|
|
{
|
|
Persistence.Deserialize(
|
|
FilePath,
|
|
reader =>
|
|
{
|
|
reader.ReadInt(); // version
|
|
|
|
if (reader.ReadInt() == 1)
|
|
{
|
|
Encounter = new KrampusEncounter();
|
|
Encounter.Deserialize(reader);
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void CheckEnabled()
|
|
{
|
|
if (Enabled)
|
|
{
|
|
if (Encounter == null)
|
|
{
|
|
Encounter = new KrampusEncounter();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (Encounter != null && Encounter.Krampus == null)
|
|
{
|
|
Encounter = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public static bool KrampusSpawned()
|
|
{
|
|
return Enabled && Encounter != null && Encounter.Krampus != null && !Encounter.Krampus.Deleted;
|
|
}
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int TotalTradesComplete { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public int Wave { get { return (int)Math.Max(1, (int)Math.Min(6, (double)TotalTradesComplete / 4.1)); } }
|
|
|
|
public Dictionary<PlayerMobile, int> CompleteTable { get; set; } = new Dictionary<PlayerMobile, int>();
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public Krampus Krampus { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public Point3D SpawnLocation { get; set; }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public bool KrampusSpawning { get { return SpawnMap != null && SpawnLocation != Point3D.Zero; } }
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public Map SpawnMap { get; set; }
|
|
|
|
public KrampusEncounter()
|
|
{
|
|
}
|
|
|
|
public void OnTradeComplete(Mobile m, TradeEntry entry)
|
|
{
|
|
bool distCheck = entry.Distance > 0;
|
|
|
|
// 0 distance indicates they used a moongate
|
|
if (m is PlayerMobile && distCheck)
|
|
{
|
|
var pm = (PlayerMobile)m;
|
|
|
|
if (!CompleteTable.ContainsKey(pm))
|
|
{
|
|
CompleteTable[pm] = 1;
|
|
}
|
|
else
|
|
{
|
|
CompleteTable[pm]++;
|
|
}
|
|
}
|
|
|
|
if (TotalTradesComplete > MinComplete || distCheck)
|
|
{
|
|
TotalTradesComplete++;
|
|
}
|
|
}
|
|
|
|
public Type[] GetCreatureTypes(Mobile m, bool wet)
|
|
{
|
|
if (Krampus != null || KrampusSpawning)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (wet)
|
|
{
|
|
return _WetSpawnTypes;
|
|
}
|
|
else
|
|
{
|
|
var wave = (int)Math.Max(1, (int)Math.Min(6, (double)TotalTradesComplete / 4.1)); // TODO: Is this right?
|
|
|
|
if (wave == 6)
|
|
{
|
|
if ((m.Map == Map.Trammel || (Siege.SiegeShard && m.Map == Map.Felucca)) && !SpellHelper.IsAnyT2A(m.Map, m.Location))
|
|
{
|
|
SpawnKrampus(m);
|
|
|
|
return null;
|
|
}
|
|
|
|
return _SpawnTypes[4];
|
|
}
|
|
|
|
return _SpawnTypes[wave - 1];
|
|
}
|
|
}
|
|
|
|
private void SpawnKrampus(Mobile m)
|
|
{
|
|
SpawnMap = m.Map;
|
|
var p = m.Location;
|
|
|
|
for (int i = 0; i < 25; i++)
|
|
{
|
|
int x = p.X + (Utility.RandomMinMax(-3, 3));
|
|
int y = p.Y + (Utility.RandomMinMax(-3, 3));
|
|
int z = m.Map.GetAverageZ(x, y);
|
|
|
|
if (SpawnMap.CanSpawnMobile(x, y, z))
|
|
{
|
|
p = new Point3D(x, y, z);
|
|
break;
|
|
}
|
|
}
|
|
|
|
SpawnLocation = p;
|
|
|
|
foreach (var ns in NetState.Instances)
|
|
{
|
|
var mob = ns.Mobile;
|
|
|
|
if (mob != null && CityTradeSystem.HasTrade(mob))
|
|
{
|
|
mob.LocalOverheadMessage(MessageType.Regular, 1150, 1158832, String.Format("{0}\t{1}", WorldLocationInfo.GetLocationString(SpawnLocation, SpawnMap), Sextant.GetCoords(SpawnLocation, SpawnMap))); // *You sense Krampus has been spotted near ~2_where~ at ~1_coords~!*
|
|
}
|
|
}
|
|
|
|
Timer.DelayCall(TimeSpan.FromMinutes(5), () =>
|
|
{
|
|
SpawnKrampus();
|
|
});
|
|
}
|
|
|
|
private void SpawnKrampus()
|
|
{
|
|
Krampus = new Krampus();
|
|
Krampus.SpawnLocation = SpawnLocation;
|
|
Krampus.Home = SpawnLocation;
|
|
Krampus.RangeHome = 5;
|
|
|
|
Krampus.MoveToWorld(SpawnLocation, SpawnMap);
|
|
Krampus.Summon(Krampus, true);
|
|
|
|
var rec = new Rectangle2D(SpawnLocation.X - 10, SpawnLocation.Y - 10, 20, 20);
|
|
|
|
for (var i = 0; i < 2; i++)
|
|
{
|
|
var drake = new FrostDrake();
|
|
|
|
Point3D p = new Point3D(SpawnLocation);
|
|
|
|
for (int j = 0; i < 10; j++)
|
|
{
|
|
p = SpawnMap.GetRandomSpawnPoint(rec);
|
|
|
|
if (SpawnMap.CanSpawnMobile(p.X, p.Y, p.Z))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
drake.MoveToWorld(p, SpawnMap);
|
|
drake.Home = p;
|
|
drake.RangeHome = 15;
|
|
}
|
|
|
|
SpawnLocation = Point3D.Zero;
|
|
SpawnMap = null;
|
|
}
|
|
|
|
public void OnKrampusKilled()
|
|
{
|
|
Krampus = null;
|
|
|
|
CompleteTable.Clear();
|
|
TotalTradesComplete = 0;
|
|
|
|
if (!Enabled)
|
|
{
|
|
Encounter = null;
|
|
}
|
|
}
|
|
|
|
public Type[][] _SpawnTypes =
|
|
{
|
|
new Type[] { typeof(FrostOoze), typeof(FrostSpider) },
|
|
new Type[] { typeof(SnowElemental), typeof(IceElemental) },
|
|
new Type[] { typeof(IceSerpent), typeof(FrostTroll) },
|
|
new Type[] { typeof(IceFiend), typeof(WhiteWyrm) },
|
|
new Type[] { typeof(KrampusMinion) },
|
|
new Type[] { typeof(Krampus) }
|
|
};
|
|
|
|
public Type[] _WetSpawnTypes =
|
|
{
|
|
typeof(SeaSerpent), typeof(DeepSeaSerpent), typeof(Kraken), typeof(WaterElemental)
|
|
};
|
|
|
|
public void Serialize(GenericWriter writer)
|
|
{
|
|
writer.Write(0);
|
|
|
|
writer.Write(Krampus);
|
|
writer.Write(SpawnLocation);
|
|
writer.Write(SpawnMap);
|
|
|
|
writer.Write(TotalTradesComplete);
|
|
|
|
writer.Write(CompleteTable.Count);
|
|
|
|
foreach (var kvp in CompleteTable)
|
|
{
|
|
writer.Write(kvp.Key);
|
|
writer.Write(kvp.Value);
|
|
}
|
|
}
|
|
|
|
public void Deserialize(GenericReader reader)
|
|
{
|
|
reader.ReadInt();
|
|
|
|
Krampus = reader.ReadMobile() as Krampus;
|
|
SpawnLocation = reader.ReadPoint3D();
|
|
SpawnMap = reader.ReadMap();
|
|
|
|
TotalTradesComplete = reader.ReadInt();
|
|
|
|
int count = reader.ReadInt();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var m = reader.ReadMobile() as PlayerMobile;
|
|
var c = reader.ReadInt();
|
|
|
|
if (m != null)
|
|
{
|
|
CompleteTable[m] = c;
|
|
}
|
|
}
|
|
|
|
if (KrampusSpawning && Krampus == null)
|
|
{
|
|
Timer.DelayCall(TimeSpan.FromMinutes(2), SpawnKrampus);
|
|
}
|
|
}
|
|
}
|
|
}
|