Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View File

@@ -0,0 +1,615 @@
using System;
using Server;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
using Server.Items;
using Server.Spells;
using Server.Spells.Necromancy;
using Server.Engines.CityLoyalty;
namespace Server.Engines.Blackthorn
{
public class Invader : BaseCreature
{
public static SkillName RandomSpecialty()
{
return _Specialties[Utility.Random(_Specialties.Length)];
}
private static SkillName[] _Specialties =
{
SkillName.Swords,
SkillName.Fencing,
SkillName.Macing,
SkillName.Archery,
SkillName.Magery,
SkillName.Mysticism,
SkillName.Spellweaving,
SkillName.Bushido,
SkillName.Bushido,
SkillName.Ninjitsu,
SkillName.Chivalry,
SkillName.Necromancy,
SkillName.Poisoning
};
private InvasionType _InvasionType;
private SkillName _Specialty;
private bool _Sampire;
private DateTime _NextSpecial;
public override bool AlwaysMurderer { get { return true; } }
public override double HealChance { get { return AI == AIType.AI_Melee || AI == AIType.AI_Paladin ? 1.0 : 0.0; } }
public override double WeaponAbilityChance { get { return AI == AIType.AI_Melee || AI == AIType.AI_Paladin ? 0.4 : 0.1; } }
public override bool CanStealth { get { return _Specialty == SkillName.Ninjitsu; } }
public override WeaponAbility GetWeaponAbility()
{
BaseWeapon wep = Weapon as BaseWeapon;
if (wep != null)
{
return 0.6 > Utility.RandomDouble() ? wep.PrimaryAbility : wep.SecondaryAbility;
}
return null;
}
public override bool UseSmartAI { get { return true; } }
public virtual bool CanDoSpecial { get { return SpellCaster; } }
public virtual double MinSkill { get { return 100.0; } }
public virtual double MaxSkill { get { return 120.0; } }
public virtual int MinResist { get { return 10; } }
public virtual int MaxResist { get { return 20; } }
public bool SpellCaster { get { return AI != AIType.AI_Melee && AI != AIType.AI_Ninja && AI != AIType.AI_Samurai && AI != AIType.AI_Paladin; } }
[Constructable]
public Invader(InvasionType type)
: this(RandomSpecialty(), type)
{
}
[Constructable]
public Invader(SkillName specialty, InvasionType type)
: base(GetAI(specialty), FightMode.Closest, 10, 1, .2, .1)
{
_Specialty = specialty;
_InvasionType = type;
if (_Specialty == SkillName.Bushido && Utility.RandomBool())
_Sampire = true;
if (Female = Utility.RandomBool())
{
//Body = 0x191;
Name = NameList.RandomName("female");
}
else
{
//Body = 0x190;
Name = NameList.RandomName("male");
}
SetBody();
string title;
if (_Sampire)
{
title = "the sampire";
}
else if (specialty == SkillName.Magery)
{
title = "the wizard";
}
else
{
title = String.Format("the {0}", Skills[specialty].Info.Title);
if (Female && title.EndsWith("man"))
title = title.Substring(0, title.Length - 3) + "woman";
}
Title = title;
SetStr(120, 170);
SetDex(SpellCaster ? 75 : 150);
SetInt(SpellCaster ? 1800 : 500);
SetHits(800, 1250);
if (AI == AIType.AI_Melee)
SetDamage(15, 28);
else if (!SpellCaster)
SetDamage(12, 22);
else
SetDamage(8, 18);
Fame = 8000;
Karma = -8000;
SetResists();
SetSkills();
EquipSpecialty();
_NextSpecial = DateTime.UtcNow;
if (_Sampire)
{
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
VampiricEmbraceSpell spell = new VampiricEmbraceSpell(this, null);
spell.Cast();
});
}
SetAreaEffect(AreaEffect.AuraOfEnergy);
}
public virtual void SetBody()
{
switch (_Specialty)
{
default:
if (0.75 > Utility.RandomDouble())
Race = Race.Human;
else
Race = Race.Elf; break;
case SkillName.Archery:
case SkillName.Spellweaving: Race = Race.Elf; break;
}
HairItemID = Race.RandomHair(Female);
HairHue = Race.RandomHairHue();
FacialHairItemID = Race.RandomFacialHair(Female);
FacialHairHue = Race.RandomHairHue();
Hue = Race.RandomSkinHue();
}
public virtual void SetResists()
{
SetResistance(ResistanceType.Physical, MinResist, MaxResist);
SetResistance(ResistanceType.Fire, MinResist, MaxResist);
SetResistance(ResistanceType.Cold, MinResist, MaxResist);
SetResistance(ResistanceType.Poison, MinResist, MaxResist);
SetResistance(ResistanceType.Energy, MinResist, MaxResist);
}
public virtual void SetSkills()
{
SetSkill(SkillName.Fencing, MinSkill, MaxSkill);
SetSkill(SkillName.Macing, MinSkill, MaxSkill);
SetSkill(SkillName.MagicResist, MinSkill, MaxSkill);
SetSkill(SkillName.Swords, MinSkill, MaxSkill);
SetSkill(SkillName.Tactics, MinSkill, MaxSkill);
SetSkill(SkillName.Wrestling, MinSkill, MaxSkill);
SetSkill(SkillName.Archery, MinSkill, MaxSkill);
SetSkill(SkillName.Parry, MinSkill, MaxSkill);
if (SpellCaster)
{
SetSkill(SkillName.Magery, MinSkill, MaxSkill);
SetSkill(SkillName.EvalInt, MinSkill, MaxSkill);
}
if (Skills[_Specialty].Base < MinSkill)
SetSkill(_Specialty, MinSkill, MaxSkill);
if (_Sampire)
{
SetSkill(SkillName.Necromancy, MinSkill, MaxSkill);
}
if (_Sampire || _Specialty == SkillName.Necromancy)
{
SetSkill(SkillName.SpiritSpeak, MinSkill, MaxSkill);
}
if (_Specialty == SkillName.Ninjitsu)
{
SetSkill(SkillName.Hiding, 100);
SetSkill(SkillName.Stealth, 100);
}
}
public virtual void EquipSpecialty()
{
if (AbilityProfile != null && AbilityProfile.HasAbility(SpecialAbility.Heal))
PackItem(new Bandage(Utility.RandomMinMax(10, 25)));
SetWearable(new ThighBoots());
SetWearable(new BodySash(), Utility.RandomSlimeHue());
switch (_Specialty)
{
case SkillName.Chivalry:
SetWearable(RandomSwordWeapon());
PaladinEquip();
break;
case SkillName.Swords:
SetWearable(RandomSwordWeapon());
StandardMeleeEquip();
break;
case SkillName.Fencing:
SetWearable(RandomFencingWeapon());
StandardMeleeEquip();
break;
case SkillName.Macing:
SetWearable(RandomMaceWeapon());
StandardMeleeEquip();
break;
case SkillName.Archery:
SetWearable(RandomArhceryWeapon());
StandardMeleeEquip();
break;
case SkillName.Magery:
SetWearable(RandomMageWeapon());
StandardMageEquip();
break;
case SkillName.Mysticism:
SetWearable(RandomMageWeapon());
StandardMageEquip();
break;
case SkillName.Spellweaving:
SetWearable(RandomMageWeapon());
StandardMageEquip();
break;
case SkillName.Necromancy:
SetWearable(RandomMageWeapon());
StandardMageEquip();
break;
case SkillName.Bushido:
BaseWeapon w = RandomSamuraiWeapon() as BaseWeapon;
SetWearable(w);
SetWearable(new LeatherSuneate());
SetWearable(new LeatherJingasa());
SetWearable(new LeatherDo());
SetWearable(new LeatherHiroSode());
SetWearable(new SamuraiTabi(Utility.RandomNondyedHue()));
if (_Sampire)
w.WeaponAttributes.HitLeechHits = 100;
SetSkill(SkillName.Parry, 120);
break;
case SkillName.Ninjitsu:
SetWearable(RandomNinjaWeapon());
LeatherNinjaBelt belt = new LeatherNinjaBelt();
belt.UsesRemaining = 20;
belt.Poison = Poison.Greater;
belt.PoisonCharges = 20;
SetWearable(belt);
for (int i = 0; i < 2; i++)
{
Fukiya f = new Fukiya();
f.UsesRemaining = 10;
f.Poison = Poison.Greater;
f.PoisonCharges = 10;
f.Movable = false;
PackItem(f);
}
SetWearable(new NinjaTabi());
SetWearable(new LeatherNinjaJacket());
SetWearable(new LeatherNinjaHood());
SetWearable(new LeatherNinjaPants());
SetWearable(new LeatherNinjaMitts());
break;
case SkillName.Poisoning:
BaseWeapon wep = RandomAssassinWeapon() as BaseWeapon;
wep.Poison = Poison.Lethal;
wep.PoisonCharges = 100;
SetWearable(wep);
SetWearable(new LeatherChest());
SetWearable(new LeatherLegs());
SetWearable(new LeatherGloves());
SetWearable(new LeatherGorget());
break;
}
}
private void PaladinEquip()
{
SetWearable(Loot.Construct(new Type[] { typeof(Bascinet), typeof(Helmet), typeof(PlateHelm) }), 1153);
SetWearable(new PlateChest());
SetWearable(new PlateLegs());
SetWearable(new PlateGloves());
SetWearable(new PlateGorget());
SetWearable(new PlateArms());
SetWearable(new MetalKiteShield());
SetSkill(SkillName.Parry, 120);
}
private void StandardMeleeEquip()
{
SetWearable(Loot.Construct(new Type[] { typeof(Bascinet), typeof(Helmet), typeof(LeatherCap), typeof(RoyalCirclet) }));
SetWearable(new ChainChest());
SetWearable(new ChainLegs());
SetWearable(new RingmailGloves());
SetWearable(new LeatherGorget());
}
private void StandardMageEquip()
{
bool mage = AI == AIType.AI_Mage;
SetWearable(new WizardsHat(), mage ? Utility.RandomBlueHue() : Utility.RandomRedHue());
SetWearable(new Robe(), mage ? Utility.RandomBlueHue() : Utility.RandomRedHue());
SetWearable(new LeatherGloves());
}
public static AIType GetAI(SkillName skill)
{
switch (skill)
{
default: return AIType.AI_Melee;
case SkillName.Ninjitsu: return AIType.AI_Ninja;
case SkillName.Bushido: return AIType.AI_Samurai;
case SkillName.Chivalry: return AIType.AI_Paladin;
case SkillName.Magery: return AIType.AI_Mage;
case SkillName.Necromancy: return AIType.AI_NecroMage;
case SkillName.Spellweaving: return AIType.AI_Spellweaving;
case SkillName.Mysticism: return AIType.AI_Mystic;
}
}
public Item RandomSwordWeapon()
{
if (Race == Race.Elf)
return Loot.Construct(new Type[] { typeof(ElvenMachete), typeof(RadiantScimitar) });
return Loot.Construct(new Type[] { typeof(Broadsword), typeof(Longsword), typeof(Katana), typeof(Halberd), typeof(Bardiche), typeof(VikingSword) });
}
public Item RandomFencingWeapon()
{
if(Race == Race.Elf)
return Loot.Construct(new Type[] { typeof(Leafblade), typeof(WarCleaver), typeof(AssassinSpike) });
return Loot.Construct(new Type[] { typeof(Kryss), typeof(Spear), typeof(ShortSpear), typeof(Lance), typeof(Pike) });
}
public Item RandomMaceWeapon()
{
return Loot.Construct(new Type[] { typeof(Mace), typeof(WarHammer), typeof(WarAxe), typeof(BlackStaff), typeof(QuarterStaff), typeof(WarMace), typeof(DiamondMace), typeof(Scepter) });
}
public Item RandomArhceryWeapon()
{
if (Race == Race.Elf)
return Loot.Construct(new Type[] { typeof(MagicalShortbow), typeof(ElvenCompositeLongbow) });
return Loot.Construct(new Type[] { typeof(Bow), typeof(Crossbow), typeof(HeavyCrossbow), typeof(CompositeBow), typeof(RepeatingCrossbow) });
}
public Item RandomMageWeapon()
{
return Loot.Construct(new Type[] { typeof(Spellbook), typeof(GnarledStaff), typeof(BlackStaff), typeof(QuarterStaff), typeof(WildStaff) });
}
public Item RandomSamuraiWeapon()
{
return Loot.Construct(new Type[] { typeof(Lajatang), typeof(Wakizashi), typeof(NoDachi) });
}
public Item RandomNinjaWeapon()
{
return Loot.Construct(new Type[] { typeof(Wakizashi), typeof(Tessen), typeof(Nunchaku), typeof(Daisho), typeof(Sai), typeof(Tekagi), typeof(Kama), typeof(Katana) });
}
public Item RandomAssassinWeapon()
{
return Loot.Construct(new Type[] { typeof(Cleaver), typeof(ButcherKnife), typeof(Kryss), typeof(Dagger) });
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
list.Add(1154196 + (int)_InvasionType);
}
public override void OnThink()
{
base.OnThink();
if (Combatant == null)
return;
if (CanDoSpecial && InRange(Combatant, 4) && 0.1 > Utility.RandomDouble() && _NextSpecial < DateTime.UtcNow)
{
DoSpecial();
_NextSpecial = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
}
else if (_Sampire)
{
if (0.1 > Utility.RandomDouble() && Weapon is BaseWeapon && !CurseWeaponSpell.IsCursed(this, (BaseWeapon)Weapon))
{
CurseWeaponSpell spell = new CurseWeaponSpell(this, null);
spell.Cast();
}
else if (!TransformationSpellHelper.UnderTransformation(this, typeof(VampiricEmbraceSpell)))
{
VampiricEmbraceSpell spell = new VampiricEmbraceSpell(this, null);
spell.Cast();
}
}
}
private void DoSpecial()
{
if (this.Map == null || this.Map == Map.Internal)
return;
Map m = this.Map;
for (int i = 0; i < 4; i++)
{
Timer.DelayCall(TimeSpan.FromMilliseconds(i * 50), o =>
{
Server.Misc.Geometry.Circle2D(this.Location, m, (int)o, (pnt, map) =>
{
Effects.SendLocationEffect(pnt, map, Utility.RandomBool() ? 14000 : 14013, 14, 20, 2018, 0);
});
}, i);
}
Timer.DelayCall(TimeSpan.FromMilliseconds(200), () =>
{
if (m != null)
{
List<Mobile> list = new List<Mobile>();
IPooledEnumerable eable = m.GetMobilesInRange(this.Location, 4);
foreach (Mobile mob in eable)
{
if (mob.AccessLevel > AccessLevel.Player)
continue;
if (mob is PlayerMobile || (mob is BaseCreature && ((BaseCreature)mob).GetMaster() is PlayerMobile) && CanBeHarmful(mob))
list.Add(mob);
}
list.ForEach(mob =>
{
AOS.Damage(mob, this, Utility.RandomMinMax(80, 90), 0, 0, 0, 0, 0, 100, 0);
});
list.Clear();
list.TrimExcess();
}
});
}
public override void GenerateLoot()
{
this.AddLoot(LootPack.UltraRich, 2);
}
public Invader(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
writer.Write((int)_Specialty);
writer.Write((int)_InvasionType);
writer.Write(_Sampire);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
_Specialty = (SkillName)reader.ReadInt();
_InvasionType = (InvasionType)reader.ReadInt();
_Sampire = reader.ReadBool();
_NextSpecial = DateTime.UtcNow;
}
}
public class InvaderCaptain : Invader
{
public override double MinSkill { get { return 105.0; } }
public override double MaxSkill { get { return 130.0; } }
public override int MinResist { get { return 20; } }
public override int MaxResist { get { return 30; } }
[Constructable]
public InvaderCaptain(InvasionType type) : base(type)
{
SetStr(250);
SetDex(SpellCaster ? 150 : 200);
SetInt(SpellCaster ? 1000 : 5000);
SetHits(8000, 12000);
if (AI == AIType.AI_Melee)
SetDamage(22, 30);
else if (!SpellCaster)
SetDamage(20, 28);
else
SetDamage(10, 20);
Fame = 48000;
Karma = -48000;
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
var rights = GetLootingRights();
rights.Sort();
List<Mobile> list = rights.Select(x => x.m_Mobile).Where(m => m.InRange(c.Location, 20)).ToList();
if(list.Count > 0)
{
for (int i = 0; i < 2; i++)
{
Mobile drop;
Item item = InvasionController.CreateItem(list[0]);
if (list.Count == 1 || i >= list.Count)
drop = list[0];
else
drop = list[i];
drop.SendLocalizedMessage(1154530); // You notice the crest of Minax on your fallen foe's equipment and decide it may be of some value...
if (drop.Backpack == null || !drop.Backpack.TryDropItem(drop, item, false))
{
drop.BankBox.DropItem(item);
drop.SendLocalizedMessage(1079730); // // The item has been placed into your bank box.
}
}
}
ColUtility.Free(list);
}
public override void GenerateLoot()
{
this.AddLoot(LootPack.UltraRich, 2);
this.AddLoot(LootPack.SuperBoss, 1);
}
public InvaderCaptain(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,66 @@
using System;
using Server;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
using Server.Items;
using Server.Engines.CityLoyalty;
namespace Server.Engines.Blackthorn
{
public class InvasionBeacon : Beacon
{
[CommandProperty(AccessLevel.GameMaster)]
public InvasionController Controller { get; set; }
public override bool CanDamage { get { return Controller == null || Controller.BeaconVulnerable; } }
public InvasionBeacon(InvasionController controller)
{
Controller = controller;
Name = "lighthouse";
Level = ItemLevel.Easy; // Hard
}
public override void OnHalfDamage()
{
IPooledEnumerable eable = this.Map.GetMobilesInRange(this.Location, 20);
foreach (Mobile m in eable)
{
if (m.NetState != null)
m.PrivateOverheadMessage(Server.Network.MessageType.Regular, 1154, 1154551, m.NetState); // *Minax's Beacon surges with energy into an invulnerable state! Defeat her Captains to weaken the Beacon's defenses!*
}
eable.Free();
if (Controller != null)
Timer.DelayCall(TimeSpan.FromSeconds(1), () => Controller.SpawnWave());
}
public override bool OnBeforeDestroyed()
{
if (Controller != null)
Controller.OnBeaconDestroyed();
return base.OnBeforeDestroyed();
}
public InvasionBeacon(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,647 @@
using System;
using Server;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
using Server.Items;
using Server.Engines.CityLoyalty;
using Server.Misc;
namespace Server.Engines.Blackthorn
{
public enum InvasionType
{
Dragons,
Undead,
Elemental,
Daemon,
Orc,
Wildlings,
Frost,
Arachnid,
Fey,
Nature
}
public class InvasionController : Item
{
public static bool Enabled = true;
public static int WaveCountMin = 8;
public static int WaveCountMax = 10;
public static int MaxWaves = 2;
[CommandProperty(AccessLevel.Administrator)]
public static InvasionController TramInstance { get; set; }
[CommandProperty(AccessLevel.Administrator)]
public static InvasionController FelInstance { get; set; }
[CommandProperty(AccessLevel.Administrator)]
public bool ForceRespawn
{
get
{
return false;
}
set
{
if (!value)
return;
RemoveSpawn();
OnEndInvasion();
Cleanup();
BeginInvasion();
}
}
public static Dictionary<City, InvasionDefinition> Defs;
[CommandProperty(AccessLevel.GameMaster)]
public City CurrentInvasion { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public InvasionType InvasionType { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public InvasionBeacon Beacon { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int SpawnCount
{
get
{
if (Spawn == null || Spawn.Count == 0)
return 0;
int count = 0;
foreach (KeyValuePair<BaseCreature, List<BaseCreature>> kvp in Spawn)
{
if (kvp.Key.Alive)
count++;
count += kvp.Value.Where(bc => bc.Alive).Count();
}
return count;
}
}
public Dictionary<BaseCreature, List<BaseCreature>> Spawn { get; set; }
public List<Rectangle2D> SpawnZones { get; set; }
[CommandProperty(AccessLevel.GameMaster)]
public int CurrentWave { get; private set; }
public bool BeaconVulnerable { get { return Beacon != null && (Spawn == null || Spawn.Count == 0); } }
public InvasionController(Map map) : base(3796)
{
Movable = false;
Visible = false;
Spawn = new Dictionary<BaseCreature, List<BaseCreature>>();
SpawnZones = new List<Rectangle2D>();
if (Enabled)
Timer.DelayCall(TimeSpan.FromSeconds(10), BeginInvasion);
}
public override void OnDoubleClick(Mobile from)
{
if (from.AccessLevel > AccessLevel.GameMaster)
{
from.SendGump(new Server.Gumps.PropertiesGump(from, this));
}
}
private Type[][] _SpawnTable =
{
new Type[] { typeof(Dragon), typeof(Drake), typeof(GiantSerpent), typeof(Reptalon), typeof(Hydra) },
new Type[] { typeof(Lich), typeof(Wraith), typeof(Mummy), typeof(Zombie), typeof(SkeletalKnight), typeof(BoneKnight) },
new Type[] { typeof(MudElemental), typeof(MoltenEarthElemental), typeof(DiseasedBloodElemental), typeof(GreaterAirElemental),
typeof(GreaterBloodElemental), typeof(GreaterEarthElemental), typeof(GreaterWaterElemental), typeof(ShameGreaterPoisonElemental),
typeof(StoneElemental) },
new Type[] { typeof(Daemon), typeof(Succubus), typeof(Imp), typeof(ChaosDaemon), typeof(BoneDemon) },
new Type[] { typeof(Orc), typeof(OrcBomber), typeof(OrcishMage), typeof(OrcishLord) },
new Type[] { typeof(SwampTentacle), typeof(PlagueBeast), typeof(Bogling), typeof(FeralTreefellow) },
new Type[] { typeof(IceElemental), typeof(SnowElemental), typeof(IceFiend), typeof(FrostTroll), typeof(IceSerpent) },
new Type[] { typeof(DreadSpider), typeof(GiantBlackWidow), typeof(Scorpion), typeof(TerathanWarrior), typeof(WolfSpider) },
new Type[] { typeof(Satyr), typeof(Centaur), typeof(CuSidhe), typeof(Wisp), typeof(MLDryad) },
new Type[] { typeof(DireWolf), typeof(GiantRat), typeof(Troglodyte), typeof(RagingGrizzlyBear), typeof(GreaterMongbat) },
};
public void BeginInvasion()
{
if (!Enabled)
return;
RemoveSpawn();
CurrentWave = 1;
InvasionType newType;
City newCity;
do
{
newType = (InvasionType)Utility.Random(10);
}
while(newType == this.InvasionType);
do
{
newCity = (City)Utility.Random(9);
}
while (newCity == this.CurrentInvasion);
this.CurrentInvasion = newCity;
this.InvasionType = newType;
SpawnZones = Defs[CurrentInvasion].SpawnRecs.ToList();
Beacon = new InvasionBeacon(this);
Beacon.MoveToWorld(Defs[CurrentInvasion].BeaconLoc, this.Map);
// Shuffle zones
for(int i = 0; i < 8; i++)
{
var rec = SpawnZones[Utility.Random(SpawnZones.Count)];
SpawnZones.Remove(rec);
SpawnZones.Insert(0, rec);
}
SpawnWave();
}
public void SpawnWave()
{
List<Rectangle2D> zones = new List<Rectangle2D>(SpawnZones);
for(int j = 0; j < 2; j++)
{
Rectangle2D spawnrec = zones[Utility.Random(zones.Count)];
zones.Remove(spawnrec);
int count = Utility.RandomMinMax(WaveCountMin, WaveCountMax);
List<BaseCreature> list = new List<BaseCreature>();
for(int i = 0; i < count; i++)
{
BaseCreature bc = Activator.CreateInstance(_SpawnTable[(int)this.InvasionType][Utility.Random(_SpawnTable[(int)this.InvasionType].Length)]) as BaseCreature;
Server.Engines.XmlSpawner2.XmlAttach.AttachTo(bc, new Server.Engines.XmlSpawner2.XmlData("Notoriety", "red"));
if (SpawnMobile(bc, spawnrec))
{
list.Add(bc);
}
else
{
bc.Delete();
}
}
for (int i = 0; i < 3; i++)
{
Invader invader = new Invader(this.InvasionType);
if (SpawnMobile(invader, spawnrec))
{
list.Add(invader);
}
else
invader.Delete();
}
InvaderCaptain capt = new InvaderCaptain(this.InvasionType);
capt.Blessed = true;
if (SpawnMobile(capt, spawnrec) || SpawnMobile(capt, new Rectangle2D(Defs[CurrentInvasion].BeaconLoc.X - 10, Defs[CurrentInvasion].BeaconLoc.Y - 10, 20, 20)))
{
Spawn[capt] = list;
}
}
}
private bool SpawnMobile(BaseCreature bc, Rectangle2D spawnrec)
{
if (Map == null)
return false;
if (bc != null)
{
for (int i = 0; i < 25; i++)
{
Point3D p = this.Map.GetRandomSpawnPoint(spawnrec);
bool exempt = false;
if (spawnrec.X == 6444 && spawnrec.Y == 2446)
{
exempt = true;
p.Z = -2;
}
if (exempt || this.Map.CanFit(p.X, p.Y, p.Z, 16, false, false, true))
{
bc.MoveToWorld(p, this.Map);
bc.Home = Defs[CurrentInvasion].BeaconLoc;
bc.SeeksHome = true;
bc.RangeHome = Utility.RandomMinMax(5, 10);
bc.CanSwim = false;
bc.Tamable = false;
return true;
}
}
}
return false;
}
public void OnDeath(BaseCreature bc)
{
if (bc == null || bc.Controlled || bc.Summoned)
return;
if (Spawn.ContainsKey(bc))
{
Spawn.Remove(bc);
bool wavecomplete = true;
foreach (KeyValuePair<BaseCreature, List<BaseCreature>> kvp in Spawn)
{
if (kvp.Key != null && kvp.Key.Alive)
{
wavecomplete = false;
break;
}
}
if (wavecomplete)
CompleteWave();
}
else
{
foreach (KeyValuePair<BaseCreature, List<BaseCreature>> kvp in Spawn)
{
if (kvp.Value.Contains(bc))
kvp.Value.Remove(bc);
int count = kvp.Value.Where(b => b != null && b.Alive).Count();
if (count == 0 && kvp.Key.Alive)
{
kvp.Key.Blessed = false;
kvp.Key.Delta(MobileDelta.Noto);
}
}
}
}
public void CleanupSpawn()
{
if (Spawn == null)
return;
List<BaseCreature> list = null;
foreach (KeyValuePair<BaseCreature, List<BaseCreature>> kvp in Spawn)
{
if (kvp.Value != null)
{
list = new List<BaseCreature>(kvp.Value);
foreach (BaseCreature b in list.Where(bc => bc == null || !bc.Alive || bc.Deleted))
kvp.Value.Remove(b);
}
if (list != null && list.Count > 0)
{
list.Clear();
list.TrimExcess();
}
}
}
private void CompleteWave()
{
if(CurrentWave == MaxWaves)
{
DoMessage();
}
else
{
DoMessage();
CurrentWave++;
}
}
private void DoMessage()
{
if (this.Map == null)
return;
IPooledEnumerable eable = this.Map.GetMobilesInRange(Beacon.Location, 20);
foreach (Mobile m in eable)
{
if (m != null && m.NetState != null)
m.PrivateOverheadMessage(Server.Network.MessageType.Regular, 1154, 1154550, m.NetState); // *A sound roars in the distance...Minax's Beacon is vulnerable to attack!!*
}
eable.Free();
}
public void OnBeaconDestroyed()
{
OnEndInvasion();
Timer.DelayCall(TimeSpan.FromMinutes(2), () =>
{
Cleanup();
BeginInvasion();
});
}
public void OnEndInvasion()
{
if (Beacon != null)
{
List<Mobile> rights = Beacon.GetLootingRights();
if (rights != null)
{
foreach (Mobile damager in rights.Where(mob => mob.InRange(Beacon.Location, 12)))
{
if (0.15 < Utility.RandomDouble())
continue;
Item i = CreateItem(damager);
if (i != null)
{
damager.PlaySound(0x5B4);
damager.SendLocalizedMessage(1154554); // You recover an artifact bearing the crest of Minax from the rubble.
if (!damager.PlaceInBackpack(i))
{
if (damager.BankBox != null && damager.BankBox.TryDropItem(damager, i, false))
damager.SendLocalizedMessage(1079730); // The item has been placed into your bank box.
else
{
damager.SendLocalizedMessage(1072523); // You find an artifact, but your backpack and bank are too full to hold it.
i.MoveToWorld(damager.Location, damager.Map);
}
}
}
}
}
}
}
public static Item CreateItem(Mobile damager)
{
Item i = Loot.RandomArmorOrShieldOrWeaponOrJewelry(LootPackEntry.IsInTokuno(damager), LootPackEntry.IsMondain(damager), LootPackEntry.IsStygian(damager));
if (i != null)
{
RunicReforging.GenerateRandomItem(i, damager, Utility.RandomMinMax(700, 800), damager is PlayerMobile ? ((PlayerMobile)damager).RealLuck : 0, ReforgedPrefix.None, ReforgedSuffix.Minax);
}
return i;
}
public void Cleanup()
{
if (Beacon != null)
Beacon.Delete();
}
public void RemoveSpawn()
{
if (Spawn == null)
return;
Dictionary<BaseCreature, List<BaseCreature>> copy = Spawn;
Spawn = new Dictionary<BaseCreature, List<BaseCreature>>();
foreach (KeyValuePair<BaseCreature, List<BaseCreature>> kvp in copy)
{
foreach (BaseCreature bc in kvp.Value.Where(b => b.Alive))
bc.Kill();
if (kvp.Key.Alive)
{
kvp.Key.Blessed = false;
kvp.Key.Kill();
}
}
copy.Clear();
}
public InvasionController(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
writer.Write((int)CurrentInvasion);
writer.Write((int)InvasionType);
writer.Write(Beacon);
writer.Write(CurrentWave);
writer.Write(SpawnZones == null ? 0 : SpawnZones.Count);
SpawnZones.ForEach(rec => writer.Write(rec));
writer.Write(Spawn == null ? 0 : Spawn.Count);
foreach(KeyValuePair<BaseCreature, List<BaseCreature>> kvp in Spawn)
{
writer.Write(kvp.Key);
writer.Write(kvp.Value.Count);
kvp.Value.ForEach(bc => writer.Write(bc));
}
Timer.DelayCall(TimeSpan.FromSeconds(30), CleanupSpawn);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Spawn = new Dictionary<BaseCreature, List<BaseCreature>>();
SpawnZones = new List<Rectangle2D>();
if(Map == Map.Trammel)
TramInstance = this;
if(Map == Map.Felucca)
FelInstance = this;
CurrentInvasion = (City)reader.ReadInt();
InvasionType = (InvasionType)reader.ReadInt();
Beacon = reader.ReadItem() as InvasionBeacon;
CurrentWave = reader.ReadInt();
if (Beacon != null)
Beacon.Controller = this;
int count = reader.ReadInt();
for(int i = 0; i < count; i++)
{
SpawnZones.Add(reader.ReadRect2D());
}
count = reader.ReadInt();
for(int i = 0; i < count; i++)
{
BaseCreature captain = reader.ReadMobile() as BaseCreature;
int c = reader.ReadInt();
List<BaseCreature> list = new List<BaseCreature>();
for(int j = 0; j < c; j++)
{
BaseCreature spawn = reader.ReadMobile() as BaseCreature;
if(spawn != null)
{
list.Add(spawn);
}
}
if(captain != null)
Spawn[captain] = list;
else
{
list.Clear();
}
}
Timer.DelayCall(TimeSpan.FromSeconds(10), () =>
{
if (Beacon == null || Beacon.Destroyed)
{
Timer.DelayCall(TimeSpan.FromMinutes(2), () =>
{
Cleanup();
BeginInvasion();
});
}
});
}
public static void Initialize()
{
if (TramInstance == null)
{
TramInstance = new InvasionController(Map.Trammel);
TramInstance.MoveToWorld(new Point3D(6359, 2570, 0), Map.Trammel);
}
if (FelInstance == null)
{
TramInstance = new InvasionController(Map.Felucca);
TramInstance.MoveToWorld(new Point3D(6359, 2570, 0), Map.Felucca);
}
Defs = new Dictionary<City, InvasionDefinition>();
Defs[City.Moonglow] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6314, 2571, 10, 5),
new Rectangle2D(6288, 2535, 8, 15),
new Rectangle2D(6322, 2527, 8, 8),
new Rectangle2D(6302, 2524, 10, 5),
},
new Point3D(6317, 2555, 0));
Defs[City.Britain] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6296, 2464, 7, 7),
new Rectangle2D(6332, 2473, 8, 10),
new Rectangle2D(6320, 2508, 3, 8),
new Rectangle2D(6287, 2494, 8, 8),
},
new Point3D(6316, 2477, 11));
Defs[City.Jhelom] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6450, 2465, 10, 8),
new Rectangle2D(6418, 2497, 15, 5),
new Rectangle2D(6417, 2469, 5, 10),
new Rectangle2D(6432, 2507, 10, 5),
},
new Point3D(6448, 2492, 5));
Defs[City.Yew] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6314, 2397, 12, 5),
new Rectangle2D(6317, 2440, 10, 10),
new Rectangle2D(6286, 2432, 8, 8),
new Rectangle2D(6289, 2405, 5, 5),
},
new Point3D(6305, 2423, 0));
Defs[City.Minoc] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6309, 2339, 10, 5),
new Rectangle2D(6290, 2367, 5, 10),
new Rectangle2D(6304, 2378, 10, 5),
new Rectangle2D(6323, 2344, 5, 10)
},
new Point3D(6307, 2362, 15));
Defs[City.Trinsic] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6356, 2371, 10, 10),
new Rectangle2D(6354, 2344, 5, 10),
new Rectangle2D(6366, 2344, 5, 7),
new Rectangle2D(6386, 2355, 8, 8),
},
new Point3D(6402, 2368, 25));
Defs[City.SkaraBrae] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6434, 2330, 10, 5),
new Rectangle2D(6456, 2342, 5, 10),
new Rectangle2D(6458, 2368, 15, 6),
new Rectangle2D(6440, 2384, 10, 3),
new Rectangle2D(6412, 2360, 12, 12),
},
new Point3D(6442, 2351, 0));
Defs[City.NewMagincia] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6426, 2397, 10, 5),
new Rectangle2D(6444, 2446, 10, 5),
new Rectangle2D(6436, 2395, 5, 8),
new Rectangle2D(6419, 2446, 10, 5),
},
new Point3D(6440, 2419, 26));
Defs[City.Vesper] = new InvasionDefinition(
new Rectangle2D[]
{
new Rectangle2D(6428, 2534, 10, 5),
new Rectangle2D(6458, 2534, 5, 10),
new Rectangle2D(6460, 2551, 5, 10),
new Rectangle2D(6433, 2561, 6, 6),
},
new Point3D(6444, 2553, 0));
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using Server;
using System.Collections.Generic;
using System.Linq;
using Server.Mobiles;
using Server.Items;
using Server.Engines.CityLoyalty;
namespace Server.Engines.Blackthorn
{
public class InvasionDefinition
{
public Rectangle2D[] SpawnRecs { get; set; }
public Point3D BeaconLoc { get; set; }
public InvasionDefinition(Rectangle2D[] spawn, Point3D beaconLoc)
{
SpawnRecs = spawn;
BeaconLoc = beaconLoc;
}
}
}