501 lines
18 KiB
C#
501 lines
18 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Collections.Generic;
|
|
|
|
using Server;
|
|
using Server.Items;
|
|
using Server.Mobiles;
|
|
|
|
namespace Server.Items
|
|
{
|
|
public class PlunderBeaconAddon : BaseAddon
|
|
{
|
|
public static readonly int MaxSpawn = 5;
|
|
|
|
[CommandProperty(AccessLevel.GameMaster)]
|
|
public PlunderBeacon Beacon { get; set; }
|
|
|
|
public List<BaseCreature> Crew { get; set; }
|
|
public Dictionary<BaseCreature, bool> Spawn { get; set; }
|
|
public List<MannedCannon> Cannons { get; set; }
|
|
|
|
public bool CannonsOperational { get { return Crew.Any(c => c.Alive && !c.Deleted); } }
|
|
public bool BeaconVulnerable { get { return !CannonsOperational; } }
|
|
|
|
public override BaseAddonDeed Deed { get { return null; } }
|
|
|
|
public Timer Timer { get; set; }
|
|
public DateTime NextShoot { get; set; }
|
|
public DateTime NextSpawn { get; set; }
|
|
public bool InitialSpawn { get; set; }
|
|
|
|
[Constructable]
|
|
public PlunderBeaconAddon()
|
|
{
|
|
for (int i = 0; i < m_AddOnSimpleComponents.Length / 4; i++)
|
|
AddComponent(new AddonComponent(m_AddOnSimpleComponents[i, 0]), m_AddOnSimpleComponents[i, 1], m_AddOnSimpleComponents[i, 2], m_AddOnSimpleComponents[i, 3]);
|
|
|
|
AddComplexComponent((BaseAddon)this, 2572, 0, 2, 37, 0, 5, "", 1);
|
|
AddComplexComponent((BaseAddon)this, 2567, 2, 0, 37, 0, 5, "", 1);
|
|
|
|
Crew = new List<BaseCreature>();
|
|
Spawn = new Dictionary<BaseCreature, bool>();
|
|
Cannons = new List<MannedCannon>();
|
|
|
|
Beacon = new PlunderBeacon(this);
|
|
Beacon.MoveToWorld(new Point3D(X + 1, Y + 1, Z + 14), Map);
|
|
|
|
AddCannon(Direction.South, CannonPower.Massive, -3, 5, 7);
|
|
AddCannon(Direction.South, CannonPower.Massive, -1, 5, 7);
|
|
AddCannon(Direction.South, CannonPower.Massive, 1, 5, 7);
|
|
AddCannon(Direction.South, CannonPower.Massive, 3, 5, 7);
|
|
|
|
AddCannon(Direction.North, CannonPower.Massive, -3, -4, 7);
|
|
AddCannon(Direction.North, CannonPower.Massive, -1, -4, 7);
|
|
AddCannon(Direction.North, CannonPower.Massive, 1, -4, 7);
|
|
AddCannon(Direction.North, CannonPower.Massive, 3, -4, 7);
|
|
|
|
AddCannon(Direction.West, CannonPower.Light, -2, -2, 12, false);
|
|
AddCannon(Direction.West, CannonPower.Light, -2, 0, 12, false);
|
|
AddCannon(Direction.West, CannonPower.Light, -2, 2, 12, false);
|
|
|
|
AddCannon(Direction.East, CannonPower.Light, 2, -2, 12, false);
|
|
AddCannon(Direction.East, CannonPower.Light, 2, 0, 12, false);
|
|
AddCannon(Direction.East, CannonPower.Light, 2, 2, 12, false);
|
|
|
|
Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
|
|
}
|
|
|
|
private void AddCannon(Direction d, CannonPower type, int xOffset, int yOffset, int zOffset, bool oper = true)
|
|
{
|
|
MannedCannon cannon;
|
|
BaseCreature mob = null;
|
|
|
|
if (oper)
|
|
{
|
|
mob = new PirateCrew();
|
|
mob.CantWalk = true;
|
|
|
|
Crew.Add(mob);
|
|
}
|
|
|
|
switch (type)
|
|
{
|
|
default:
|
|
case CannonPower.Light:
|
|
cannon = new MannedCulverin(mob, d); break;
|
|
case CannonPower.Heavy:
|
|
cannon = new MannedCarronade(mob, d); break;
|
|
case CannonPower.Massive:
|
|
cannon = new MannedBlundercannon(mob, d); break;
|
|
}
|
|
|
|
if (mob == null)
|
|
{
|
|
cannon.CanFireUnmanned = true;
|
|
}
|
|
|
|
cannon.MoveToWorld(new Point3D(X + xOffset, Y + yOffset, Z + zOffset), Map);
|
|
Cannons.Add(cannon);
|
|
|
|
if (mob != null)
|
|
{
|
|
Point3D offset;
|
|
|
|
switch (d)
|
|
{
|
|
default:
|
|
case Direction.South:
|
|
offset = new Point3D(0, -1, 0); break;
|
|
case Direction.North:
|
|
offset = new Point3D(0, 1, 0); break;
|
|
case Direction.West:
|
|
offset = new Point3D(1, 0, 0); break;
|
|
case Direction.East:
|
|
offset = new Point3D(-1, 0, 0); break;
|
|
}
|
|
|
|
mob.MoveToWorld(new Point3D(cannon.X + offset.X, cannon.Y + offset.Y, cannon.Z + offset.Z), Map);
|
|
}
|
|
}
|
|
|
|
public override void OnLocationChange(Point3D old)
|
|
{
|
|
base.OnLocationChange(old);
|
|
|
|
foreach (var c in Cannons)
|
|
{
|
|
c.Location = new Point3D(X + (c.X - old.X), Y + (c.Y - old.Y), Z + (c.Z - old.Z));
|
|
}
|
|
|
|
foreach (var c in Crew)
|
|
{
|
|
c.Location = new Point3D(X + (c.X - old.X), Y + (c.Y - old.Y), Z + (c.Z - old.Z));
|
|
}
|
|
|
|
foreach (var c in Spawn.Keys.Where(c => c != null && !c.Deleted))
|
|
{
|
|
c.Location = new Point3D(X + (c.X - old.X), Y + (c.Y - old.Y), Z + (c.Z - old.Z));
|
|
}
|
|
|
|
if (Beacon != null)
|
|
{
|
|
Beacon.Location = new Point3D(X + (Beacon.X - old.X), Y + (Beacon.Y - old.Y), Z + (Beacon.Z - old.Z));
|
|
}
|
|
}
|
|
|
|
public override void OnMapChange()
|
|
{
|
|
base.OnMapChange();
|
|
|
|
foreach (var c in Cannons)
|
|
{
|
|
c.Map = Map;
|
|
}
|
|
|
|
foreach (var c in Crew.Where(c => c != null && !c.Deleted))
|
|
{
|
|
c.Map = Map;
|
|
}
|
|
|
|
foreach (var c in Spawn.Keys.Where(c => c != null && !c.Deleted))
|
|
{
|
|
c.Map = Map;
|
|
}
|
|
|
|
if (Beacon != null)
|
|
{
|
|
Beacon.Map = Map;
|
|
}
|
|
}
|
|
|
|
public void OnBeaconDestroyed()
|
|
{
|
|
if (Deleted)
|
|
return;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
Timer.DelayCall(TimeSpan.FromSeconds(3 + (i * 3)), stage =>
|
|
{
|
|
Z -= 1;
|
|
|
|
if (stage == 3)
|
|
{
|
|
Delete();
|
|
}
|
|
}, i);
|
|
}
|
|
}
|
|
|
|
public override void OnSectorActivate()
|
|
{
|
|
if (Timer == null)
|
|
{
|
|
Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
|
|
}
|
|
}
|
|
|
|
public override void OnSectorDeactivate()
|
|
{
|
|
if (Timer != null && SpawnCount() >= MaxSpawn)
|
|
{
|
|
Timer.Stop();
|
|
Timer = null;
|
|
}
|
|
}
|
|
|
|
public void OnTick()
|
|
{
|
|
var map = Map;
|
|
|
|
if (map == null)
|
|
{
|
|
return;
|
|
}
|
|
else if (!InitialSpawn)
|
|
{
|
|
for (int i = 0; i < MaxSpawn; i++)
|
|
{
|
|
SpawnHelper(true);
|
|
InitialSpawn = true;
|
|
}
|
|
}
|
|
else if (CannonsOperational && NextShoot < DateTime.UtcNow)
|
|
{
|
|
foreach (var cannon in Cannons.Where(c => c != null && !c.Deleted && (c.CanFireUnmanned || (c.Operator != null && !c.Operator.Deleted && c.Operator.Alive))))
|
|
{
|
|
cannon.Scan(true);
|
|
}
|
|
|
|
NextShoot = DateTime.UtcNow + TimeSpan.FromSeconds(2);
|
|
}
|
|
|
|
if (NextSpawn < DateTime.UtcNow)
|
|
{
|
|
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
|
|
{
|
|
if (SpawnCount() < MaxSpawn)
|
|
{
|
|
SpawnHelper(false);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
private void SpawnHelper(bool initial)
|
|
{
|
|
if (Map == null || Beacon == null)
|
|
return;
|
|
|
|
Point3D p = Location;
|
|
var map = Map;
|
|
var range = 15;
|
|
|
|
if (Beacon.LastDamager != null && Beacon.LastDamager.InRange(Location, 20))
|
|
{
|
|
p = Beacon.LastDamager.Location;
|
|
range = 8;
|
|
}
|
|
|
|
BaseCreature creature = Activator.CreateInstance(_SpawnTypes[Utility.Random(_SpawnTypes.Length)]) as BaseCreature;
|
|
|
|
for (int i = 0; i < 50; i++)
|
|
{
|
|
var spawnLoc = new Point3D(Utility.RandomMinMax(p.X - range, p.X + range), Utility.RandomMinMax(p.Y - range, p.Y + range), -5);
|
|
|
|
if (map.CanFit(spawnLoc.X, spawnLoc.Y, spawnLoc.Z, 16, true, true, false, creature))
|
|
{
|
|
if (creature != null)
|
|
{
|
|
creature.MoveToWorld(spawnLoc, map);
|
|
creature.Home = spawnLoc;
|
|
creature.RangeHome = 10;
|
|
|
|
if (creature.IsSoulboundEnemies)
|
|
creature.IsSoulbound = true;
|
|
|
|
Spawn.Add(creature, initial);
|
|
|
|
NextSpawn = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
creature.Delete();
|
|
}
|
|
|
|
private int SpawnCount()
|
|
{
|
|
return Spawn.Keys.Where(s => s != null && !s.Deleted).Count();
|
|
}
|
|
|
|
private Type[] _SpawnTypes =
|
|
{
|
|
typeof(WaterElemental),
|
|
typeof(SeaSerpent),
|
|
typeof(DeepSeaSerpent)
|
|
};
|
|
|
|
public override void Delete()
|
|
{
|
|
base.Delete();
|
|
|
|
if (Beacon != null && !Beacon.Deleted)
|
|
{
|
|
Beacon.Delete();
|
|
}
|
|
|
|
if (Timer != null)
|
|
{
|
|
Timer.Stop();
|
|
Timer = null;
|
|
}
|
|
|
|
foreach (var bc in Crew.Where(c => c != null && !c.Deleted))
|
|
{
|
|
bc.Kill();
|
|
}
|
|
|
|
foreach (var bc in Spawn.Keys.Where(sp => sp != null && !sp.Deleted))
|
|
{
|
|
bc.Kill();
|
|
}
|
|
|
|
foreach (var cannon in Cannons)
|
|
{
|
|
cannon.Delete();
|
|
}
|
|
|
|
if (PlunderBeaconSpawner.Spawner != null)
|
|
{
|
|
PlunderBeaconSpawner.Spawner.RemovePlunderBeacon(this);
|
|
}
|
|
}
|
|
|
|
public bool Contains(IPoint3D p)
|
|
{
|
|
return p.X >= X - 8 && p.X <= X + 8 && p.Y >= Y - 8 && p.Y <= Y + 8;
|
|
}
|
|
|
|
public PlunderBeaconAddon( Serial serial ) : base( serial )
|
|
{
|
|
}
|
|
|
|
public override void Serialize(GenericWriter writer)
|
|
{
|
|
base.Serialize(writer);
|
|
writer.Write(1); // Version
|
|
|
|
writer.Write(InitialSpawn);
|
|
|
|
writer.WriteItem<PlunderBeacon>(Beacon);
|
|
|
|
writer.WriteItemList(Cannons, true);
|
|
writer.WriteMobileList(Crew, true);
|
|
//writer.WriteMobileList(Spawn, true);
|
|
|
|
writer.Write(Spawn.Count);
|
|
|
|
foreach (var kvp in Spawn)
|
|
{
|
|
writer.WriteMobile(kvp.Key);
|
|
writer.Write(kvp.Value);
|
|
}
|
|
}
|
|
|
|
public override void Deserialize(GenericReader reader)
|
|
{
|
|
base.Deserialize(reader);
|
|
int version = reader.ReadInt();
|
|
|
|
switch (version)
|
|
{
|
|
case 1:
|
|
InitialSpawn = reader.ReadBool();
|
|
goto case 0;
|
|
case 0:
|
|
Beacon = reader.ReadItem<PlunderBeacon>();
|
|
|
|
Cannons = reader.ReadStrongItemList<MannedCannon>();
|
|
Crew = reader.ReadStrongMobileList<BaseCreature>();
|
|
Spawn = new Dictionary<BaseCreature, bool>();
|
|
|
|
if (version == 0)
|
|
{
|
|
//Spawn = reader.ReadStrongMobileList<BaseCreature>();
|
|
List<BaseCreature> list = reader.ReadStrongMobileList<BaseCreature>();
|
|
|
|
foreach (var bc in list)
|
|
{
|
|
Spawn[bc] = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int count = reader.ReadInt();
|
|
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
var bc = reader.ReadMobile<BaseCreature>();
|
|
var initial = reader.ReadBool();
|
|
|
|
if (bc != null)
|
|
{
|
|
Spawn[bc] = initial;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
|
|
}
|
|
|
|
#region Components
|
|
private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource)
|
|
{
|
|
AddComplexComponent(addon, item, xoffset, yoffset, zoffset, hue, lightsource, null, 1);
|
|
}
|
|
|
|
private static void AddComplexComponent(BaseAddon addon, int item, int xoffset, int yoffset, int zoffset, int hue, int lightsource, string name, int amount)
|
|
{
|
|
AddonComponent ac;
|
|
ac = new AddonComponent(item);
|
|
if (name != null && name.Length > 0)
|
|
ac.Name = name;
|
|
if (hue != 0)
|
|
ac.Hue = hue;
|
|
if (amount > 1)
|
|
{
|
|
ac.Stackable = true;
|
|
ac.Amount = amount;
|
|
}
|
|
if (lightsource != -1)
|
|
ac.Light = (LightType)lightsource;
|
|
addon.AddComponent(ac, xoffset, yoffset, zoffset);
|
|
}
|
|
|
|
private static int[,] m_AddOnSimpleComponents = new int[,] {
|
|
{16017, -5, -3, 4}, {16011, -2, 4, 4}// 1 2 3
|
|
, {16011, -2, -4, 4}, {16020, -5, -5, 4}, {16008, -2, -5, 4}// 4 5 6
|
|
, {16014, -4, -3, 4}, {16011, 3, -4, 4}, {16008, -2, 3, 4}// 7 8 9
|
|
, {16021, -6, 4, 4}, {15998, 3, -3, 4}, {16016, -4, -5, 4}// 10 11 12
|
|
, {16008, 1, 3, 4}, {16011, -1, -3, 4}, {16014, -4, 5, 4}// 13 14 15
|
|
, {16011, 4, -4, 4}, {16011, 1, 5, 4}, {16011, 1, -4, 4}// 16 17 18
|
|
, {16011, 2, 5, 4}, {16010, 0, -6, 4}, {16012, -3, -3, 4}// 19 20 21
|
|
, {15996, 4, -3, 4}, {16011, 3, 4, 4}, {16010, 1, 2, 4}// 22 23 24
|
|
, {15997, 4, -5, 4}, {16010, 0, 2, 4}// 25 26 27
|
|
, {15993, 5, -3, 4}, {16010, 2, -6, 4}, {15996, 4, 5, 4}// 28 29 30
|
|
, {16011, -3, -4, 4}, {16005, 1, -2, 4}, {16011, 0, -4, 4}// 31 32 33
|
|
, {15998, 3, 5, 4}, {16011, 1, -3, 4}, {16005, 2, 6, 4}// 34 35 36
|
|
, {16017, -5, 5, 4}, {16008, 2, 3, 4}, {16011, -3, 4, 4}// 37 38 39
|
|
, {16008, 0, 3, 4}, {16010, 2, 2, 4}, {16010, -1, 2, 4}// 40 41 42
|
|
, {16011, 2, -3, 4}, {16015, -4, -4, 4}, {16005, 2, -2, 4}// 43 44 45
|
|
, {16010, -2, -6, 4}, {16008, 0, -5, 4}// 46 47 48
|
|
, {16010, -2, 2, 4}, {16011, 4, 4, 4}// 49 50 51
|
|
, {16013, -3, -5, 4}, {15997, 4, 3, 4}, {16008, -1, 3, 4}// 52 53 54
|
|
, {16005, 0, -2, 4}, {15999, 3, -5, 4}, {16011, 0, 5, 4}// 55 56 57
|
|
, {16011, 0, -3, 4}, {16005, 1, 6, 4}, {15993, 5, 5, 4}// 58 59 60
|
|
, {15999, 3, 3, 4}, {16011, 0, 4, 4}// 61 62 63
|
|
, {16011, 2, -4, 4}, {16005, 0, 6, 4}, {16010, 1, -6, 4}// 64 65 66
|
|
, {16008, 2, -5, 4}, {16011, -2, -3, 4}// 67 68 69
|
|
, {15995, 5, -5, 4}, {16015, -4, 4, 4}, {16011, 1, 4, 4}// 70 71 72
|
|
, {16021, -6, -4, 4}, {16005, -2, 6, 4 } // 73 74 75
|
|
, {16012, -3, 5, 4}, {16008, 1, -5, 4}, {16013, -3, 3, 4}// 76 77 78
|
|
, {16011, 2, 4, 4}, {16016, -4, 3, 4}// 79 80 81
|
|
, {15990, 6, 4, 4}, {16020, -5, 3, 4}, {15995, 5, 3, 4}// 82 83 84
|
|
, {16011, -1, 5, 4}, {16011, -2, 5, 4}, {16008, -1, -5, 4}// 85 86 87
|
|
, {15990, 6, -4, 4}, {5367, 3, 0, 4}, {2462, -1, 2, 17}// 88 89 90
|
|
, {4014, 1, 1, 17}, {4014, 1, 2, 12} // 91 92 93
|
|
, {4014, 1, 1, 10}, {16933, 1, 2, 17}, {15991, 5, 5, 4}// 94 95 96
|
|
, {19341, 0, 2, 12}, {16035, -2, -1, 9} // 97 98 99
|
|
, {16011, -1, 4, 4}, {4014, -1, 1, 12}, {4334, 4, 4, 7}// 100 101 102
|
|
, {4014, -1, 2, 12}, {16019, -5, 4, 4}, {16036, 2, 1, 9}// 104 105 106
|
|
, {16011, 1, -1, 9}, {16011, 1, 0, 9}, {16035, -2, 0, 9}// 107 108 109
|
|
, {30715, -1, 3, 5}, {30715, 0, 3, 5}, {16036, 2, -1, 9}// 110 111 112
|
|
, {16036, 2, 0, 9}, {16011, -1, -1, 9}// 113 114 115
|
|
, {16011, -1, 0, 9}, {16036, 2, 2, 9}, {16011, -1, 1, 9}// 116 117 118
|
|
, {4335, 2, 4, 7}, {16011, -1, 2, 9}, {16011, 0, -1, 9}// 119 120 121
|
|
, {16011, 0, 0, 9}, {16011, 0, 1, 9}, {7846, 3, -1, 0}// 122 123 124
|
|
, {6941, 3, 2, 35}, {16011, 0, 2, 9}, {16011, 1, 2, 9}// 125 126 127
|
|
, {6942, 1, 2, 24}, {30715, -2, 3, 5} // 128 129 130
|
|
, {7846, 3, 2, 0}, {16035, -2, 1, 9}, {16011, 1, 1, 9}// 131 132 133
|
|
, {30715, 2, 3, 5}, {4335, -3, 5, 7}, {30715, 1, 3, 5}// 134 135 136
|
|
, {16010, -1, 2, 7}, {16035, -2, 2, 9}, {16005, -1, 6, 4}// 137 138 139
|
|
, {16011, 5, 4, 8}, {16933, 0, -2, 17}, {4335, 4, -4, 7}// 140 141 142
|
|
, {30717, -2, -3, 5}, {15991, 5, -3, 4}, {30717, -1, -3, 5}// 143 144 145
|
|
, {30717, 0, -3, 5}, {16035, -2, -2, 9}, {30717, 2, -3, 5}// 146 147 148
|
|
, {4334, -2, -4, 7}, {16019, -5, -4, 4}, {4335, 3, -4, 7}// 149 150 151
|
|
, {30717, 1, -3, 5}, {16011, 1, -2, 9}, {16036, 2, -2, 9}// 152 153 154
|
|
, {4014, 0, -2, 12}, {16011, -1, -2, 9}// 155 156 157
|
|
, {16011, 0, -2, 9}, {16011, -1, -4, 4}, {16010, -1, -6, 4}// 158 159 160
|
|
, {16005, -1, -2, 7}, {16011, 5, -4, 8}// 161 162
|
|
};
|
|
|
|
#endregion
|
|
}
|
|
}
|