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,426 @@
using System;
using Server.Engines.CannedEvil;
using Server.Items;
using System.Collections.Generic;
using System.Linq;
using Server.Network;
namespace Server.Mobiles
{
[CorpseName("an abyssal infernal corpse")]
public class AbyssalInfernal : BaseChampion
{
private static Dictionary<Mobile, Point3D> m_Table = new Dictionary<Mobile, Point3D>();
private DateTime m_NextAbility;
[Constructable]
public AbyssalInfernal()
: base(AIType.AI_Mage)
{
Body = 713;
Name = "Abyssal Infernal";
SetStr(1200, 1300);
SetDex(100, 125);
SetInt(600, 700);
SetHits(30000);
SetStam(203, 650);
SetDamage(11, 18);
SetDamageType(ResistanceType.Physical, 60);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Energy, 20);
SetResistance(ResistanceType.Physical, 50, 60);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 70, 80);
SetSkill(SkillName.Anatomy, 110.0, 120.0);
SetSkill(SkillName.Magery, 130.0, 140.0);
SetSkill(SkillName.EvalInt, 120.0, 140.0);
SetSkill(SkillName.MagicResist, 120);
SetSkill(SkillName.Tactics, 120.0);
SetSkill(SkillName.Wrestling, 110.0, 120.0);
SetSkill(SkillName.Meditation, 100.0);
Fame = 28000;
Karma = -28000;
VirtualArmor = 40;
}
public AbyssalInfernal(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType { get { return ChampionSkullType.None; } }
public override Type[] UniqueList { get { return new Type[] { typeof(TongueOfTheBeast), typeof(DeathsHead), typeof(WallOfHungryMouths), typeof(AbyssalBlade) }; } }
public override Type[] SharedList { get { return new Type[] { typeof(RoyalGuardInvestigatorsCloak), typeof(DetectiveBoots), typeof(JadeArmband) }; } }
public override Type[] DecorativeList { get { return new Type[] { typeof(MagicalDoor) }; } }
public override MonsterStatuetteType[] StatueTypes { get { return new MonsterStatuetteType[] { MonsterStatuetteType.AbyssalInfernal, MonsterStatuetteType.ArchDemon }; } }
public override Poison PoisonImmune { get { return Poison.Lethal; } }
public override ScaleType ScaleType { get { return ScaleType.All; } }
public override int Scales { get { return 20; } }
public override int GetAttackSound() { return 0x5D4; }
public override int GetDeathSound() { return 0x5D5; }
public override int GetHurtSound() { return 0x5D6; }
public override int GetIdleSound() { return 0x5D7; }
public override void GenerateLoot()
{
AddLoot(LootPack.SuperBoss, 4);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomBool())
{
switch (Utility.Random(2))
{
case 0:
c.DropItem(new HornAbyssalInferno());
break;
case 1:
c.DropItem(new NetherCycloneScroll());
break;
}
}
}
public override void OnThink()
{
base.OnThink();
if (Combatant == null)
return;
if (m_NextAbility < DateTime.UtcNow)
{
switch (Utility.Random(3))
{
case 0: { DoCondemn(); break; }
case 1: { DoSummon(); break; }
case 2: { DoNuke(); break; }
}
m_NextAbility = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(35, 45));
}
}
private Mobile GetRandomTarget(int range, bool playersOnly)
{
List<Mobile> list = GetTargets(range, playersOnly);
Mobile m = null;
if (list != null && list.Count > 0)
{
m = list[Utility.Random(list.Count)];
ColUtility.Free(list);
}
return m;
}
private List<Mobile> GetTargets(int range, bool playersOnly)
{
List<Mobile> targets = new List<Mobile>();
IPooledEnumerable eable = GetMobilesInRange(range);
foreach (Mobile m in eable)
{
if (m == this || !CanBeHarmful(m))
continue;
if (!playersOnly && m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != Team))
targets.Add(m);
else if (m.Player)
targets.Add(m);
}
eable.Free();
return targets;
}
#region Condemn
private static Point3D[] _Locs = new Point3D[]
{
new Point3D(6949, 701, 32),
new Point3D(6941, 761, 32),
new Point3D(7015, 688, 32),
new Point3D(7043, 751, 32),
new Point3D(6999, 798, 32),
};
public void DoCondemn()
{
Map map = Map;
if (map != null)
{
Mobile toCondemn = GetRandomTarget(8, true);
if (toCondemn != null && !m_Table.ContainsKey(toCondemn))
{
m_Table[toCondemn] = toCondemn.Location;
var loc = _Locs[Utility.Random(_Locs.Length)];
toCondemn.MoveToWorld(loc, map);
toCondemn.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
toCondemn.PlaySound(0x1FE);
toCondemn.Frozen = true;
int seconds = 15;
BuffInfo.AddBuff(toCondemn, new BuffInfo(BuffIcon.TrueFear, 1153791, 1153827, TimeSpan.FromSeconds(seconds), toCondemn));
Timer.DelayCall(TimeSpan.FromSeconds(seconds), () =>
{
toCondemn.Frozen = false;
toCondemn.SendLocalizedMessage(1005603); // You can move again!
loc = m_Table.ToList().Find(x => x.Key == toCondemn).Value;
toCondemn.MoveToWorld(loc, map);
m_Table.Remove(toCondemn);
});
}
}
}
#endregion
public void DoNuke()
{
if (!Alive || Map == null)
return;
Say(1112362); // You will burn to a pile of ash!
int range = 8;
Effects.PlaySound(Location, Map, 0x349);
//Flame Columns
for (int i = 0; i < 2; i++)
{
Misc.Geometry.Circle2D(Location, Map, i, (pnt, map) =>
{
Effects.SendLocationParticles(EffectItem.Create(pnt, map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
});
}
//Flash then boom
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
if (Alive && Map != null)
{
Effects.PlaySound(Location, Map, 0x44B);
Packet flash = ScreenLightFlash.Instance;
IPooledEnumerable e = Map.GetClientsInRange(Location, (range * 4) + 5);
foreach (NetState ns in e)
{
if (ns.Mobile != null)
ns.Mobile.Send(flash);
}
e.Free();
for (int i = 0; i < range; i++)
{
Misc.Geometry.Circle2D(Location, Map, i, (pnt, map) =>
{
Effects.SendLocationEffect(pnt, map, 14000, 14, 10, Utility.RandomMinMax(2497, 2499), 2);
});
}
}
});
IPooledEnumerable eable = GetMobilesInRange(range);
foreach (Mobile m in eable)
{
if ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && CanBeHarmful(m))
Timer.DelayCall(TimeSpan.FromSeconds(1.75), new TimerStateCallback(DoDamage_Callback), m);
}
eable.Free();
}
private void DoDamage_Callback(object o)
{
Mobile m = o as Mobile;
if (m != null && Map != null)
{
IMount mount = m.Mount;
if (mount != null)
{
if (m is PlayerMobile)
((PlayerMobile)m).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
else
mount.Rider = null;
}
else if (m.Flying)
{
((PlayerMobile)m).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
}
DoHarmful(m);
AOS.Damage(m, this, Utility.RandomMinMax(90, 110), 0, 0, 0, 0, 100);
m.Frozen = true;
Timer.DelayCall(TimeSpan.FromSeconds(3), () =>
{
m.Frozen = false;
m.SendLocalizedMessage(1005603); // You can move again!
});
}
}
#region Spawn
public List<BaseCreature> SummonedHelpers { get; set; }
private static Type[] SummonTypes = new Type[]
{
typeof(HellHound), typeof(Phoenix),
typeof(FireSteed), typeof(FireElemental),
typeof(LavaElemental), typeof(FireGargoyle),
typeof(Efreet), typeof(Gargoyle),
typeof(Nightmare), typeof(HellCat)
};
public int TotalSummons()
{
if (SummonedHelpers == null || SummonedHelpers.Count == 0)
return 0;
return SummonedHelpers.Where(bc => bc != null && bc.Alive).Count();
}
public virtual void DoSummon()
{
if (Map == null || TotalSummons() > 0)
return;
Type type = SummonTypes[Utility.Random(SummonTypes.Length)];
for (int i = 0; i < 3; i++)
{
if (Combatant == null)
return;
Point3D p = Combatant.Location;
for (int j = 0; j < 10; j++)
{
int x = Utility.RandomMinMax(p.X - 3, p.X + 3);
int y = Utility.RandomMinMax(p.Y - 3, p.Y + 3);
int z = Map.GetAverageZ(x, y);
if (Map.CanSpawnMobile(x, y, z))
{
p = new Point3D(x, y, z);
break;
}
}
BaseCreature spawn = Activator.CreateInstance(type) as BaseCreature;
if (spawn != null)
{
spawn.MoveToWorld(p, Map);
spawn.Team = Team;
spawn.SummonMaster = this;
Timer.DelayCall(TimeSpan.FromSeconds(1), (o) =>
{
BaseCreature s = o as BaseCreature;
if (s != null && s.Combatant != null)
{
if (!(s.Combatant is PlayerMobile) || !((PlayerMobile)s.Combatant).HonorActive)
s.Combatant = Combatant;
}
}, spawn);
AddHelper(spawn);
}
}
}
protected virtual void AddHelper(BaseCreature bc)
{
if (SummonedHelpers == null)
SummonedHelpers = new List<BaseCreature>();
if (!SummonedHelpers.Contains(bc))
SummonedHelpers.Add(bc);
}
public override void Delete()
{
base.Delete();
if (SummonedHelpers != null)
{
ColUtility.Free(SummonedHelpers);
}
}
#endregion
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
writer.Write(SummonedHelpers == null ? 0 : SummonedHelpers.Count);
if (SummonedHelpers != null)
SummonedHelpers.ForEach(m => writer.Write(m));
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
int count = reader.ReadInt();
if (count > 0)
{
for (int i = 0; i < count; i++)
{
BaseCreature summon = reader.ReadMobile() as BaseCreature;
if (summon != null)
{
if (SummonedHelpers == null)
SummonedHelpers = new List<BaseCreature>();
SummonedHelpers.Add(summon);
}
}
}
m_NextAbility = DateTime.UtcNow;
}
}
}

View File

@@ -0,0 +1,360 @@
using System;
using Server.Engines.CannedEvil;
using Server.Items;
using Server.Spells.Fifth;
using Server.Spells.Seventh;
namespace Server.Mobiles
{
public class Barracoon : BaseChampion
{
[Constructable]
public Barracoon()
: base(AIType.AI_Melee)
{
Name = "Barracoon";
Title = "the piper";
Body = 0x190;
Hue = 0x83EC;
SetStr(283, 425);
SetDex(72, 150);
SetInt(505, 750);
SetHits(12000);
SetStam(102, 300);
SetMana(505, 750);
SetDamage(29, 38);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 65, 75);
SetResistance(ResistanceType.Fire, 70, 80);
SetResistance(ResistanceType.Cold, 65, 80);
SetResistance(ResistanceType.Poison, 70, 75);
SetResistance(ResistanceType.Energy, 70, 80);
SetSkill(SkillName.MagicResist, 100.0);
SetSkill(SkillName.Tactics, 118.3, 120.2);
SetSkill(SkillName.Wrestling, 118.4, 122.7);
Fame = 22500;
Karma = -22500;
VirtualArmor = 70;
AddItem(new FancyShirt(Utility.RandomGreenHue()));
AddItem(new LongPants(Utility.RandomYellowHue()));
AddItem(new JesterHat(Utility.RandomPinkHue()));
AddItem(new Cloak(Utility.RandomPinkHue()));
AddItem(new Sandals());
HairItemID = 0x203B; // Short Hair
HairHue = 0x94;
m_SpecialSlayerMechanics = true;
}
public Barracoon(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Greed;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(FangOfRactus) };
}
}
public override Type[] SharedList
{
get
{
return new Type[]
{
typeof(EmbroideredOakLeafCloak),
typeof(DjinnisRing),
typeof(DetectiveBoots),
typeof(GauntletsOfAnger)
};
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(SwampTile), typeof(MonsterStatuette) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { MonsterStatuetteType.Slime };
}
}
public override bool AlwaysMurderer
{
get
{
return true;
}
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override double AutoDispelChance
{
get
{
return 1.0;
}
}
public override bool BardImmune
{
get
{
return !Core.SE;
}
}
public override bool AllureImmune
{
get
{
return true;
}
}
public override bool Unprovokable
{
get
{
return Core.SE;
}
}
public override bool Uncalmable
{
get
{
return Core.SE;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Deadly;
}
}
public override bool ShowFameTitle
{
get
{
return false;
}
}
public override bool ClickTitle
{
get
{
return false;
}
}
public override bool ForceStayHome { get { return true; } }
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
}
public void Polymorph(Mobile m)
{
if (!m.CanBeginAction(typeof(PolymorphSpell)) || !m.CanBeginAction(typeof(IncognitoSpell)) || m.IsBodyMod)
return;
IMount mount = m.Mount;
if (mount != null)
mount.Rider = null;
if (m.Flying)
m.ToggleFlying();
if (m.Mounted)
return;
if (m.BeginAction(typeof(PolymorphSpell)))
{
m.BodyMod = 42;
m.HueMod = 0;
if (m == this) {
m_SlayerVulnerabilities.Add("Vermin");
m_SlayerVulnerabilities.Add("Repond");
}
new ExpirePolymorphTimer(m).Start();
}
}
public void SpawnRatmen(Mobile target)
{
Map map = Map;
if (map == null)
return;
int rats = 0;
IPooledEnumerable eable = GetMobilesInRange(10);
foreach (Mobile m in eable)
{
if (m is Ratman || m is RatmanArcher || m is RatmanMage)
++rats;
}
eable.Free();
if (rats < 16)
{
PlaySound(0x3D);
int newRats = Utility.RandomMinMax(3, 6);
for (int i = 0; i < newRats; ++i)
{
BaseCreature rat;
switch ( Utility.Random(5) )
{
default:
case 0:
case 1:
rat = new Ratman();
break;
case 2:
case 3:
rat = new RatmanArcher();
break;
case 4:
rat = new RatmanMage();
break;
}
rat.Team = Team;
bool validLocation = false;
Point3D loc = Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = X + Utility.Random(3) - 1;
int y = Y + Utility.Random(3) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
loc = new Point3D(x, y, Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
rat.IsChampionSpawn = true;
rat.MoveToWorld(loc, map);
rat.Combatant = target;
}
}
}
public void DoSpecialAbility(Mobile target)
{
if (target == null || target.Deleted) //sanity
return;
if (target.Player && 0.6 >= Utility.RandomDouble()) // 60% chance to polymorph attacker into a ratman
Polymorph(target);
if (0.1 >= Utility.RandomDouble()) // 10% chance to more ratmen
SpawnRatmen(target);
if (0.05 >= Utility.RandomDouble() && !IsBodyMod) // 5% chance to polymorph into a ratman
Polymorph(this);
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
DoSpecialAbility(attacker);
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
DoSpecialAbility(defender);
}
public override void OnDamagedBySpell(Mobile from)
{
base.OnDamagedBySpell(from);
DoSpecialAbility(from);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_SlayerVulnerabilities.Clear();
}
private class ExpirePolymorphTimer : Timer
{
private Mobile m_Owner;
public ExpirePolymorphTimer(Mobile owner)
: base(TimeSpan.FromMinutes(3.0)) //3.0
{
m_Owner = owner;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
if (!m_Owner.CanBeginAction(typeof(PolymorphSpell)))
{
m_Owner.BodyMod = 0;
m_Owner.HueMod = -1;
m_Owner.EndAction(typeof(PolymorphSpell));
if (m_Owner.SlayerVulnerabilities != null)
{
m_Owner.SlayerVulnerabilities.Remove("Vermin");
m_Owner.SlayerVulnerabilities.Remove("Repond");
}
}
}
}
}
}

View File

@@ -0,0 +1,302 @@
using System;
using System.Collections.Generic;
using Server.Engines.CannedEvil;
using Server.Items;
using Server.Services.Virtues;
namespace Server.Mobiles
{
public abstract class BaseChampion : BaseCreature
{
public BaseChampion(AIType aiType)
: this(aiType, FightMode.Closest)
{
}
public BaseChampion(AIType aiType, FightMode mode)
: base(aiType, mode, 18, 1, 0.1, 0.2)
{
}
public BaseChampion(Serial serial)
: base(serial)
{
}
public override bool CanBeParagon { get { return false; } }
public abstract ChampionSkullType SkullType { get; }
public abstract Type[] UniqueList { get; }
public abstract Type[] SharedList { get; }
public abstract Type[] DecorativeList { get; }
public abstract MonsterStatuetteType[] StatueTypes { get; }
public virtual bool NoGoodies
{
get
{
return false;
}
}
public virtual bool CanGivePowerscrolls { get { return true; } }
public static void GivePowerScrollTo(Mobile m, Item item, BaseChampion champ)
{
if (m == null) //sanity
return;
if (!Core.SE || m.Alive)
m.AddToBackpack(item);
else
{
if (m.Corpse != null && !m.Corpse.Deleted)
m.Corpse.DropItem(item);
else
m.AddToBackpack(item);
}
if (item is PowerScroll && m is PlayerMobile)
{
PlayerMobile pm = (PlayerMobile)m;
for (int j = 0; j < pm.JusticeProtectors.Count; ++j)
{
Mobile prot = pm.JusticeProtectors[j];
if (prot.Map != m.Map || prot.Murderer || prot.Criminal || !JusticeVirtue.CheckMapRegion(m, prot) || !prot.InRange(champ, 100))
continue;
int chance = 0;
switch( VirtueHelper.GetLevel(prot, VirtueName.Justice) )
{
case VirtueLevel.Seeker:
chance = 60;
break;
case VirtueLevel.Follower:
chance = 80;
break;
case VirtueLevel.Knight:
chance = 100;
break;
}
if (chance > Utility.Random(100))
{
PowerScroll powerScroll = CreateRandomPowerScroll();
prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
if (!Core.SE || prot.Alive)
prot.AddToBackpack(powerScroll);
else
{
if (prot.Corpse != null && !prot.Corpse.Deleted)
prot.Corpse.DropItem(powerScroll);
else
prot.AddToBackpack(powerScroll);
}
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public virtual Item GetArtifact()
{
double random = Utility.RandomDouble();
if (0.05 >= random)
return this.CreateArtifact(this.UniqueList);
else if (0.15 >= random)
return this.CreateArtifact(this.SharedList);
else if (0.30 >= random)
return this.CreateArtifact(this.DecorativeList);
return null;
}
public Item CreateArtifact(Type[] list)
{
if (list.Length == 0)
return null;
int random = Utility.Random(list.Length);
Type type = list[random];
Item artifact = Loot.Construct(type);
if (artifact is MonsterStatuette && this.StatueTypes.Length > 0)
{
((MonsterStatuette)artifact).Type = this.StatueTypes[Utility.Random(this.StatueTypes.Length)];
((MonsterStatuette)artifact).LootType = LootType.Regular;
}
return artifact;
}
public virtual void GivePowerScrolls()
{
if (this.Map != Map.Felucca)
return;
List<Mobile> toGive = new List<Mobile>();
List<DamageStore> rights = GetLootingRights();
for (int i = rights.Count - 1; i >= 0; --i)
{
DamageStore ds = rights[i];
if (ds.m_HasRight && InRange(ds.m_Mobile, 100) && ds.m_Mobile.Map == this.Map)
toGive.Add(ds.m_Mobile);
}
if (toGive.Count == 0)
return;
for (int i = 0; i < toGive.Count; i++)
{
Mobile m = toGive[i];
if (!(m is PlayerMobile))
continue;
bool gainedPath = false;
int pointsToGain = 800;
if (VirtueHelper.Award(m, VirtueName.Valor, pointsToGain, ref gainedPath))
{
if (gainedPath)
m.SendLocalizedMessage(1054032); // You have gained a path in Valor!
else
m.SendLocalizedMessage(1054030); // You have gained in Valor!
//No delay on Valor gains
}
}
// Randomize - PowerScrolls
for (int i = 0; i < toGive.Count; ++i)
{
int rand = Utility.Random(toGive.Count);
Mobile hold = toGive[i];
toGive[i] = toGive[rand];
toGive[rand] = hold;
}
for (int i = 0; i < ChampionSystem.PowerScrollAmount; ++i)
{
Mobile m = toGive[i % toGive.Count];
PowerScroll ps = CreateRandomPowerScroll();
m.SendLocalizedMessage(1049524); // You have received a scroll of power!
GivePowerScrollTo(m, ps, this);
}
if (Core.TOL)
{
// Randomize - Primers
for (int i = 0; i < toGive.Count; ++i)
{
int rand = Utility.Random(toGive.Count);
Mobile hold = toGive[i];
toGive[i] = toGive[rand];
toGive[rand] = hold;
}
for (int i = 0; i < ChampionSystem.PowerScrollAmount; ++i)
{
Mobile m = toGive[i % toGive.Count];
SkillMasteryPrimer p = CreateRandomPrimer();
m.SendLocalizedMessage(1156209); // You have received a mastery primer!
GivePowerScrollTo(m, p, this);
}
}
ColUtility.Free(toGive);
}
public virtual void OnChampPopped(ChampionSpawn spawn)
{
}
public override bool OnBeforeDeath()
{
if (CanGivePowerscrolls && !NoKillAwards)
{
this.GivePowerScrolls();
if (this.NoGoodies)
return base.OnBeforeDeath();
GoldShower.DoForChamp(Location, Map);
}
return base.OnBeforeDeath();
}
public override void OnDeath(Container c)
{
if (this.Map == Map.Felucca)
{
//TODO: Confirm SE change or AoS one too?
List<DamageStore> rights = GetLootingRights();
List<Mobile> toGive = new List<Mobile>();
for (int i = rights.Count - 1; i >= 0; --i)
{
DamageStore ds = rights[i];
if (ds.m_HasRight)
toGive.Add(ds.m_Mobile);
}
if (SkullType != ChampionSkullType.None)
{
if (toGive.Count > 0)
toGive[Utility.Random(toGive.Count)].AddToBackpack(new ChampionSkull(this.SkullType));
else
c.DropItem(new ChampionSkull(this.SkullType));
}
if(Core.SA)
RefinementComponent.Roll(c, 3, 0.10);
}
base.OnDeath(c);
}
private static PowerScroll CreateRandomPowerScroll()
{
int level;
double random = Utility.RandomDouble();
if (0.05 >= random)
level = 20;
else if (0.4 >= random)
level = 15;
else
level = 10;
return PowerScroll.CreateRandomNoCraft(level, level);
}
private static SkillMasteryPrimer CreateRandomPrimer()
{
return SkillMasteryPrimer.GetRandom();
}
}
}

View File

@@ -0,0 +1,182 @@
using System;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a chief paroxysmus corpse")]
public class ChiefParoxysmus : BasePeerless
{
[Constructable]
public ChiefParoxysmus()
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "a chief paroxysmus";
Body = 0x100;
SetStr(1232, 1400);
SetDex(76, 82);
SetInt(76, 85);
SetHits(50000);
SetDamage(27, 31);
SetDamageType(ResistanceType.Physical, 80);
SetDamageType(ResistanceType.Poison, 20);
SetResistance(ResistanceType.Physical, 75, 85);
SetResistance(ResistanceType.Fire, 40, 50);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 55, 65);
SetResistance(ResistanceType.Energy, 50, 60);
SetSkill(SkillName.Wrestling, 120.0);
SetSkill(SkillName.Tactics, 120.0);
SetSkill(SkillName.MagicResist, 120.0);
SetSkill(SkillName.Anatomy, 120.0);
SetSkill(SkillName.Poisoning, 120.0);
PackResources(8);
PackTalismans(5);
Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerCallback(SpawnBulbous)); //BulbousPutrification
Fame = 25000;
Karma = -25000;
SetAreaEffect(AreaEffect.PoisonBreath);
}
public ChiefParoxysmus(Serial serial)
: base(serial)
{
}
public override bool GivesMLMinorArtifact
{
get
{
return true;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 8);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new LardOfParoxysmus());
switch ( Utility.Random(3) )
{
case 0:
c.DropItem(new ParoxysmusDinner());
break;
case 1:
c.DropItem(new ParoxysmusCorrodedStein());
break;
case 2:
c.DropItem(new StringOfPartsOfParoxysmusVictims());
break;
}
if (Utility.RandomDouble() < 0.6)
c.DropItem(new ParrotItem());
if (Utility.RandomBool())
c.DropItem(new SweatOfParoxysmus());
if (Utility.RandomDouble() < 0.05)
c.DropItem(new ParoxysmusSwampDragonStatuette());
if (Utility.RandomDouble() < 0.05)
c.DropItem(new ScepterOfTheChief());
}
public override int GetDeathSound()
{
return 0x56F;
}
public override int GetAttackSound()
{
return 0x570;
}
public override int GetIdleSound()
{
return 0x571;
}
public override int GetAngerSound()
{
return 0x572;
}
public override int GetHurtSound()
{
return 0x573;
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
base.OnDamage(amount, from, willKill);
// eats pet or summons
if (from is BaseCreature)
{
BaseCreature creature = (BaseCreature)from;
if (creature.Controlled || creature.Summoned)
{
Heal(creature.Hits);
creature.Kill();
Effects.PlaySound(Location, Map, 0x574);
}
}
// teleports player near
if (from is PlayerMobile && !InRange(from.Location, 1))
{
Combatant = from;
from.MoveToWorld(GetSpawnPosition(1), Map);
from.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
from.PlaySound(0x1FE);
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public virtual void SpawnBulbous()
{
for (int i = 0; i < 3; i++)
{
SpawnHelper(new BulbousPutrification(), GetSpawnPosition(4));
}
}
}
}

View File

@@ -0,0 +1,364 @@
using System;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a crimson dragon corpse")]
public class CrimsonDragon : BasePeerless
{
public override bool GiveMLSpecial { get { return false; } }
private DateTime m_NextTerror;
[Constructable]
public CrimsonDragon()
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "a crimson dragon";
Body = 197;
BaseSoundID = 362;
SetStr(2034, 2140);
SetDex(215, 256);
SetInt(1025, 1116);
SetHits(25000);
SetDamage(8, 10);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Fire, 50);
SetResistance(ResistanceType.Physical, 80, 85);
SetResistance(ResistanceType.Fire, 100);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 80, 85);
SetResistance(ResistanceType.Energy, 80, 85);
SetSkill(SkillName.EvalInt, 110.2, 125.3);
SetSkill(SkillName.Magery, 110.9, 125.5);
SetSkill(SkillName.MagicResist, 116.3, 125.0);
SetSkill(SkillName.Tactics, 111.7, 126.3);
SetSkill(SkillName.Wrestling, 120.5, 128.0);
SetSkill(SkillName.Meditation, 119.4, 130.0);
SetSkill(SkillName.Anatomy, 118.7, 125.0);
SetSkill(SkillName.DetectHidden, 120.0);
// ingredients
PackResources(8);
Fame = 20000;
Karma = -20000;
VirtualArmor = 70;
SetSpecialAbility(SpecialAbility.DragonBreath);
}
public CrimsonDragon(Serial serial)
: base(serial)
{
}
public override bool AlwaysMurderer
{
get
{
return true;
}
}
public override bool Unprovokable
{
get
{
return true;
}
}
public override bool BardImmune
{
get
{
return true;
}
}
public override bool ReacquireOnMovement
{
get
{
return true;
}
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override bool Uncalmable
{
get
{
return true;
}
}
public override int Meat
{
get
{
return 19;
}
}
public override int Hides
{
get
{
return 40;
}
}
public override HideType HideType
{
get
{
return HideType.Barbed;
}
}
public override int Scales
{
get
{
return 12;
}
}
public override ScaleType ScaleType
{
get
{
return (ScaleType)Utility.Random(4);
}
}
public override FoodType FavoriteFood
{
get
{
return FoodType.Meat;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override Poison HitPoison
{
get
{
return Utility.RandomBool() ? Poison.Deadly : Poison.Lethal;
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 8);
AddLoot(LootPack.Gems, 12);
}
public override int GetIdleSound()
{
return 0x2D3;
}
public override int GetHurtSound()
{
return 0x2D1;
}
public override void OnDamagedBySpell(Mobile caster)
{
if (Map != null && caster != this && 0.50 > Utility.RandomDouble())
{
Map = caster.Map;
Location = caster.Location;
Combatant = caster;
Effects.PlaySound(Location, Map, 0x1FE);
}
base.OnDamagedBySpell(caster);
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
base.OnMovement(m, oldLocation);
if (m_NextTerror < DateTime.UtcNow && m != null && InRange(m.Location, 3) && m.IsPlayer())
{
m.Frozen = true;
m.SendLocalizedMessage(1080342, Name, 33); // Terror slices into your very being, destroying any chance of resisting ~1_name~ you might have had
Timer.DelayCall(TimeSpan.FromSeconds(5), new TimerStateCallback(Terrorize), m);
}
}
public override void OnGotMeleeAttack(Mobile attacker)
{
if (Map != null && attacker != this && 0.1 > Utility.RandomDouble())
{
if (attacker is BaseCreature)
{
BaseCreature pet = (BaseCreature)attacker;
if (pet.ControlMaster != null && (attacker is Dragon || attacker is GreaterDragon || attacker is SkeletalDragon || attacker is WhiteWyrm || attacker is Drake))
{
Combatant = null;
pet.Combatant = null;
Combatant = null;
pet.ControlMaster = null;
pet.Controlled = false;
attacker.Emote(String.Format("* {0} decided to go wild *", attacker.Name));
}
if (pet.ControlMaster != null && 0.1 > Utility.RandomDouble())
{
Combatant = null;
pet.Combatant = pet.ControlMaster;
Combatant = null;
attacker.Emote(String.Format("* {0} is being angered *", attacker.Name));
}
}
}
base.OnGotMeleeAttack(attacker);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override bool OnBeforeDeath()
{
Hue = 16385;
if (!NoKillAwards)
{
Map map = Map;
if (map != null)
{
for (int x = -7; x <= 7; ++x)
{
for (int y = -7; y <= 3; ++y)
{
double dist = Math.Sqrt(x * x + y * y);
if (dist <= 12)
new GoodiesTimer(map, X + x, Y + y).Start();
}
}
}
}
return base.OnBeforeDeath();
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.6)
c.DropItem(new ParrotItem());
if (Utility.RandomDouble() < 0.025)
c.DropItem(new CrimsonCincture());
}
private void Terrorize(object o)
{
if (o is Mobile)
{
Mobile m = (Mobile)o;
m.Frozen = false;
m.SendLocalizedMessage(1005603); // You can move again!
m_NextTerror = DateTime.UtcNow + TimeSpan.FromMinutes(5);
}
}
private class GoodiesTimer : Timer
{
private readonly Map m_Map;
private readonly int m_X;
private readonly int m_Y;
public GoodiesTimer(Map map, int x, int y)
: base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0))
{
m_Map = map;
m_X = x;
m_Y = y;
}
protected override void OnTick()
{
int z = m_Map.GetAverageZ(m_X, m_Y);
bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false);
for (int i = -3; !canFit && i <= 3; ++i)
{
canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false);
if (canFit)
z += i;
}
if (!canFit)
return;
Gold g = new Gold(300, 500);
g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map);
if (0.5 >= Utility.RandomDouble())
{
switch (Utility.Random(3))
{
case 0: // Fire column
{
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
Effects.PlaySound(g, g.Map, 0x208);
break;
}
case 1: // Explosion
{
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x36BD, 20, 10, 5044);
Effects.PlaySound(g, g.Map, 0x307);
break;
}
case 2: // Ball of fire
{
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x36FE, 10, 10, 5052);
break;
}
}
}
}
}
}
}

View File

@@ -0,0 +1,490 @@
using Server;
using System;
using Server.Items;
using Server.Mobiles;
using System.Collections.Generic;
namespace Server.Engines.Despise
{
public class DespiseBoss : BaseCreature
{
public static readonly int ArtifactChance = 5;
public virtual BaseCreature SummonWisp { get { return null; } }
public virtual double WispScalar { get { return 0.33; } }
private BaseCreature m_Wisp;
private Timer m_SummonTimer;
[CommandProperty(AccessLevel.GameMaster)]
public BaseCreature Wisp { get { return m_Wisp; } }
public DespiseBoss(AIType ai, FightMode fightmode) : base(ai, fightmode, 10, 1, .1, .2)
{
m_SummonTimer = Timer.DelayCall(TimeSpan.FromSeconds(5), new TimerCallback(SummonWisp_Callback));
FollowersMax = 100;
}
public void SetNonMovable(Item item)
{
item.Movable = false;
AddItem(item);
}
public override int Damage(int amount, Mobile from, bool informMount, bool checkDisrupt)
{
if (from is DespiseCreature)
return base.Damage(amount, from, informMount, checkDisrupt);
return 0;
}
public override void OnKilledBy( Mobile mob )
{
if(mob is PlayerMobile)
{
int chance = ArtifactChance + (int)Math.Min(10, ((PlayerMobile)mob).Luck / 180);
if (chance >= Utility.Random(100))
{
Type t = m_Artifacts[Utility.Random(m_Artifacts.Length)];
if (t != null)
{
Item arty = Loot.Construct(t);
if (arty != null)
{
Container pack = mob.Backpack;
if (pack == null || !pack.TryDropItem(mob, arty, false))
{
mob.BankBox.DropItem(arty);
mob.SendMessage("An artifact has been placed in your bankbox!");
}
else
mob.SendLocalizedMessage(1153440); // An artifact has been placed in your backpack!
}
}
}
}
}
public override void AlterMeleeDamageTo(Mobile to, ref int damage)
{
base.AlterMeleeDamageTo(to, ref damage);
if(m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
damage += (int)((double)damage * WispScalar);
}
public override void AlterMeleeDamageFrom(Mobile from, ref int damage)
{
base.AlterMeleeDamageFrom(from, ref damage);
if(m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
damage -= (int)((double)damage * WispScalar);
}
public override void AlterSpellDamageTo(Mobile to, ref int damage)
{
base.AlterSpellDamageTo(to, ref damage);
if (m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
damage += (int)((double)damage * WispScalar);
}
public override void AlterSpellDamageFrom(Mobile from, ref int damage)
{
base.AlterSpellDamageFrom(from, ref damage);
if (m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
damage -= (int)((double)damage * WispScalar);
}
public override void OnThink()
{
base.OnThink();
if(m_SummonTimer == null && (m_Wisp == null || !m_Wisp.Alive || m_Wisp.Deleted))
{
m_SummonTimer = Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(40, 60)), new TimerCallback(SummonWisp_Callback));
}
}
public void SummonWisp_Callback()
{
m_Wisp = SummonWisp;
BaseCreature.Summon(m_Wisp, true, this, this.Location, 0, TimeSpan.FromMinutes(90));
m_SummonTimer = null;
}
public override void Delete()
{
base.Delete();
if (m_Wisp != null && m_Wisp.Alive)
m_Wisp.Kill();
}
public static Type[] Artifacts { get { return m_Artifacts; } }
private static Type[] m_Artifacts = new Type[]
{
typeof(CompassionsEye),
typeof(UnicornManeWovenSandals),
typeof(UnicornManeWovenTalons),
typeof(DespicableQuiver),
typeof(UnforgivenVeil),
typeof(HailstormHuman),
typeof(HailstormGargoyle),
};
public DespiseBoss(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
writer.Write(m_Wisp);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int v = reader.ReadInt();
m_Wisp = reader.ReadMobile() as BaseCreature;
}
}
public class AdrianTheGloriousLord : DespiseBoss
{
[Constructable]
public AdrianTheGloriousLord() : base(AIType.AI_Mage, FightMode.Closest)
{
Name = "Adrian";
Title = "the Glorious Lord";
Race = Race.Human;
Body = 0x190;
Female = false;
Hue = Race.RandomSkinHue();
HairItemID = 8252;
HairHue = 153;
SetStr( 900, 1200 );
SetDex( 500, 600 );
SetInt( 500, 600 );
SetHits( 60000 );
SetStam( 415 );
SetMana( 22000 );
SetDamage( 18, 28 );
SetDamageType( ResistanceType.Physical, 100 );
SetResistance( ResistanceType.Physical, 40, 60 );
SetResistance( ResistanceType.Fire, 40, 60 );
SetResistance( ResistanceType.Cold, 40, 60 );
SetResistance( ResistanceType.Poison, 40, 60 );
SetResistance( ResistanceType.Energy, 40, 60 );
SetSkill( SkillName.MagicResist, 120 );
SetSkill( SkillName.Tactics, 120 );
SetSkill( SkillName.Wrestling, 120 );
SetSkill( SkillName.Anatomy, 120 );
SetSkill( SkillName.Magery, 120 );
SetSkill( SkillName.EvalInt, 120 );
SetSkill( SkillName.Mysticism, 120 );
SetSkill( SkillName.Focus, 160 );
Fame = 22000;
Karma = 22000;
Item boots = new ThighBoots();
boots.Hue = 1;
Item scimitar = new Item(5046);
scimitar.Hue = 1818;
scimitar.Layer = Layer.OneHanded;
SetNonMovable(boots);
SetNonMovable(scimitar);
SetNonMovable(new LongPants(1818));
SetNonMovable(new FancyShirt(194));
SetNonMovable(new Doublet(1281));
}
public override bool InitialInnocent { get { return true; } }
public override BaseCreature SummonWisp { get { return new EnsorcledWisp(); } }
public override void GenerateLoot()
{
AddLoot( LootPack.SuperBoss, 3);
}
public AdrianTheGloriousLord(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int v = reader.ReadInt();
}
}
public class AndrosTheDreadLord : DespiseBoss
{
[Constructable]
public AndrosTheDreadLord() : base(AIType.AI_Mage, FightMode.Closest)
{
Name = "Andros";
Title = "the Dread Lord";
Race = Race.Human;
Body = 0x190;
Female = false;
Hue = Race.RandomSkinHue();
HairItemID = 0;
SetStr( 900, 1200 );
SetDex( 500, 600 );
SetInt( 500, 600 );
SetHits( 60000 );
SetStam( 415 );
SetMana( 22000 );
SetDamage( 18, 28 );
SetDamageType( ResistanceType.Physical, 100 );
SetResistance( ResistanceType.Physical, 40, 60 );
SetResistance( ResistanceType.Fire, 40, 60 );
SetResistance( ResistanceType.Cold, 40, 60 );
SetResistance( ResistanceType.Poison, 40, 60 );
SetResistance( ResistanceType.Energy, 40, 60 );
SetSkill( SkillName.MagicResist, 120 );
SetSkill( SkillName.Tactics, 120 );
SetSkill( SkillName.Wrestling, 120 );
SetSkill( SkillName.Anatomy, 120 );
SetSkill( SkillName.Magery, 120 );
SetSkill( SkillName.EvalInt, 120 );
SetSkill( SkillName.Mysticism, 120 );
SetSkill( SkillName.Focus, 160 );
Fame = 22000;
Karma = -22000;
Item boots = new ThighBoots();
boots.Hue = 1;
Item staff = new Item(3721);
staff.Layer = Layer.TwoHanded;
SetNonMovable(boots);
SetNonMovable(new LongPants(1818));
SetNonMovable(new FancyShirt(2726));
SetNonMovable(new Doublet(1153));
SetNonMovable(staff);
}
public override bool AlwaysMurderer { get { return true; } }
public override BaseCreature SummonWisp { get { return new CorruptedWisp(); } }
public override void GenerateLoot()
{
AddLoot( LootPack.SuperBoss, 3);
}
public AndrosTheDreadLord(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int v = reader.ReadInt();
}
}
public class EnsorcledWisp : BaseCreature
{
public EnsorcledWisp() : base(AIType.AI_Melee, FightMode.None, 10, 1, .2, .4)
{
Name = "Ensorcled Wisp";
Body = 165;
Hue = 0x901;
BaseSoundID = 466;
SetStr( 600, 700 );
SetDex( 500, 600 );
SetInt( 500, 600 );
SetHits( 7000, 8000 );
SetDamage( 12, 19 );
SetDamageType( ResistanceType.Physical, 40 );
SetDamageType( ResistanceType.Fire, 30 );
SetDamageType( ResistanceType.Energy, 30 );
SetResistance( ResistanceType.Physical, 50 );
SetResistance( ResistanceType.Fire, 60, 70 );
SetResistance( ResistanceType.Cold, 60, 70 );
SetResistance( ResistanceType.Poison, 50, 60 );
SetResistance( ResistanceType.Energy, 60, 70 );
SetSkill( SkillName.MagicResist, 110, 125 );
SetSkill( SkillName.Tactics, 110, 125 );
SetSkill( SkillName.Wrestling, 110, 125 );
SetSkill( SkillName.Anatomy, 110, 125 );
Fame = 8000;
Karma = 8000;
}
public override void OnThink()
{
base.OnThink();
if (ControlTarget != ControlMaster || ControlOrder != OrderType.Follow)
{
ControlTarget = ControlMaster;
ControlOrder = OrderType.Follow;
}
}
public override void GenerateLoot()
{
AddLoot( LootPack.FilthyRich, 3);
}
public override bool OnBeforeDeath()
{
Summoned = false;
PackItem(new Gold(Utility.Random(800, 1000)));
return base.OnBeforeDeath();
}
public override bool InitialInnocent { get { return true; } }
//public override bool ForceNotoriety { get { return true; } }
public EnsorcledWisp(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int v = reader.ReadInt();
}
}
public class CorruptedWisp : BaseCreature
{
public CorruptedWisp() : base(AIType.AI_Melee, FightMode.None, 10, 1, .2, .4)
{
Name = "Corrupted Wisp";
Body = 165;
Hue = 1955;
BaseSoundID = 466;
SetStr( 600, 700 );
SetDex( 500, 600 );
SetInt( 500, 600 );
SetHits( 7000, 8000 );
SetDamage( 12, 19 );
SetDamageType( ResistanceType.Physical, 40 );
SetDamageType( ResistanceType.Fire, 30 );
SetDamageType( ResistanceType.Energy, 30 );
SetResistance( ResistanceType.Physical, 50 );
SetResistance( ResistanceType.Fire, 60, 70 );
SetResistance( ResistanceType.Cold, 60, 70 );
SetResistance( ResistanceType.Poison, 50, 60 );
SetResistance( ResistanceType.Energy, 60, 70 );
SetSkill( SkillName.MagicResist, 110, 125 );
SetSkill( SkillName.Tactics, 110, 125 );
SetSkill( SkillName.Wrestling, 110, 125 );
SetSkill( SkillName.Anatomy, 110, 125 );
Fame = 8000;
Karma = -8000;
}
public override void OnThink()
{
base.OnThink();
if (ControlTarget != ControlMaster || ControlOrder != OrderType.Follow)
{
ControlTarget = ControlMaster;
ControlOrder = OrderType.Follow;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.FilthyRich, 3);
}
public override bool OnBeforeDeath()
{
Summoned = false;
PackItem(new Gold(Utility.Random(800, 1000)));
return base.OnBeforeDeath();
}
public override bool AlwaysMurderer { get { return true; } }
//public override bool ForceNotoriety { get { return true; } }
public CorruptedWisp(Serial serial) : base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int v = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,299 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Server;
using Server.Items;
using Server.Misc;
using Server.Spells;
using Server.Spells.Third;
using Server.Spells.Sixth;
using Server.Targeting;
namespace Server.Mobiles
{
[CorpseName( "a dread horns corpse" )]
public class DreadHorn : BasePeerless
{
public virtual int StrikingRange{ get{ return 12; } }
[Constructable]
public DreadHorn() : base( AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4 )
{
Name = "a Dread Horn";
Body = 257;
BaseSoundID = 0xA8;
SetStr( 878, 993 );
SetDex( 581, 683 );
SetInt( 1200, 1300 );
SetHits( 50000 );
SetStam( 507, 669 );
SetMana( 1200, 1300 );
SetDamage( 21, 28 );
SetDamageType( ResistanceType.Physical, 40 );
SetDamageType( ResistanceType.Poison, 60 );
SetResistance( ResistanceType.Physical, 40, 55 );
SetResistance( ResistanceType.Fire, 50, 65 );
SetResistance( ResistanceType.Cold, 50, 65 );
SetResistance( ResistanceType.Poison, 65, 75 );
SetResistance( ResistanceType.Energy, 60, 75 );
SetSkill( SkillName.Wrestling, 90.0 );
SetSkill( SkillName.Tactics, 90.0 );
SetSkill( SkillName.MagicResist, 110.0 );
SetSkill( SkillName.Poisoning, 120.0 );
SetSkill( SkillName.Magery, 110.0 );
SetSkill( SkillName.EvalInt, 110.0 );
SetSkill( SkillName.Meditation, 110.0 );
SetSkill(SkillName.Spellweaving, 120.0);
// TODO 1-3 spellweaving scroll
Fame = 32000;
Karma = -32000;
PackResources( 8 );
PackTalismans( 5 );
m_Change = DateTime.UtcNow;
m_Stomp = DateTime.UtcNow;
m_Teleport = DateTime.UtcNow;
for (int i = 0; i < Utility.RandomMinMax(1, 3); i++)
{
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 8);
AddLoot(LootPack.LowScrolls, 4);
AddLoot(LootPack.MedScrolls, 4);
AddLoot(LootPack.HighScrolls, 4);
}
public override void OnThink()
{
base.OnThink();
if ( Combatant != null )
{
if ( m_Change < DateTime.UtcNow && Utility.RandomDouble() < 0.1 )
ChangeOpponent();
if ( m_Stomp < DateTime.UtcNow && Utility.RandomDouble() < 0.1 )
HoofStomp();
if (m_Teleport < DateTime.UtcNow && Utility.RandomDouble() < 0.1)
Teleport();
}
}
public override void OnDeath( Container c )
{
base.OnDeath( c );
c.DropItem( new DreadHornMane() );
if ( Utility.RandomDouble() < 0.6 )
c.DropItem( new TaintedMushroom() );
if ( Utility.RandomDouble() < 0.6 )
c.DropItem( new ParrotItem() );
if ( Utility.RandomDouble() < 0.5 )
c.DropItem( new MangledHeadOfDreadhorn() );
if ( Utility.RandomDouble() < 0.5 )
c.DropItem( new HornOfTheDreadhorn() );
if ( Utility.RandomDouble() < 0.05 )
c.DropItem( new PristineDreadHorn() );
if ( Utility.RandomDouble() < 0.05 )
c.DropItem( new DreadFlute() );
if ( Utility.RandomDouble() < 0.05 )
c.DropItem( new DreadsRevenge() );
}
public override int Hides{ get{ return 10; } }
public override HideType HideType{ get{ return HideType.Regular; } }
public override int Meat{ get{ return 5; } }
public override MeatType MeatType{ get{ return MeatType.Ribs; } }
public override bool GivesMLMinorArtifact { get { return true; } }
public override bool Unprovokable{ get{ return true; } }
public override Poison PoisonImmune{ get{ return Poison.Deadly; } }
public override Poison HitPoison{ get{ return Poison.Lethal; } }
public override int TreasureMapLevel{ get{ return 5; } }
public DreadHorn( Serial serial ) : base( serial )
{
}
public override void Serialize( GenericWriter writer )
{
base.Serialize( writer );
writer.Write( (int) 0 ); // version
}
public override void Deserialize( GenericReader reader )
{
base.Deserialize( reader );
int version = reader.ReadInt();
m_Change = DateTime.UtcNow;
m_Stomp = DateTime.UtcNow;
m_Teleport = DateTime.UtcNow;
}
private DateTime m_Change;
private DateTime m_Stomp;
private DateTime m_Teleport;
private void Teleport()
{
var toTele = SpellHelper.AcquireIndirectTargets(this, Location, Map, StrikingRange).OfType<PlayerMobile>().ToList();
if (toTele.Count > 0)
{
var from = toTele[Utility.Random(toTele.Count)];
if (from != null)
{
Combatant = from;
from.MoveToWorld(GetSpawnPosition(1), Map);
from.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
from.PlaySound(0x1FE);
from.ApplyPoison(this, HitPoison);
}
}
ColUtility.Free(toTele);
m_Teleport = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(40, 60));
}
public void ChangeOpponent()
{
Mobile agro, best = null;
double distance, random = Utility.RandomDouble();
if (random < 0.75)
{
// find random target relatively close
for (int i = 0; i < Aggressors.Count && best == null; i++)
{
agro = Validate(Aggressors[i].Attacker);
if (agro == null)
continue;
distance = StrikingRange - GetDistanceToSqrt(agro);
if (distance > 0 && distance < StrikingRange - 2 && InLOS(agro.Location))
{
distance /= StrikingRange;
if (random < distance)
best = agro;
}
}
}
else
{
int damage = 0;
// find a player who dealt most damage
for (int i = 0; i < DamageEntries.Count; i++)
{
agro = Validate(DamageEntries[i].Damager);
if (agro == null)
continue;
distance = GetDistanceToSqrt(agro);
if (distance < StrikingRange && DamageEntries[i].DamageGiven > damage && InLOS(agro.Location))
{
best = agro;
damage = DamageEntries[i].DamageGiven;
}
}
}
if (best != null)
{
// teleport
best.Location = BasePeerless.GetSpawnPosition(Location, Map, 1);
best.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
best.PlaySound(0x1FE);
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
{
best.ApplyPoison(this, HitPoison);
best.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist);
best.PlaySound(0x474);
});
m_Change = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10));
}
}
public void HoofStomp()
{
if (Map == null)
return;
foreach (Mobile m in SpellHelper.AcquireIndirectTargets(this, Location, Map, StrikingRange).OfType<Mobile>())
{
if (m.GetStatMod("DreadHornStr") == null)
{
double percent = m.Skills.MagicResist.Value / 100;
int malas = (int)(-20 + (percent * 5.2));
m.AddStatMod(new StatMod(StatType.Str, "DreadHornStr", m.Str < Math.Abs(malas) ? m.Str / 2 : malas, TimeSpan.FromSeconds(60)));
m.AddStatMod(new StatMod(StatType.Dex, "DreadHornDex", m.Dex < Math.Abs(malas) ? m.Dex / 2 : malas, TimeSpan.FromSeconds(60)));
m.AddStatMod(new StatMod(StatType.Int, "DreadHornInt", m.Int < Math.Abs(malas) ? m.Int / 2 : malas, TimeSpan.FromSeconds(60)));
}
m.SendLocalizedMessage(1075081); // *Dreadhorn’s eyes light up, his mouth almost a grin, as he slams one hoof to the ground!*
}
// earthquake
PlaySound( 0x2F3 );
m_Stomp = DateTime.UtcNow + TimeSpan.FromSeconds( Utility.RandomMinMax( 60, 80 ) );
}
public static bool IsUnderInfluence(Mobile m)
{
return m.GetStatMod("DreadHornStr") != null;
}
public Mobile Validate( Mobile m )
{
Mobile agro;
if ( m is BaseCreature )
agro = ( (BaseCreature) m ).ControlMaster;
else
agro = m;
if ( !CanBeHarmful( agro, false ) || !agro.Player /*|| Combatant == agro*/ )
return null;
return agro;
}
}
}

View File

@@ -0,0 +1,564 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server.Items;
using Server.Engines.CannedEvil;
using Server.Services.Virtues;
namespace Server.Mobiles
{
public class Harrower : BaseCreature
{
private int m_StatCap = Config.Get("PlayerCaps.TotalStatCap", 225);
private static readonly SpawnEntry[] m_Entries = new SpawnEntry[]
{
new SpawnEntry(new Point3D(5242, 945, -40), new Point3D(1176, 2638, 0)), // Destard
new SpawnEntry(new Point3D(5225, 798, 0), new Point3D(1176, 2638, 0)), // Destard
new SpawnEntry(new Point3D(5556, 886, 30), new Point3D(1298, 1080, 0)), // Despise
new SpawnEntry(new Point3D(5187, 615, 0), new Point3D(4111, 432, 5)), // Deceit
new SpawnEntry(new Point3D(5319, 583, 0), new Point3D(4111, 432, 5)), // Deceit
new SpawnEntry(new Point3D(5713, 1334, -1), new Point3D(2923, 3407, 8)), // Fire
new SpawnEntry(new Point3D(5860, 1460, -2), new Point3D(2923, 3407, 8)), // Fire
new SpawnEntry(new Point3D(5328, 1620, 0), new Point3D(5451, 3143, -60)), // Terathan Keep
new SpawnEntry(new Point3D(5690, 538, 0), new Point3D(2042, 224, 14)), // Wrong
new SpawnEntry(new Point3D(5609, 195, 0), new Point3D(514, 1561, 0)), // Shame
new SpawnEntry(new Point3D(5475, 187, 0), new Point3D(514, 1561, 0)), // Shame
new SpawnEntry(new Point3D(6085, 179, 0), new Point3D(4721, 3822, 0)), // Hythloth
new SpawnEntry(new Point3D(6084, 66, 0), new Point3D(4721, 3822, 0)), // Hythloth
/*new SpawnEntry(new Point3D(5499, 2003, 0), new Point3D(2499, 919, 0)), // Covetous*/
new SpawnEntry(new Point3D(5579, 1858, 0), new Point3D(2499, 919, 0))// Covetous
};
private static readonly ArrayList m_Instances = new ArrayList();
private static readonly double[] m_Offsets = new double[]
{
Math.Cos(000.0 / 180.0 * Math.PI), Math.Sin(000.0 / 180.0 * Math.PI),
Math.Cos(040.0 / 180.0 * Math.PI), Math.Sin(040.0 / 180.0 * Math.PI),
Math.Cos(080.0 / 180.0 * Math.PI), Math.Sin(080.0 / 180.0 * Math.PI),
Math.Cos(120.0 / 180.0 * Math.PI), Math.Sin(120.0 / 180.0 * Math.PI),
Math.Cos(160.0 / 180.0 * Math.PI), Math.Sin(160.0 / 180.0 * Math.PI),
Math.Cos(200.0 / 180.0 * Math.PI), Math.Sin(200.0 / 180.0 * Math.PI),
Math.Cos(240.0 / 180.0 * Math.PI), Math.Sin(240.0 / 180.0 * Math.PI),
Math.Cos(280.0 / 180.0 * Math.PI), Math.Sin(280.0 / 180.0 * Math.PI),
Math.Cos(320.0 / 180.0 * Math.PI), Math.Sin(320.0 / 180.0 * Math.PI),
};
private bool m_TrueForm;
private bool m_IsSpawned;
private Item m_GateItem;
private List<HarrowerTentacles> m_Tentacles;
Dictionary<Mobile, int> m_DamageEntries;
[Constructable]
public Harrower()
: base(AIType.AI_NecroMage, FightMode.Closest, 18, 1, 0.2, 0.4)
{
Name = "the harrower";
BodyValue = 146;
SetStr(900, 1000);
SetDex(125, 135);
SetInt(1000, 1200);
Fame = 22500;
Karma = -22500;
VirtualArmor = 60;
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Energy, 50);
SetResistance(ResistanceType.Physical, 55, 65);
SetResistance(ResistanceType.Fire, 60, 80);
SetResistance(ResistanceType.Cold, 60, 80);
SetResistance(ResistanceType.Poison, 60, 80);
SetResistance(ResistanceType.Energy, 60, 80);
SetSkill(SkillName.Wrestling, 90.1, 100.0);
SetSkill(SkillName.Tactics, 90.2, 110.0);
SetSkill(SkillName.MagicResist, 120.2, 160.0);
SetSkill(SkillName.Magery, 120.0);
SetSkill(SkillName.EvalInt, 120.0);
SetSkill(SkillName.Meditation, 120.0);
m_Tentacles = new List<HarrowerTentacles>();
}
public Harrower(Serial serial)
: base(serial)
{
}
public static ArrayList Instances
{
get
{
return m_Instances;
}
}
public static bool CanSpawn
{
get
{
return (m_Instances.Count == 0);
}
}
public Type[] UniqueList
{
get
{
return new Type[] { typeof(AcidProofRobe) };
}
}
public Type[] SharedList
{
get
{
return new Type[] { typeof(TheRobeOfBritanniaAri) };
}
}
public Type[] DecorativeList
{
get
{
return new Type[] { typeof(EvilIdolSkull), typeof(SkullPole) };
}
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override bool Unprovokable
{
get
{
return true;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public override int HitsMax
{
get
{
return m_TrueForm ? 65000 : 30000;
}
}
[CommandProperty(AccessLevel.GameMaster)]
public override int ManaMax
{
get
{
return 5000;
}
}
public override bool DisallowAllMoves
{
get
{
return m_TrueForm;
}
}
public override bool TeleportsTo { get { return true; } }
public static Harrower Spawn(Point3D platLoc, Map platMap)
{
if (m_Instances.Count > 0)
return null;
SpawnEntry entry = m_Entries[Utility.Random(m_Entries.Length)];
Harrower harrower = new Harrower();
harrower.m_IsSpawned = true;
m_Instances.Add(harrower);
harrower.MoveToWorld(entry.m_Location, Map.Felucca);
harrower.m_GateItem = new HarrowerGate(harrower, platLoc, platMap, entry.m_Entrance, Map.Felucca);
return harrower;
}
public override void GenerateLoot()
{
AddLoot(LootPack.SuperBoss, 2);
AddLoot(LootPack.Meager);
}
public void Morph()
{
if (m_TrueForm)
return;
m_TrueForm = true;
Name = "the true harrower";
BodyValue = 780;
Hue = 0x497;
Hits = HitsMax;
Stam = StamMax;
Mana = ManaMax;
ProcessDelta();
Say(1049499); // Behold my true form!
Map map = Map;
if (map != null)
{
for (int i = 0; i < m_Offsets.Length; i += 2)
{
double rx = m_Offsets[i];
double ry = m_Offsets[i + 1];
int dist = 0;
bool ok = false;
int x = 0, y = 0, z = 0;
while (!ok && dist < 10)
{
int rdist = 10 + dist;
x = X + (int)(rx * rdist);
y = Y + (int)(ry * rdist);
z = map.GetAverageZ(x, y);
if (!(ok = map.CanFit(x, y, Z, 16, false, false)))
ok = map.CanFit(x, y, z, 16, false, false);
if (dist >= 0)
dist = -(dist + 1);
else
dist = -(dist - 1);
}
if (!ok)
continue;
HarrowerTentacles spawn = new HarrowerTentacles(this);
spawn.Team = Team;
spawn.MoveToWorld(new Point3D(x, y, z), map);
m_Tentacles.Add(spawn);
}
}
}
public override void OnAfterDelete()
{
m_Instances.Remove(this);
base.OnAfterDelete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1); // version
writer.Write(m_IsSpawned);
writer.Write(m_TrueForm);
writer.Write(m_GateItem);
writer.WriteMobileList<HarrowerTentacles>(m_Tentacles);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch ( version )
{
case 1:
{
m_IsSpawned = reader.ReadBool();
goto case 0;
}
case 0:
{
m_TrueForm = reader.ReadBool();
m_GateItem = reader.ReadItem();
m_Tentacles = reader.ReadStrongMobileList<HarrowerTentacles>();
break;
}
}
if (m_IsSpawned)
m_Instances.Add(this);
}
public void GivePowerScrolls()
{
List<Mobile> toGive = new List<Mobile>();
List<DamageStore> rights = GetLootingRights();
for (int i = rights.Count - 1; i >= 0; --i)
{
DamageStore ds = rights[i];
if (ds.m_HasRight)
toGive.Add(ds.m_Mobile);
}
if (toGive.Count == 0)
return;
// Randomize
for (int i = 0; i < toGive.Count; ++i)
{
int rand = Utility.Random(toGive.Count);
Mobile hold = toGive[i];
toGive[i] = toGive[rand];
toGive[rand] = hold;
}
for (int i = 0; i < ChampionSystem.StatScrollAmount; ++i)
{
Mobile m = toGive[i % toGive.Count];
m.SendLocalizedMessage(1049524); // You have received a scroll of power!
m.AddToBackpack(new StatCapScroll(m_StatCap + RandomStatScrollLevel()));
if (m is PlayerMobile)
{
PlayerMobile pm = (PlayerMobile)m;
for (int j = 0; j < pm.JusticeProtectors.Count; ++j)
{
Mobile prot = (Mobile)pm.JusticeProtectors[j];
if (prot.Map != m.Map || prot.Murderer || prot.Criminal || !JusticeVirtue.CheckMapRegion(m, prot))
continue;
int chance = 0;
switch ( VirtueHelper.GetLevel(prot, VirtueName.Justice) )
{
case VirtueLevel.Seeker:
chance = 60;
break;
case VirtueLevel.Follower:
chance = 80;
break;
case VirtueLevel.Knight:
chance = 100;
break;
}
if (chance > Utility.Random(100))
{
prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
prot.AddToBackpack(new StatCapScroll(m_StatCap + RandomStatScrollLevel()));
}
}
}
}
}
private static int RandomStatScrollLevel()
{
double random = Utility.RandomDouble();
if (0.1 >= random)
return 25;
else if (0.25 >= random)
return 20;
else if (0.45 >= random)
return 15;
else if (0.70 >= random)
return 10;
return 5;
}
public override bool OnBeforeDeath()
{
if (m_TrueForm)
{
List<DamageStore> rights = GetLootingRights();
for (int i = rights.Count - 1; i >= 0; --i)
{
DamageStore ds = rights[i];
if (ds.m_HasRight && ds.m_Mobile is PlayerMobile)
PlayerMobile.ChampionTitleInfo.AwardHarrowerTitle((PlayerMobile)ds.m_Mobile);
}
if (!NoKillAwards)
{
GivePowerScrolls();
Map map = Map;
GoldShower.DoForHarrower(Location, Map);
m_DamageEntries = new Dictionary<Mobile, int>();
for (int i = 0; i < m_Tentacles.Count; ++i)
{
Mobile m = m_Tentacles[i];
if (!m.Deleted)
m.Kill();
RegisterDamageTo(m);
}
m_Tentacles.Clear();
RegisterDamageTo(this);
AwardArtifact(GetArtifact());
if (m_GateItem != null)
m_GateItem.Delete();
}
return base.OnBeforeDeath();
}
else
{
Morph();
return false;
}
}
public virtual void RegisterDamageTo(Mobile m)
{
if (m == null)
return;
foreach (DamageEntry de in m.DamageEntries)
{
Mobile damager = de.Damager;
Mobile master = damager.GetDamageMaster(m);
if (master != null)
damager = master;
RegisterDamage(damager, de.DamageGiven);
}
}
public void RegisterDamage(Mobile from, int amount)
{
if (from == null || !from.Player)
return;
if (m_DamageEntries.ContainsKey(from))
m_DamageEntries[from] += amount;
else
m_DamageEntries.Add(from, amount);
from.SendMessage(String.Format("Total Damage: {0}", m_DamageEntries[from]));
}
public void AwardArtifact(Item artifact)
{
if (artifact == null)
return;
int totalDamage = 0;
Dictionary<Mobile, int> validEntries = new Dictionary<Mobile, int>();
foreach (KeyValuePair<Mobile, int> kvp in m_DamageEntries)
{
if (IsEligible(kvp.Key, artifact))
{
validEntries.Add(kvp.Key, kvp.Value);
totalDamage += kvp.Value;
}
}
int randomDamage = Utility.RandomMinMax(1, totalDamage);
totalDamage = 0;
foreach (KeyValuePair<Mobile, int> kvp in validEntries)
{
totalDamage += kvp.Value;
if (totalDamage >= randomDamage)
{
GiveArtifact(kvp.Key, artifact);
return;
}
}
artifact.Delete();
}
public void GiveArtifact(Mobile to, Item artifact)
{
if (to == null || artifact == null)
return;
to.PlaySound(0x5B4);
Container pack = to.Backpack;
if (pack == null || !pack.TryDropItem(to, artifact, false))
artifact.Delete();
else
to.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you.
}
public bool IsEligible(Mobile m, Item Artifact)
{
return m.Player && m.Alive && m.InRange(Location, 32) && m.Backpack != null && m.Backpack.CheckHold(m, Artifact, false);
}
public Item GetArtifact()
{
double random = Utility.RandomDouble();
if (0.05 >= random)
return CreateArtifact(UniqueList);
else if (0.15 >= random)
return CreateArtifact(SharedList);
else if (0.30 >= random)
return CreateArtifact(DecorativeList);
return null;
}
public Item CreateArtifact(Type[] list)
{
if (list.Length == 0)
return null;
int random = Utility.Random(list.Length);
Type type = list[random];
return Loot.Construct(type);
}
private class SpawnEntry
{
public readonly Point3D m_Location;
public readonly Point3D m_Entrance;
public SpawnEntry(Point3D loc, Point3D ent)
{
m_Location = loc;
m_Entrance = ent;
}
}
}
}

View File

@@ -0,0 +1,261 @@
using System;
using System.Collections;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a tentacles corpse")]
public class HarrowerTentacles : BaseCreature
{
private Mobile m_Harrower;
private DrainTimer m_Timer;
[Constructable]
public HarrowerTentacles()
: this(null)
{
}
public HarrowerTentacles(Mobile harrower)
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
this.m_Harrower = harrower;
this.Name = "tentacles of the harrower";
this.Body = 129;
this.SetStr(901, 1000);
this.SetDex(126, 140);
this.SetInt(1001, 1200);
this.SetHits(541, 600);
this.SetDamage(13, 20);
this.SetDamageType(ResistanceType.Physical, 20);
this.SetDamageType(ResistanceType.Fire, 20);
this.SetDamageType(ResistanceType.Cold, 20);
this.SetDamageType(ResistanceType.Poison, 20);
this.SetDamageType(ResistanceType.Energy, 20);
this.SetResistance(ResistanceType.Physical, 55, 65);
this.SetResistance(ResistanceType.Fire, 35, 45);
this.SetResistance(ResistanceType.Cold, 35, 45);
this.SetResistance(ResistanceType.Poison, 35, 45);
this.SetResistance(ResistanceType.Energy, 35, 45);
this.SetSkill(SkillName.Meditation, 100.0);
this.SetSkill(SkillName.MagicResist, 120.1, 140.0);
this.SetSkill(SkillName.Swords, 90.1, 100.0);
this.SetSkill(SkillName.Tactics, 90.1, 100.0);
this.SetSkill(SkillName.Wrestling, 90.1, 100.0);
this.Fame = 15000;
this.Karma = -15000;
this.VirtualArmor = 60;
this.m_Timer = new DrainTimer(this);
this.m_Timer.Start();
this.PackReg(50);
this.PackNecroReg(15, 75);
switch (Utility.Random(3))
{
case 0: PackItem(new VampiricEmbraceScroll()); break;
}
}
public HarrowerTentacles(Serial serial)
: base(serial)
{
}
[CommandProperty(AccessLevel.GameMaster)]
public Mobile Harrower
{
get
{
return this.m_Harrower;
}
set
{
this.m_Harrower = value;
}
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override bool Unprovokable
{
get
{
return true;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override bool DisallowAllMoves
{
get
{
return true;
}
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
reflect = true;
}
public override int GetIdleSound()
{
return 0x101;
}
public override int GetAngerSound()
{
return 0x5E;
}
public override int GetDeathSound()
{
return 0x1C2;
}
public override int GetAttackSound()
{
return -1; // unknown
}
public override int GetHurtSound()
{
return 0x289;
}
public override void GenerateLoot()
{
this.AddLoot(LootPack.FilthyRich, 2);
this.AddLoot(LootPack.MedScrolls, 3);
this.AddLoot(LootPack.HighScrolls, 2);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(this.m_Harrower);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
this.m_Harrower = reader.ReadMobile();
this.m_Timer = new DrainTimer(this);
this.m_Timer.Start();
break;
}
}
}
public override void OnAfterDelete()
{
if (this.m_Timer != null)
this.m_Timer.Stop();
this.m_Timer = null;
base.OnAfterDelete();
}
private class DrainTimer : Timer
{
private static readonly ArrayList m_ToDrain = new ArrayList();
private readonly HarrowerTentacles m_Owner;
public DrainTimer(HarrowerTentacles owner)
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
{
this.m_Owner = owner;
this.Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if (this.m_Owner.Deleted)
{
this.Stop();
return;
}
IPooledEnumerable eable = m_Owner.GetMobilesInRange(9);
foreach (Mobile m in eable)
{
if (m == this.m_Owner || m == this.m_Owner.Harrower || !this.m_Owner.CanBeHarmful(m))
continue;
if (m is BaseCreature)
{
BaseCreature bc = m as BaseCreature;
if (bc.Controlled || bc.Summoned)
m_ToDrain.Add(m);
}
else if (m.Player)
{
m_ToDrain.Add(m);
}
}
eable.Free();
foreach (Mobile m in m_ToDrain)
{
this.m_Owner.DoHarmful(m);
m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist);
m.PlaySound(0x1F1);
int drain = Utility.RandomMinMax(14, 30);
//Monster Stealables
if (m is PlayerMobile)
{
PlayerMobile pm = m as PlayerMobile;
drain = (int)LifeShieldLotion.HandleLifeDrain(pm, drain);
}
//end
this.m_Owner.Hits += drain;
if (this.m_Owner.Harrower != null)
this.m_Owner.Harrower.Hits += drain;
m.Damage(drain, this.m_Owner);
}
m_ToDrain.Clear();
}
}
}
}

View File

@@ -0,0 +1,288 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a lady melisande corpse")]
public class LadyMelisande : BasePeerless
{
[Constructable]
public LadyMelisande()
: base(AIType.AI_NecroMage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "a lady melisande";
Body = 0x102;
BaseSoundID = 451;
SetStr(400, 1000);
SetDex(300, 400);
SetInt(1500, 1700);
SetHits(100000);
SetDamage(11, 18);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Energy, 50);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 40, 50);
SetResistance(ResistanceType.Cold, 55, 65);
SetResistance(ResistanceType.Poison, 70, 75);
SetResistance(ResistanceType.Energy, 70, 80);
SetSkill(SkillName.Wrestling, 100, 105);
SetSkill(SkillName.Tactics, 100, 105);
SetSkill(SkillName.MagicResist, 120);
SetSkill(SkillName.Magery, 120);
SetSkill(SkillName.EvalInt, 120);
SetSkill(SkillName.Meditation, 120);
SetSkill(SkillName.Necromancy, 120);
SetSkill(SkillName.SpiritSpeak, 120);
PackResources(8);
PackTalismans(5);
Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerCallback(SpawnSatyrs));
Fame = 25000;
Karma = -25000;
VirtualArmor = 50;
for (int i = 0; i < Utility.RandomMinMax(0, 1); i++)
{
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
}
SetAreaEffect(AreaEffect.AuraOfNausea);
}
public override void GenerateLoot()
{
AddLoot(LootPack.SuperBoss, 8);
AddLoot(LootPack.Parrot, 1);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new DiseasedBark());
c.DropItem(new EternallyCorruptTree());
int drop = Utility.Random(4, 8);
for (int i = 0; i < drop; i++)
c.DropItem(new MelisandesFermentedWine());
if (Utility.RandomDouble() < 0.6)
c.DropItem(new ParrotItem());
if (Utility.RandomDouble() < 0.2225)
{
switch ( Utility.Random(3) )
{
case 0:
c.DropItem(new MelisandesHairDye());
break;
case 1:
c.DropItem(new MelisandesCorrodedHatchet());
break;
case 2:
c.DropItem(new AlbinoSquirrelImprisonedInCrystal());
break;
}
}
}
public override void OnThink()
{
base.OnThink();
Mobile combatant = Combatant as Mobile;
if (combatant != null)
{
if (CanTakeLife(combatant))
TakeLife(combatant);
if (CanSmackTalk())
SmackTalk();
}
}
public override void SetLocation(Point3D newLocation, bool isTeleport)
{
if (newLocation.Z > -10)
base.SetLocation(newLocation, isTeleport);
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
if (willKill)
{
SpawnHelper(new Reaper(), 6490, 948, 19);
SpawnHelper(new InsaneDryad(), 6497, 946, 17);
SpawnHelper(new StoneHarpy(), 6511, 946, 28);
Say(1075118); // Noooooo! You shall never defeat me. Even if I should fall, my tree will sustain me and I will rise again.
}
base.OnDamage(amount, from, willKill);
}
public override bool GivesMLMinorArtifact
{
get
{
return true;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public LadyMelisande(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
#region Smack Talk
private DateTime m_NextSmackTalk;
public bool CanSmackTalk()
{
if (m_NextSmackTalk > DateTime.UtcNow)
return false;
if (Combatant == null)
return false;
return Hits > 0.5 * HitsMax;
}
public void SmackTalk()
{
Say(Utility.RandomMinMax(1075102, 1075115)); // Muahahahaha! I'll feast on your flesh.
m_NextSmackTalk = DateTime.UtcNow + TimeSpan.FromSeconds(2 + Utility.RandomDouble() * 3);
}
#endregion
#region Take Life
private DateTime m_NextTakeLife;
public bool CanTakeLife(Mobile from)
{
if (m_NextTakeLife > DateTime.UtcNow)
return false;
if (!CanBeHarmful(from))
return false;
if (Hits > 0.1 * HitsMax || Hits < 0.025 * HitsMax)
return false;
return true;
}
public void TakeLife(Mobile from)
{
Hits += from.Hits / (from.Player ? 2 : 6);
FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
PlaySound(0x1F2);
Say(1075117); // Muahahaha! Your life essence is MINE!
Say(1075120); // An unholy aura surrounds Lady Melisande as her wounds begin to close.
m_NextTakeLife = DateTime.UtcNow + TimeSpan.FromSeconds(15 + Utility.RandomDouble() * 45);
}
#endregion
#region Helpers
public override bool CanSpawnHelpers
{
get
{
return true;
}
}
public override int MaxHelpersWaves
{
get
{
return 1;
}
}
public override void SpawnHelpers()
{
int count = 4;
if (Altar != null)
{
count = Math.Min(Altar.Fighters.Count, 4);
for (int i = 0; i < count; i++)
{
Mobile fighter = Altar.Fighters[i];
if (CanBeHarmful(fighter))
{
EnslavedSatyr satyr = new EnslavedSatyr();
satyr.FightMode = FightMode.Closest;
SpawnHelper(satyr, GetSpawnPosition(fighter.Location, fighter.Map, 2));
satyr.Combatant = fighter;
fighter.SendLocalizedMessage(1075116); // A twisted satyr scrambles onto the branch beside you and attacks!
}
}
}
else
{
for (int i = 0; i < count; i++)
SpawnHelper(new EnslavedSatyr(), 4);
}
}
public void SpawnSatyrs()
{
SpawnHelper(new EnslavedSatyr(), 6485, 945, 19);
SpawnHelper(new EnslavedSatyr(), 6486, 948, 22);
SpawnHelper(new EnslavedSatyr(), 6487, 945, 17);
SpawnHelper(new EnslavedSatyr(), 6488, 947, 23);
}
#endregion
}
}

View File

@@ -0,0 +1,332 @@
using System;
using Server.Engines.CannedEvil;
using Server.Items;
namespace Server.Mobiles
{
public class LordOaks : BaseChampion
{
private Mobile m_Queen;
private bool m_SpawnedQueen;
[Constructable]
public LordOaks()
: base(AIType.AI_Paladin, FightMode.Evil)
{
Body = 175;
Name = "Lord Oaks";
SetStr(403, 850);
SetDex(101, 150);
SetInt(503, 800);
SetHits(12000);
SetStam(202, 400);
SetDamage(21, 33);
SetDamageType(ResistanceType.Physical, 75);
SetDamageType(ResistanceType.Fire, 25);
SetResistance(ResistanceType.Physical, 85, 90);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 80, 90);
SetResistance(ResistanceType.Energy, 80, 90);
SetSkill(SkillName.Anatomy, 75.1, 100.0);
SetSkill(SkillName.EvalInt, 120.1, 130.0);
SetSkill(SkillName.Magery, 120.0);
SetSkill(SkillName.Meditation, 120.1, 130.0);
SetSkill(SkillName.MagicResist, 100.5, 150.0);
SetSkill(SkillName.Tactics, 100.0);
SetSkill(SkillName.Wrestling, 100.0);
SetSkill(SkillName.Chivalry, 100.0);
Fame = 22500;
Karma = 22500;
VirtualArmor = 100;
}
public LordOaks(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Enlightenment;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(OrcChieftainHelm) };
}
}
public override Type[] SharedList
{
get
{
return new Type[]
{
typeof(RoyalGuardSurvivalKnife),
typeof(DjinnisRing),
typeof(LieutenantOfTheBritannianRoyalGuard),
typeof(SamaritanRobe),
typeof(DetectiveBoots),
typeof(TheMostKnowledgePerson)
};
}
}
public override Type[] DecorativeList
{
get
{
return new Type[]
{
typeof(WaterTile),
typeof(WindSpirit),
typeof(Pier),
};
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { };
}
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override bool CanFly
{
get
{
return true;
}
}
public override bool BardImmune
{
get
{
return !Core.SE;
}
}
public override bool Unprovokable
{
get
{
return Core.SE;
}
}
public override bool Uncalmable
{
get
{
return Core.SE;
}
}
public override TribeType Tribe { get { return TribeType.Fey; } }
public override OppositionGroup OppositionGroup
{
get
{
return OppositionGroup.FeyAndUndead;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Deadly;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 5);
}
public void SpawnPixies(Mobile target)
{
Map map = Map;
if (map == null)
return;
Say(1042154); // You shall never defeat me as long as I have my queen!
int newPixies = Utility.RandomMinMax(3, 6);
for (int i = 0; i < newPixies; ++i)
{
Pixie pixie = new Pixie();
pixie.Team = Team;
pixie.FightMode = FightMode.Closest;
bool validLocation = false;
Point3D loc = Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = X + Utility.Random(3) - 1;
int y = Y + Utility.Random(3) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
loc = new Point3D(x, y, Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
pixie.MoveToWorld(loc, map);
pixie.Combatant = target;
}
}
public override int GetAngerSound()
{
return 0x2F8;
}
public override int GetIdleSound()
{
return 0x2F8;
}
public override int GetAttackSound()
{
return Utility.Random(0x2F5, 2);
}
public override int GetHurtSound()
{
return 0x2F9;
}
public override int GetDeathSound()
{
return 0x2F7;
}
public void CheckQueen()
{
if (Map == null)
return;
if (!m_SpawnedQueen)
{
Say(1042153); // Come forth my queen!
m_Queen = new Silvani();
((BaseCreature)m_Queen).Team = Team;
m_Queen.MoveToWorld(Location, Map);
m_SpawnedQueen = true;
}
else if (m_Queen != null && m_Queen.Deleted)
{
m_Queen = null;
}
}
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
{
CheckQueen();
if (m_Queen != null)
{
scalar *= 0.1;
if (0.1 >= Utility.RandomDouble())
SpawnPixies(caster);
}
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
if (0.25 > Utility.RandomDouble())
{
int toSap = Utility.RandomMinMax(20, 30);
switch (Utility.Random(3))
{
case 0:
defender.Damage(toSap, this);
Hits += toSap;
break;
case 1:
defender.Stam -= toSap;
Stam += toSap;
break;
case 2:
defender.Mana -= toSap;
Mana += toSap;
break;
}
}
/*defender.Damage(Utility.Random(20, 10), this);
defender.Stam -= Utility.Random(20, 10);
defender.Mana -= Utility.Random(20, 10);*/
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
CheckQueen();
if (m_Queen != null && 0.1 >= Utility.RandomDouble())
SpawnPixies(attacker);
/*attacker.Damage(Utility.Random(20, 10), this);
attacker.Stam -= Utility.Random(20, 10);
attacker.Mana -= Utility.Random(20, 10);*/
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write(m_Queen);
writer.Write(m_SpawnedQueen);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch ( version )
{
case 0:
{
m_Queen = reader.ReadMobile();
m_SpawnedQueen = reader.ReadBool();
break;
}
}
}
}
}

View File

@@ -0,0 +1,809 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Mobiles
{
[CorpseName("a medusa corpse")]
public class Medusa : BaseSABoss, ICarvable
{
private List<Mobile> m_TurnedToStone = new List<Mobile>();
public List<Mobile> AffectedMobiles { get { return m_TurnedToStone; } }
public List<Mobile> m_Helpers = new List<Mobile>();
private int m_Scales;
private DateTime m_GazeDelay;
private DateTime m_StoneDelay;
private DateTime m_NextCarve;
[Constructable]
public Medusa()
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.1, 0.2)
{
Name = "Medusa";
Body = 728;
SetStr(1235, 1391);
SetDex(128, 139);
SetInt(537, 664);
SetHits(60000);
SetDamage(21, 28);
SetDamageType(ResistanceType.Physical, 60);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Energy, 20);
SetResistance(ResistanceType.Physical, 55, 65);
SetResistance(ResistanceType.Fire, 55, 65);
SetResistance(ResistanceType.Cold, 55, 65);
SetResistance(ResistanceType.Poison, 80, 90);
SetResistance(ResistanceType.Energy, 60, 75);
SetSkill(SkillName.Anatomy, 110.6, 116.1);
SetSkill(SkillName.EvalInt, 100.0, 114.4);
SetSkill(SkillName.Magery, 100.0);
SetSkill(SkillName.Meditation, 118.2, 127.8);
SetSkill(SkillName.MagicResist, 120.0);
SetSkill(SkillName.Tactics, 111.9, 134.5);
SetSkill(SkillName.Wrestling, 119.7, 128.9);
Fame = 22000;
Karma = -22000;
VirtualArmor = 60;
PackItem(new Arrow(Utility.RandomMinMax(100, 200)));
IronwoodCompositeBow Bow = new IronwoodCompositeBow();
Bow.Movable = false;
AddItem(Bow);
m_Scales = Utility.RandomMinMax(1, 2) + 7;
SetWeaponAbility(WeaponAbility.MortalStrike);
SetSpecialAbility(SpecialAbility.VenomousBite);
}
public Medusa(Serial serial)
: base(serial)
{
}
public override Type[] UniqueSAList
{
get { return new Type[] { typeof(Slither), typeof(IronwoodCompositeBow), typeof(Venom), typeof(PetrifiedSnake), typeof(StoneDragonsTooth), typeof(MedusaFloorTileAddonDeed) }; }
}
public override Type[] SharedSAList
{
get { return new Type[] { typeof(SummonersKilt) }; }
}
public override bool IgnoreYoungProtection { get { return true; } }
public override bool AutoDispel { get { return true; } }
public override double AutoDispelChance { get { return 1.0; } }
public override bool BardImmune { get { return true; } }
public override Poison PoisonImmune { get { return Poison.Lethal; } }
public override Poison HitPoison { get { return (0.8 >= Utility.RandomDouble() ? Poison.Deadly : Poison.Lethal); } }
public override int GetIdleSound() { return 1557; }
public override int GetAngerSound() { return 1554; }
public override int GetHurtSound() { return 1556; }
public override int GetDeathSound() { return 1555; }
public override void OnCarve(Mobile from, Corpse corpse, Item with)
{
int amount = Utility.Random(5) + 1;
corpse.DropItem(new MedusaDarkScales(amount));
if(0.20 > Utility.RandomDouble())
corpse.DropItem(new MedusaBlood());
base.OnCarve(from, corpse, with);
corpse.Carved = true;
}
public override void OnGotMeleeAttack(Mobile m)
{
base.OnGotMeleeAttack(m);
if (0.05 > Utility.RandomDouble())
ReleaseStoneMonster();
}
public override void OnDamagedBySpell(Mobile m)
{
base.OnDamagedBySpell(m);
if (0.05 > Utility.RandomDouble())
ReleaseStoneMonster();
}
public override void OnHarmfulSpell(Mobile from)
{
base.OnHarmfulSpell(from);
if (0.05 > Utility.RandomDouble())
ReleaseStoneMonster();
}
public void RemoveAffectedMobiles(Mobile toRemove)
{
if (m_TurnedToStone.Contains(toRemove))
m_TurnedToStone.Remove(toRemove);
}
public Mobile FindRandomMedusaTarget()
{
List<Mobile> list = new List<Mobile>();
IPooledEnumerable eable = this.GetMobilesInRange(12);
foreach (Mobile m in eable)
{
if ( m == null || m == this || m_TurnedToStone.Contains(m) || !CanBeHarmful(m) || !InLOS(m) || m.AccessLevel > AccessLevel.Player)
continue;
//Pets
if (m is BaseCreature && (((BaseCreature)m).GetMaster() is PlayerMobile))
list.Add(m);
//players
else if (m is PlayerMobile)
list.Add(m);
}
eable.Free();
if (list.Count == 0)
return null;
if (list.Count == 1)
return list[0];
return list[Utility.Random(list.Count)];
}
public static bool CheckBlockGaze(Mobile m)
{
if (m == null)
return false;
Item helm = m.FindItemOnLayer(Layer.Helm);
Item neck = m.FindItemOnLayer(Layer.Neck);
Item ear = m.FindItemOnLayer(Layer.Earrings);
Item shi = m.FindItemOnLayer(Layer.TwoHanded);
bool deflect = false;
int perc = 0;
if (helm != null)
{
if (helm is BaseArmor && ((BaseArmor)helm).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseArmor)helm).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseArmor)helm).GorgonLenseCharges--;
deflect = true;
}
}
else if (helm is BaseClothing && ((BaseClothing)helm).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseClothing)helm).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseClothing)helm).GorgonLenseCharges--;
deflect = true;
}
}
}
if (!deflect && shi != null && shi is BaseShield && ((BaseArmor)shi).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseArmor)shi).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseArmor)shi).GorgonLenseCharges--;
deflect = true;
}
}
if (!deflect && neck != null)
{
if (neck is BaseArmor && ((BaseArmor)neck).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseArmor)neck).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseArmor)neck).GorgonLenseCharges--;
deflect = true;
}
}
else if (neck is BaseJewel && ((BaseJewel)neck).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseJewel)neck).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseJewel)neck).GorgonLenseCharges--;
deflect = true;
}
}
else if (neck is BaseClothing && ((BaseClothing)neck).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseClothing)neck).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseClothing)neck).GorgonLenseCharges--;
deflect = true;
}
}
}
if (!deflect && ear != null)
{
if (ear is BaseJewel && ((BaseJewel)ear).GorgonLenseCharges > 0)
{
perc = GetScaleEffectiveness(((BaseJewel)ear).GorgonLenseType);
if (perc > Utility.Random(100))
{
((BaseJewel)ear).GorgonLenseCharges--;
deflect = true;
}
}
}
return deflect;
}
private static int GetScaleEffectiveness(LenseType type)
{
switch (type)
{
case LenseType.None: return 0;
case LenseType.Enhanced: return 100;
case LenseType.Regular: return 50;
case LenseType.Limited: return 15;
}
return 0;
}
public bool Carve(Mobile from, Item item)
{
if (m_Scales > 0)
{
if (DateTime.UtcNow < m_NextCarve)
{
from.SendLocalizedMessage(1112677); // The creature is still recovering from the previous harvest. Try again in a few seconds.
}
else
{
int amount = Math.Min(m_Scales, Utility.RandomMinMax(2, 3));
m_Scales -= amount;
Item scales = new MedusaLightScales(amount);
if (from.PlaceInBackpack(scales))
{
// You harvest magical resources from the creature and place it in your bag.
from.SendLocalizedMessage(1112676);
}
else
{
scales.MoveToWorld(from.Location, from.Map);
}
new Blood(0x122D).MoveToWorld(Location, Map);
m_NextCarve = DateTime.UtcNow + TimeSpan.FromMinutes(1.0);
return true;
}
}
else
from.SendLocalizedMessage(1112674); // There's nothing left to harvest from this creature.
return false;
}
public override void OnThink()
{
base.OnThink();
if (Combatant == null)
return;
if (m_StoneDelay < DateTime.UtcNow)
SpawnStone();
if (m_GazeDelay < DateTime.UtcNow)
DoGaze();
}
public void DoGaze()
{
Mobile target = FindRandomMedusaTarget();
Map map = Map;
if (map == null || target == null)
return;
if ((target is BaseCreature && ((BaseCreature)target).SummonMaster != this) || CanBeHarmful(target))
{
if (CheckBlockGaze(target))
{
if (GorgonLense.TotalCharges(target) == 0)
target.SendLocalizedMessage(1112600); // Your lenses crumble. You are no longer protected from Medusa's gaze!
else
target.SendLocalizedMessage(1112599); //Your Gorgon Lens deflect Medusa's petrifying gaze!
}
else
{
BaseCreature clone = new MedusaClone(target);
bool validLocation = false;
Point3D loc = Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = X + Utility.Random(10) - 1;
int y = Y + Utility.Random(10) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
loc = new Point3D(x, y, Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
Effects.SendLocationEffect(loc, target.Map, 0x37B9, 10, 5);
clone.Frozen = clone.Blessed = true;
clone.SolidHueOverride = 761;
target.Frozen = target.Blessed = true;
target.SolidHueOverride = 761;
//clone.MoveToWorld(loc, target.Map);
BaseCreature.Summon(clone, false, this, loc, 0, TimeSpan.FromMinutes(90));
if (target is BaseCreature && !((BaseCreature)target).Summoned && ((BaseCreature)target).GetMaster() != null)
((BaseCreature)target).GetMaster().SendLocalizedMessage(1113281, null, 43); // Your pet has been petrified!
else
target.SendLocalizedMessage(1112768); // You have been turned to stone!!!
new GazeTimer(target, clone, this, Utility.RandomMinMax(5, 10)).Start();
m_GazeDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(45, 75));
m_Helpers.Add(clone);
m_TurnedToStone.Add(target);
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.MedusaStone, 1153790, 1153825));
return;
}
}
m_GazeDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(25, 65));
}
public void SpawnStone()
{
DefragHelpers();
Map map = Map;
if (map == null)
return;
int stones = 0;
foreach (Mobile m in m_Helpers)
{
if (!(m is MedusaClone))
++stones;
}
if (stones >= 5)
return;
else
{
BaseCreature stone = GetRandomStoneMonster();
bool validLocation = false;
Point3D loc = Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = X + Utility.Random(10) - 1;
int y = Y + Utility.Random(10) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
loc = new Point3D(x, y, Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
BaseCreature.Summon(stone, false, this, loc, 0, TimeSpan.FromMinutes(90));
//stone.MoveToWorld(loc, map);
stone.Frozen = stone.Blessed = true;
stone.SolidHueOverride = 761;
stone.Combatant = null;
m_Helpers.Add(stone);
}
m_StoneDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 150));
}
private void DefragHelpers()
{
List<Mobile> toDelete = new List<Mobile>();
foreach (Mobile m in m_Helpers)
{
if(m == null)
continue;
if (!m.Alive || m.Deleted)
toDelete.Add(m);
}
foreach (Mobile m in toDelete)
{
if (m_Helpers.Contains(m))
m_Helpers.Remove(m);
}
}
private BaseCreature GetRandomStoneMonster()
{
switch (Utility.Random(6))
{
default:
case 0: return new OphidianWarrior();
case 1: return new OphidianArchmage();
case 2: return new WailingBanshee();
case 3: return new OgreLord();
case 4: return new Dragon();
case 5: return new UndeadGargoyle();
}
}
public void ReleaseStoneMonster()
{
List<Mobile> stones = new List<Mobile>();
foreach (Mobile mob in m_Helpers)
{
if (!(mob is MedusaClone) && mob.Alive)
stones.Add(mob);
}
if(stones.Count == 0)
return;
Mobile m = stones[Utility.Random(stones.Count)];
if (m != null)
{
m.Frozen = m.Blessed = false;
m.SolidHueOverride = -1;
Mobile closest = null;
int dist = 12;
m_Helpers.Remove(m);
IPooledEnumerable eable = m.GetMobilesInRange(12);
foreach (Mobile targ in eable)
{
if (targ != null && targ.Player)
{
targ.SendLocalizedMessage(1112767, null, 43); // Medusa releases one of the petrified creatures!!
targ.Combatant = targ;
}
if (targ is PlayerMobile || (targ is BaseCreature && ((BaseCreature)targ).GetMaster() is PlayerMobile))
{
int d = (int)m.GetDistanceToSqrt(targ.Location);
if (d < dist)
{
dist = d;
closest = targ;
}
}
}
eable.Free();
if (closest != null)
m.Combatant = closest;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.SuperBoss, 8);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (Utility.RandomDouble() < 0.025)
c.DropItem(new MedusaStatue());
}
public override void OnAfterDelete()
{
foreach (Mobile m in m_Helpers)
{
if (m != null && !m.Deleted)
m.Delete();
}
base.OnAfterDelete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
writer.Write((int)m_Scales);
writer.Write(m_Helpers.Count);
foreach (Mobile helper in m_Helpers)
writer.Write(helper);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Scales = reader.ReadInt();
int count = reader.ReadInt();
for (int i = 0; i < count; i++)
{
Mobile m = reader.ReadMobile();
if (m != null && m.Alive)
m_Helpers.Add(m);
}
}
public class GazeTimer : Timer
{
private Mobile target;
private Mobile clone;
private Medusa m_Medusa;
private int m_Count;
public GazeTimer(Mobile m, Mobile mc, Medusa medusa, int duration)
: base(TimeSpan.FromSeconds(duration), TimeSpan.FromSeconds(duration))
{
target = m;
clone = mc;
m_Medusa = medusa;
m_Count = 0;
}
protected override void OnTick()
{
++m_Count;
if (m_Count == 1 && target != null)
{
target.Frozen = false;
target.SolidHueOverride = -1;
target.Blessed = false;
m_Medusa.RemoveAffectedMobiles(target);
if (target is BaseCreature && !((BaseCreature)target).Summoned && ((BaseCreature)target).GetMaster() != null)
((BaseCreature)target).GetMaster().SendLocalizedMessage(1113285, null, 43); // Beware! A statue of your pet has been created!
BuffInfo.RemoveBuff(target, BuffIcon.MedusaStone);
}
else if (m_Count == 2 && clone != null)
{
clone.SolidHueOverride = -1;
clone.Frozen = clone.Blessed = false;
int dist = 12;
Mobile closest = null;
IPooledEnumerable eable = clone.GetMobilesInRange(12);
foreach (Mobile m in eable)
{
int d = (int)clone.GetDistanceToSqrt(m.Location);
if (m != null && m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile))
{
if (m.NetState != null)
{
m.Send(new RemoveMobile(clone));
m.NetState.Send(MobileIncoming.Create(m.NetState, m, clone));
m.SendLocalizedMessage(1112767); // Medusa releases one of the petrified creatures!!
}
if (d < dist)
{
dist = d;
closest = m;
}
}
}
eable.Free();
if (closest != null)
clone.Combatant = closest;
}
else
Stop();
}
}
}
public class MedusaClone : BaseCreature, IFreezable
{
public MedusaClone(Mobile m)
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
SolidHueOverride = 33;
Clone(m);
}
public MedusaClone(Serial serial)
: base(serial)
{
}
public override bool DeleteCorpseOnDeath
{
get
{
return true;
}
}
public override bool ReacquireOnMovement
{
get
{
return true;
}
}
public override bool AlwaysMurderer
{
get
{
return !Frozen;
}
}
public void Clone(Mobile m)
{
if (m == null)
{
Delete();
return;
}
Body = m.Body;
Str = m.Str;
Dex = m.Dex;
Int = m.Int;
Hits = m.HitsMax;
Hue = m.Hue;
Female = m.Female;
Name = m.Name;
NameHue = m.NameHue;
Title = m.Title;
Kills = m.Kills;
HairItemID = m.HairItemID;
HairHue = m.HairHue;
FacialHairItemID = m.FacialHairItemID;
FacialHairHue = m.FacialHairHue;
BaseSoundID = m.BaseSoundID;
for (int i = 0; i < m.Skills.Length; ++i)
{
Skills[i].Base = m.Skills[i].Base;
Skills[i].Cap = m.Skills[i].Cap;
}
for (int i = 0; i < m.Items.Count; i++)
{
if (m.Items[i].Layer != Layer.Backpack && m.Items[i].Layer != Layer.Mount && m.Items[i].Layer != Layer.Bank)
AddItem(CloneItem(m.Items[i]));
}
}
public Item CloneItem(Item item)
{
Item cloned = new Item(item.ItemID);
cloned.Layer = item.Layer;
cloned.Name = item.Name;
cloned.Hue = item.Hue;
cloned.Weight = item.Weight;
cloned.Movable = false;
return cloned;
}
public override void OnDoubleClick(Mobile from)
{
if (Frozen)
DisplayPaperdollTo(from);
else
base.OnDoubleClick(from);
}
public void OnRequestedAnimation(Mobile from)
{
if (Frozen)
{
from.Send(new UpdateStatueAnimation(this, 1, 31, 5));
}
}
public override void OnDelete()
{
Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 15, 5042);
base.OnDelete();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
}
}
namespace Server.Commands
{
public class AddCloneCommands
{
public static void Initialize()
{
CommandSystem.Register("addclone", AccessLevel.Seer, new CommandEventHandler(AddClone_OnCommand));
}
[Description("")]
public static void AddClone_OnCommand(CommandEventArgs e)
{
BaseCreature clone = new MedusaClone(e.Mobile);
clone.Frozen = clone.Blessed = true;
clone.MoveToWorld(e.Mobile.Location, e.Mobile.Map);
}
}
}

View File

@@ -0,0 +1,123 @@
using System;
using Server.Engines.CannedEvil;
using Server.Items;
using System.Collections.Generic;
namespace Server.Mobiles
{
public class Mephitis : BaseChampion
{
[Constructable]
public Mephitis()
: base(AIType.AI_Melee)
{
Body = 173;
Name = "Mephitis";
BaseSoundID = 0x183;
SetStr(505, 1000);
SetDex(102, 300);
SetInt(402, 600);
SetHits(12000);
SetStam(105, 600);
SetDamage(21, 33);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Poison, 50);
SetResistance(ResistanceType.Physical, 75, 80);
SetResistance(ResistanceType.Fire, 60, 70);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 100);
SetResistance(ResistanceType.Energy, 60, 70);
SetSkill(SkillName.MagicResist, 70.7, 140.0);
SetSkill(SkillName.Tactics, 97.6, 100.0);
SetSkill(SkillName.Wrestling, 97.6, 100.0);
Fame = 22500;
Karma = -22500;
VirtualArmor = 80;
SetSpecialAbility(SpecialAbility.Webbing);
ForceActiveSpeed = 0.3;
ForcePassiveSpeed = 0.6;
}
public Mephitis(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Venom;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(Calm) };
}
}
public override Type[] SharedList
{
get
{
return new Type[] { typeof(OblivionsNeedle), typeof(ANecromancerShroud) };
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(Web), typeof(MonsterStatuette) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { MonsterStatuetteType.Spider };
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override Poison HitPoison
{
get
{
return Poison.Lethal;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 4);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,347 @@
using System;
using System.Linq;
using Server.Items;
using Server.Network;
using Server.Spells;
namespace Server.Mobiles
{
[CorpseName("a monstrous interred grizzle corpse")]
public class MonstrousInterredGrizzle : BasePeerless
{
private static readonly int[] m_Tiles = new int[]
{
-2, 0,
2, 0,
2, -2,
2, 2,
-2, -2,
-2, 2,
0, 2,
1, 0,
0, -2
};
private readonly DateTime m_NextDrop = DateTime.UtcNow;
[Constructable]
public MonstrousInterredGrizzle()
: base(AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "a monstrous interred grizzle";
Body = 0x103;
BaseSoundID = 589;
SetStr(1198, 1207);
SetDex(127, 135);
SetInt(595, 646);
SetHits(50000);
SetDamage(27, 31);
SetDamageType(ResistanceType.Physical, 60);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Energy, 20);
SetResistance(ResistanceType.Physical, 48, 52);
SetResistance(ResistanceType.Fire, 77, 82);
SetResistance(ResistanceType.Cold, 56, 61);
SetResistance(ResistanceType.Poison, 32, 40);
SetResistance(ResistanceType.Energy, 69, 71);
SetSkill(SkillName.Wrestling, 112.6, 116.9);
SetSkill(SkillName.Tactics, 118.5, 119.2);
SetSkill(SkillName.MagicResist, 120);
SetSkill(SkillName.Anatomy, 111.0, 111.7);
SetSkill(SkillName.Magery, 100.0);
SetSkill(SkillName.EvalInt, 100);
SetSkill(SkillName.Meditation, 100);
SetSkill(SkillName.Spellweaving, 100.0);
Fame = 24000;
Karma = -24000;
VirtualArmor = 80;
PackResources(8);
PackTalismans(5);
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
{
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
}
SetSpecialAbility(SpecialAbility.HowlOfCacophony);
}
public MonstrousInterredGrizzle(Serial serial)
: base(serial)
{
}
public override bool GivesMLMinorArtifact
{
get
{
return true;
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 8);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new GrizzledBones());
switch (Utility.Random(4))
{
case 0:
c.DropItem(new TombstoneOfTheDamned());
break;
case 1:
c.DropItem(new GlobOfMonstreousInterredGrizzle());
break;
case 2:
c.DropItem(new MonsterousInterredGrizzleMaggots());
break;
case 3:
c.DropItem(new GrizzledSkullCollection());
break;
}
if (Utility.RandomDouble() < 0.6)
c.DropItem(new ParrotItem());
if (Utility.RandomDouble() < 0.05)
c.DropItem(new GrizzledMareStatuette());
if (Utility.RandomDouble() < 0.05)
{
switch (Utility.Random(5))
{
case 0:
c.DropItem(new GrizzleGauntlets());
break;
case 1:
c.DropItem(new GrizzleGreaves());
break;
case 2:
c.DropItem(new GrizzleHelm());
break;
case 3:
c.DropItem(new GrizzleTunic());
break;
case 4:
c.DropItem(new GrizzleVambraces());
break;
}
}
}
public override int GetDeathSound()
{
return 0x57F;
}
public override int GetAttackSound()
{
return 0x580;
}
public override int GetIdleSound()
{
return 0x581;
}
public override int GetAngerSound()
{
return 0x582;
}
public override int GetHurtSound()
{
return 0x583;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
if (Utility.RandomDouble() < 0.06)
SpillAcid(null, Utility.RandomMinMax(1, 3));
base.OnDamage(amount, from, willKill);
}
public override Item NewHarmfulItem()
{
return new InfernalOoze(this, Utility.RandomBool());
}
}
public class InfernalOoze : Item
{
private bool m_Corrosive;
private int m_Damage;
private Mobile m_Owner;
private Timer m_Timer;
private DateTime m_StartTime;
public InfernalOoze(Mobile owner)
: this(owner, false)
{
}
[Constructable]
public InfernalOoze(Mobile owner, bool corrosive, int damage = 40)
: base(0x122A)
{
Movable = false;
m_Owner = owner;
Hue = 0x95;
m_Damage = damage;
m_Corrosive = corrosive;
m_StartTime = DateTime.UtcNow;
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
}
[CommandProperty(AccessLevel.GameMaster)]
public bool Corrosive
{
get { return m_Corrosive; }
set { m_Corrosive = value; }
}
private void OnTick()
{
if (ItemID == 0x122A && m_StartTime + TimeSpan.FromSeconds(30) < DateTime.UtcNow)
{
ItemID++;
}
else if (m_StartTime + TimeSpan.FromSeconds(35) < DateTime.UtcNow)
{
Delete();
return;
}
if (m_Owner == null)
return;
if (!Deleted && Map != Map.Internal && Map != null)
{
foreach (var m in SpellHelper.AcquireIndirectTargets(m_Owner, Location, Map, 0).OfType<Mobile>())
{
OnMoveOver(m);
}
}
}
public override bool OnMoveOver(Mobile m)
{
if (Map == null)
return base.OnMoveOver(m);
if ((m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile) || m.Player)
{
Damage(m);
}
return base.OnMoveOver(m);
}
public virtual void Damage(Mobile m)
{
if (m_Corrosive)
{
for (int i = 0; i < m.Items.Count; i++)
{
IDurability item = m.Items[i] as IDurability;
if (item != null && Utility.RandomDouble() < 0.25)
{
if (item.HitPoints > 10)
item.HitPoints -= 10;
else
item.HitPoints -= 1;
}
}
}
else
{
int dmg = m_Damage;
if (m is PlayerMobile)
{
PlayerMobile pm = m as PlayerMobile;
dmg = (int)BalmOfProtection.HandleDamage(pm, dmg);
AOS.Damage(m, m_Owner, dmg, 0, 0, 0, 100, 0);
}
else
{
AOS.Damage(m, m_Owner, dmg, 0, 0, 0, 100, 0);
}
}
}
public override void Delete()
{
base.Delete();
if (m_Timer != null)
{
m_Timer.Stop();
m_Timer = null;
}
}
public InfernalOoze(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Delete();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
namespace Server.Items
{
public class EyeOfNavrey : Item
{
[Constructable]
public EyeOfNavrey()
: base(0x318D)
{
this.Weight = 1;
this.Hue = 68;
this.LootType = LootType.Blessed;
}
public EyeOfNavrey(Serial serial)
: base(serial)
{
}
public override int LabelNumber
{
get
{
return 1095154;
}
}// Eye of Navrey Night-Eyes
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using Server.Engines.Quests;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a navrey corpse")]
public class Navrey : BaseCreature
{
private NavreysController m_Spawner;
[CommandProperty(AccessLevel.GameMaster)]
public bool UsedPillars { get; set; }
private static readonly Type[] m_Artifact = new Type[]
{
typeof(NightEyes),
typeof(Tangle1)
};
[Constructable]
public Navrey(NavreysController spawner)
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
m_Spawner = spawner;
Name = "Navrey Night-Eyes";
Body = 735;
BaseSoundID = 389;
SetStr(1000, 1500);
SetDex(200, 250);
SetInt(150, 200);
SetHits(30000, 35000);
SetDamage(25, 40);
SetDamageType(ResistanceType.Physical, 50);
SetDamageType(ResistanceType.Fire, 25);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 55, 65);
SetResistance(ResistanceType.Fire, 45, 55);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 100);
SetResistance(ResistanceType.Energy, 65, 80);
SetSkill(SkillName.Anatomy, 50.0, 80.0);
SetSkill(SkillName.EvalInt, 90.0, 100.0);
SetSkill(SkillName.Magery, 90.0, 100.0);
SetSkill(SkillName.MagicResist, 100.0, 130.0);
SetSkill(SkillName.Meditation, 80.0, 100.0);
SetSkill(SkillName.Poisoning, 100.0);
SetSkill(SkillName.Tactics, 90.0, 100.0);
SetSkill(SkillName.Wrestling, 91.6, 98.2);
Fame = 24000;
Karma = -24000;
VirtualArmor = 90;
for (int i = 0; i < Utility.RandomMinMax(1, 3); i++)
{
PackItem(Loot.RandomScroll(0, Loot.MysticismScrollTypes.Length, SpellbookType.Mystic));
}
SetSpecialAbility(SpecialAbility.Webbing);
}
public Navrey(Serial serial)
: base(serial)
{
}
public override double TeleportChance { get { return 0; } }
public override bool AlwaysMurderer { get { return true; } }
public override Poison PoisonImmune { get { return Poison.Parasitic; } }
public override Poison HitPoison { get { return Poison.Lethal; } }
public override int Meat { get { return 1; } }
public static void DistributeRandomArtifact(BaseCreature bc, Type[] typelist)
{
int random = Utility.Random(typelist.Length);
Item item = Loot.Construct(typelist[random]);
DistributeArtifact(DemonKnight.FindRandomPlayer(bc), item);
}
public static void DistributeArtifact(Mobile to, Item artifact)
{
if (artifact == null)
return;
if (to != null)
{
Container pack = to.Backpack;
if (pack == null || !pack.TryDropItem(to, artifact, false))
to.BankBox.DropItem(artifact);
to.SendLocalizedMessage(502088); // A special gift has been placed in your backpack.
}
else
{
artifact.Delete();
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 3);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
if (m_Spawner != null)
m_Spawner.OnNavreyKilled();
if (Utility.RandomBool())
c.AddItem(new UntranslatedAncientTome());
if (0.1 >= Utility.RandomDouble())
c.AddItem(ScrollOfTranscendence.CreateRandom(30, 30));
if (0.1 >= Utility.RandomDouble())
c.AddItem(new TatteredAncientScroll());
if (Utility.RandomDouble() < 0.10)
c.DropItem(new LuckyCoin());
if (Utility.RandomDouble() < 0.025)
DistributeRandomArtifact(this, m_Artifact);
// distribute quest items for the 'Green with Envy' quest given by Vernix
List<DamageStore> rights = GetLootingRights();
for (int i = rights.Count - 1; i >= 0; --i)
{
DamageStore ds = rights[i];
if (!ds.m_HasRight)
rights.RemoveAt(i);
}
// for each with looting rights... give an eye of navrey if they have the quest
foreach (DamageStore d in rights)
{
PlayerMobile pm = d.m_Mobile as PlayerMobile;
if (null != pm)
{
foreach (BaseQuest quest in pm.Quests)
{
if (quest is GreenWithEnvyQuest)
{
Container pack = pm.Backpack;
Item item = new EyeOfNavrey();
if (pack == null || !pack.TryDropItem(pm, item, false))
pm.BankBox.DropItem(item);
pm.SendLocalizedMessage(1095155); // As Navrey Night-Eyes dies, you find and claim one of her eyes as proof of her demise.
break;
}
}
}
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1);
writer.Write((Item)m_Spawner);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version >= 1)
m_Spawner = reader.ReadItem() as NavreysController;
}
}
}

View File

@@ -0,0 +1,387 @@
using System;
using Server.Engines.CannedEvil;
using Server.Items;
namespace Server.Mobiles
{
public class Neira : BaseChampion
{
private const double SpeedBoostScalar = 1.2;
private bool m_SpeedBoost;
[Constructable]
public Neira()
: base(AIType.AI_Mage)
{
Name = "Neira";
Title = "the necromancer";
Body = 401;
Hue = 0x83EC;
SetStr(305, 425);
SetDex(72, 150);
SetInt(505, 750);
SetHits(4800);
SetStam(102, 300);
SetDamage(25, 35);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 25, 30);
SetResistance(ResistanceType.Fire, 35, 45);
SetResistance(ResistanceType.Cold, 50, 60);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 20, 30);
SetSkill(SkillName.EvalInt, 120.0);
SetSkill(SkillName.Magery, 120.0);
SetSkill(SkillName.Meditation, 120.0);
SetSkill(SkillName.MagicResist, 150.0);
SetSkill(SkillName.Tactics, 97.6, 100.0);
SetSkill(SkillName.Wrestling, 97.6, 100.0);
Fame = 22500;
Karma = -22500;
VirtualArmor = 30;
Female = true;
Item shroud = new HoodedShroudOfShadows();
shroud.Movable = false;
AddItem(shroud);
Scimitar weapon = new Scimitar();
weapon.Skill = SkillName.Wrestling;
weapon.Hue = 38;
weapon.Movable = false;
AddItem(weapon);
//new SkeletalMount().Rider = this;
AddItem(new VirtualMountItem(this));
}
public Neira(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Death;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(ShroudOfDeceit) };
}
}
public override Type[] SharedList
{
get
{
return new Type[]
{
typeof(ANecromancerShroud),
typeof(CaptainJohnsHat),
typeof(DetectiveBoots)
};
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(WallBlood), typeof(TatteredAncientMummyWrapping) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { };
}
}
public override bool AlwaysMurderer
{
get
{
return true;
}
}
public override bool BardImmune
{
get
{
return !Core.SE;
}
}
public override bool Unprovokable
{
get
{
return Core.SE;
}
}
public override bool Uncalmable
{
get
{
return Core.SE;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Deadly;
}
}
public override bool ShowFameTitle
{
get
{
return false;
}
}
public override bool ClickTitle
{
get
{
return false;
}
}
public override bool ForceStayHome { get { return true; } }
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
AddLoot(LootPack.Meager);
}
public override bool OnBeforeDeath()
{
IMount mount = Mount;
if (mount != null)
mount.Rider = null;
if (mount is Mobile)
((Mobile)mount).Delete();
return base.OnBeforeDeath();
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
NecromancerSpellbook book = new NecromancerSpellbook();
book.Content = (1ul << book.BookCount) - 1;
c.DropItem(book);
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
CheckSpeedBoost();
base.OnDamage(amount, from, willKill);
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
if (0.1 >= Utility.RandomDouble()) // 10% chance to drop or throw an unholy bone
AddUnholyBone(defender, 0.25);
CheckSpeedBoost();
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
if (0.1 >= Utility.RandomDouble()) // 10% chance to drop or throw an unholy bone
AddUnholyBone(attacker, 0.25);
}
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
{
base.AlterDamageScalarFrom(caster, ref scalar);
if (0.1 >= Utility.RandomDouble()) // 10% chance to throw an unholy bone
AddUnholyBone(caster, 1.0);
}
public void AddUnholyBone(Mobile target, double chanceToThrow)
{
if (Map == null)
return;
if (chanceToThrow >= Utility.RandomDouble())
{
Direction = GetDirectionTo(target);
MovingEffect(target, 0xF7E, 10, 1, true, false, 0x496, 0);
new DelayTimer(this, target).Start();
}
else
{
new UnholyBone().MoveToWorld(Location, Map);
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1); // version
writer.Write(m_SpeedBoost);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch( version )
{
case 1:
{
m_SpeedBoost = reader.ReadBool();
break;
}
}
}
private void CheckSpeedBoost()
{
if (Hits < (HitsMax / 4))
{
if (!m_SpeedBoost)
{
ActiveSpeed /= SpeedBoostScalar;
PassiveSpeed /= SpeedBoostScalar;
m_SpeedBoost = true;
}
}
else if (m_SpeedBoost)
{
ActiveSpeed *= SpeedBoostScalar;
PassiveSpeed *= SpeedBoostScalar;
m_SpeedBoost = false;
}
}
private class VirtualMount : IMount
{
private readonly VirtualMountItem m_Item;
public VirtualMount(VirtualMountItem item)
{
m_Item = item;
}
public Mobile Rider
{
get
{
return m_Item.Rider;
}
set
{
}
}
public virtual void OnRiderDamaged(Mobile from, ref int amount, bool willKill)
{
}
}
private class VirtualMountItem : Item, IMountItem
{
private readonly VirtualMount m_Mount;
private Mobile m_Rider;
public VirtualMountItem(Mobile mob)
: base(0x3EBB)
{
Layer = Layer.Mount;
Movable = false;
m_Rider = mob;
m_Mount = new VirtualMount(this);
}
public VirtualMountItem(Serial serial)
: base(serial)
{
m_Mount = new VirtualMount(this);
}
public Mobile Rider
{
get
{
return m_Rider;
}
}
public IMount Mount
{
get
{
return m_Mount;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
writer.Write((Mobile)m_Rider);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Rider = reader.ReadMobile();
if (m_Rider == null)
Delete();
}
}
private class DelayTimer : Timer
{
private readonly Mobile m_Mobile;
private readonly Mobile m_Target;
public DelayTimer(Mobile m, Mobile target)
: base(TimeSpan.FromSeconds(1.0))
{
m_Mobile = m;
m_Target = target;
}
protected override void OnTick()
{
if (m_Mobile.CanBeHarmful(m_Target))
{
m_Mobile.DoHarmful(m_Target);
AOS.Damage(m_Target, m_Mobile, Utility.RandomMinMax(10, 20), 100, 0, 0, 0, 0);
new UnholyBone().MoveToWorld(m_Target.Location, m_Target.Map);
}
}
}
}
}

View File

@@ -0,0 +1,520 @@
using System;
using System.Collections;
using Server.Engines.CannedEvil;
using Server.Items;
using System.Collections.Generic;
using Server.Network;
using System.Linq;
namespace Server.Mobiles
{
[CorpseName("a Primeval Lich corpse")]
public class PrimevalLich : BaseChampion
{
private DateTime m_NextDiscordTime;
private DateTime m_NextAbilityTime;
private Timer m_Timer;
[Constructable]
public PrimevalLich()
: base(AIType.AI_NecroMage)
{
Name = "Primeval Lich";
Body = 830;
SetStr(500);
SetDex(100);
SetInt(1000);
SetHits(30000);
SetMana(5000);
SetDamage(17, 21);
SetDamageType(ResistanceType.Physical, 20);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Cold, 20);
SetDamageType(ResistanceType.Energy, 20);
SetDamageType(ResistanceType.Poison, 20);
SetResistance(ResistanceType.Physical, 30);
SetResistance(ResistanceType.Fire, 30);
SetResistance(ResistanceType.Cold, 30);
SetResistance(ResistanceType.Poison, 30);
SetResistance(ResistanceType.Energy, 20);
SetSkill(SkillName.EvalInt, 90, 120.0);
SetSkill(SkillName.Magery, 90, 120.0);
SetSkill(SkillName.Meditation, 100, 120.0);
SetSkill(SkillName.Necromancy, 120.0);
SetSkill(SkillName.SpiritSpeak, 120.0);
SetSkill(SkillName.MagicResist, 120, 140.0);
SetSkill(SkillName.Tactics, 90, 120);
SetSkill(SkillName.Wrestling, 100, 120);
Fame = 28000;
Karma = -28000;
VirtualArmor = 80;
m_Timer = new TeleportTimer(this);
m_Timer.Start();
}
public PrimevalLich(Serial serial)
: base(serial)
{
}
public override int GetAttackSound() { return 0x61E; }
public override int GetDeathSound() { return 0x61F; }
public override int GetHurtSound() { return 0x620; }
public override int GetIdleSound() { return 0x621; }
public override bool CanRummageCorpses { get { return true; } }
public override bool BleedImmune { get { return true; } }
public override Poison PoisonImmune { get { return Poison.Lethal; } }
public override bool ShowFameTitle { get { return false; } }
public override bool ClickTitle { get { return false; } }
public override ChampionSkullType SkullType { get { return ChampionSkullType.None; } }
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(BansheesCall), typeof(CastOffZombieSkin), typeof(ChannelersDefender), typeof(LightsRampart) };
}
}
public override Type[] SharedList
{
get
{
return new Type[] { typeof(TokenOfHolyFavor), typeof(TheMostKnowledgePerson), typeof(LieutenantOfTheBritannianRoyalGuard), typeof(ProtectoroftheBattleMage) };
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(MummifiedCorpse) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { };
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 3);
AddLoot(LootPack.Meager);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new PrimalLichDust());
c.DropItem(new RisingColossusScroll());
}
public void ChangeCombatant()
{
ForceReacquire();
BeginFlee(TimeSpan.FromSeconds(2.5));
}
public override void OnThink()
{
if (m_NextDiscordTime <= DateTime.UtcNow)
{
Mobile target = Combatant as Mobile;
if (target != null && target.InRange(this, 8) && CanBeHarmful(target))
Discord(target);
}
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
if (0.05 >= Utility.RandomDouble())
SpawnShadowDwellers(attacker);
}
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
{
if (0.05 >= Utility.RandomDouble())
SpawnShadowDwellers(caster);
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
if (DateTime.UtcNow > m_NextAbilityTime && 0.2 > Utility.RandomDouble())
{
switch (Utility.Random(2))
{
case 0: BlastRadius(); break;
case 1: Lightning(); break;
}
m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(25, 35));
}
}
#region Blast Radius
private static readonly int BlastRange = 16;
private static readonly double[] BlastChance = new double[]
{
0.0, 0.0, 0.05, 0.95, 0.95, 0.95, 0.05, 0.95, 0.95,
0.95, 0.05, 0.95, 0.95, 0.95, 0.05, 0.95, 0.95
};
private void BlastRadius()
{
// TODO: Based on OSI taken videos, not accurate, but an aproximation
Point3D loc = Location;
for (int x = -BlastRange; x <= BlastRange; x++)
{
for (int y = -BlastRange; y <= BlastRange; y++)
{
Point3D p = new Point3D(loc.X + x, loc.Y + y, loc.Z);
int dist = (int)Math.Round(Utility.GetDistanceToSqrt(loc, p));
if (dist <= BlastRange && BlastChance[dist] > Utility.RandomDouble())
{
Timer.DelayCall(TimeSpan.FromSeconds(0.1 * dist), new TimerCallback(
delegate
{
int hue = Utility.RandomList(90, 95);
Effects.SendPacket(loc, Map, new HuedEffect(EffectType.FixedXYZ, Serial.Zero, Serial.Zero, 0x3709, p, p, 20, 30, true, false, hue, 4));
}
));
}
}
}
PlaySound(0x64C);
IPooledEnumerable eable = GetMobilesInRange(BlastRange);
foreach (Mobile m in eable)
{
if (this != m && GetDistanceToSqrt(m) <= BlastRange && CanBeHarmful(m))
{
if (m is ShadowDweller)
continue;
DoHarmful(m);
double damage = m.Hits * 0.6;
if (damage < 100.0)
damage = 100.0;
else if (damage > 200.0)
damage = 200.0;
DoHarmful(m);
AOS.Damage(m, this, (int)damage, 0, 0, 0, 0, 100);
}
}
eable.Free();
}
#endregion
#region Lightning
private void Lightning()
{
int count = 0;
IPooledEnumerable eable = GetMobilesInRange(BlastRange);
foreach (Mobile m in eable)
{
if (m is ShadowDweller)
continue;
if (m.IsPlayer() && GetDistanceToSqrt(m) <= BlastRange && CanBeHarmful(m))
{
DoHarmful(m);
Effects.SendBoltEffect(m, false, 0);
Effects.PlaySound(m, m.Map, 0x51D);
double damage = m.Hits * 0.6;
if (damage < 100.0)
damage = 100.0;
else if (damage > 200.0)
damage = 200.0;
AOS.Damage(m, this, (int)damage, 0, 0, 0, 0, 100);
count++;
if (count >= 6)
break;
}
}
eable.Free();
}
#endregion
#region Teleport
private class TeleportTimer : Timer
{
private Mobile m_Owner;
private static int[] m_Offsets = new int[]
{
-1, -1,
-1, 0,
-1, 1,
0, -1,
0, 1,
1, -1,
1, 0,
1, 1
};
public TeleportTimer(Mobile owner)
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
{
m_Owner = owner;
}
protected override void OnTick()
{
if (m_Owner.Deleted)
{
Stop();
return;
}
Map map = m_Owner.Map;
if (map == null)
return;
if (0.25 < Utility.RandomDouble())
return;
Mobile toTeleport = null;
foreach (Mobile m in m_Owner.GetMobilesInRange(BlastRange))
{
if (m != m_Owner && m.IsPlayer() && m_Owner.CanBeHarmful(m) && m_Owner.CanSee(m))
{
if (m is ShadowDweller)
continue;
toTeleport = m;
break;
}
}
if (toTeleport != null)
{
int offset = Utility.Random(8) * 2;
Point3D to = m_Owner.Location;
for (int i = 0; i < m_Offsets.Length; i += 2)
{
int x = m_Owner.X + m_Offsets[(offset + i) % m_Offsets.Length];
int y = m_Owner.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length];
if (map.CanSpawnMobile(x, y, m_Owner.Z))
{
to = new Point3D(x, y, m_Owner.Z);
break;
}
else
{
int z = map.GetAverageZ(x, y);
if (map.CanSpawnMobile(x, y, z))
{
to = new Point3D(x, y, z);
break;
}
}
}
Mobile m = toTeleport;
Point3D from = m.Location;
m.Location = to;
Server.Spells.SpellHelper.Turn(m_Owner, toTeleport);
Server.Spells.SpellHelper.Turn(toTeleport, m_Owner);
m.ProcessDelta();
Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023);
Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023);
m.PlaySound(0x1FE);
m_Owner.Combatant = toTeleport;
}
}
}
#endregion
#region Unholy Touch
private static Dictionary<Mobile, Timer> m_UnholyTouched = new Dictionary<Mobile, Timer>();
public void Discord(Mobile target)
{
if (Utility.RandomDouble() < 0.9 && !m_UnholyTouched.ContainsKey(target))
{
double scalar = -((20 - (target.Skills[SkillName.MagicResist].Value / 10)) / 100);
ArrayList mods = new ArrayList();
if (target.PhysicalResistance > 0)
{
mods.Add(new ResistanceMod(ResistanceType.Physical, (int)((double)target.PhysicalResistance * scalar)));
}
if (target.FireResistance > 0)
{
mods.Add(new ResistanceMod(ResistanceType.Fire, (int)((double)target.FireResistance * scalar)));
}
if (target.ColdResistance > 0)
{
mods.Add(new ResistanceMod(ResistanceType.Cold, (int)((double)target.ColdResistance * scalar)));
}
if (target.PoisonResistance > 0)
{
mods.Add(new ResistanceMod(ResistanceType.Poison, (int)((double)target.PoisonResistance * scalar)));
}
if (target.EnergyResistance > 0)
{
mods.Add(new ResistanceMod(ResistanceType.Energy, (int)((double)target.EnergyResistance * scalar)));
}
for (int i = 0; i < target.Skills.Length; ++i)
{
if (target.Skills[i].Value > 0)
{
mods.Add(new DefaultSkillMod((SkillName)i, true, target.Skills[i].Value * scalar));
}
}
target.PlaySound(0x458);
ApplyMods(target, mods);
m_UnholyTouched[target] = Timer.DelayCall(TimeSpan.FromSeconds(30), new TimerCallback(
delegate
{
ClearMods(target, mods);
m_UnholyTouched.Remove(target);
}));
}
m_NextDiscordTime = DateTime.UtcNow + TimeSpan.FromSeconds(5 + Utility.RandomDouble() * 22);
}
private static void ApplyMods(Mobile from, ArrayList mods)
{
for (int i = 0; i < mods.Count; ++i)
{
object mod = mods[i];
if (mod is ResistanceMod)
from.AddResistanceMod((ResistanceMod)mod);
else if (mod is StatMod)
from.AddStatMod((StatMod)mod);
else if (mod is SkillMod)
from.AddSkillMod((SkillMod)mod);
}
}
private static void ClearMods(Mobile from, ArrayList mods)
{
for (int i = 0; i < mods.Count; ++i)
{
object mod = mods[i];
if (mod is ResistanceMod)
from.RemoveResistanceMod((ResistanceMod)mod);
else if (mod is StatMod)
from.RemoveStatMod(((StatMod)mod).Name);
else if (mod is SkillMod)
from.RemoveSkillMod((SkillMod)mod);
}
}
#endregion
public void SpawnShadowDwellers(Mobile target)
{
Map map = Map;
if (map == null)
return;
int newShadowDwellers = Utility.RandomMinMax(2, 3);
for (int i = 0; i < newShadowDwellers; ++i)
{
ShadowDweller shadowdweller = new ShadowDweller();
shadowdweller.Team = Team;
shadowdweller.FightMode = FightMode.Closest;
bool validLocation = false;
Point3D loc = Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = X + Utility.Random(3) - 1;
int y = Y + Utility.Random(3) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
loc = new Point3D(x, y, Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
shadowdweller.MoveToWorld(loc, map);
shadowdweller.Combatant = target;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Timer = new TeleportTimer(this);
m_Timer.Start();
}
}
}

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections;
using Server.Engines.CannedEvil;
using Server.Items;
namespace Server.Mobiles
{
public class Rikktor : BaseChampion
{
[Constructable]
public Rikktor()
: base(AIType.AI_Melee)
{
Body = 172;
Name = "Rikktor";
SetStr(701, 900);
SetDex(201, 350);
SetInt(51, 100);
SetHits(15000);
SetStam(203, 650);
SetDamage(28, 55);
SetDamageType(ResistanceType.Physical, 25);
SetDamageType(ResistanceType.Fire, 50);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 80, 90);
SetResistance(ResistanceType.Fire, 80, 90);
SetResistance(ResistanceType.Cold, 30, 40);
SetResistance(ResistanceType.Poison, 80, 90);
SetResistance(ResistanceType.Energy, 80, 90);
SetSkill(SkillName.Anatomy, 100.0);
SetSkill(SkillName.MagicResist, 140.2, 160.0);
SetSkill(SkillName.Tactics, 100.0);
SetSkill(SkillName.Wrestling, 118.4, 123.9);
Fame = 22500;
Karma = -22500;
VirtualArmor = 130;
ForceActiveSpeed = 0.35;
ForcePassiveSpeed = 0.7;
}
public Rikktor(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Power;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(CrownOfTalKeesh) };
}
}
public override Type[] SharedList
{
get
{
return new Type[]
{
typeof(TheMostKnowledgePerson),
typeof(BraveKnightOfTheBritannia),
typeof(LieutenantOfTheBritannianRoyalGuard)
};
}
}
public override Type[] DecorativeList
{
get
{
return new Type[]
{
typeof(LavaTile),
typeof(MonsterStatuette),
typeof(MonsterStatuette)
};
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[]
{
MonsterStatuetteType.OphidianArchMage,
MonsterStatuetteType.OphidianWarrior
};
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override ScaleType ScaleType
{
get
{
return ScaleType.All;
}
}
public override int Scales
{
get
{
return 20;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 4);
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
if (0.2 >= Utility.RandomDouble())
this.Earthquake();
}
public void Earthquake()
{
Map map = this.Map;
if (map == null)
return;
ArrayList targets = new ArrayList();
IPooledEnumerable eable = GetMobilesInRange(8);
foreach (Mobile m in eable)
{
if (m == this || !this.CanBeHarmful(m))
continue;
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team))
targets.Add(m);
else if (m.Player)
targets.Add(m);
}
eable.Free();
this.PlaySound(0x2F3);
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = (Mobile)targets[i];
double damage = m.Hits * 0.6;
if (damage < 10.0)
damage = 10.0;
else if (damage > 75.0)
damage = 75.0;
this.DoHarmful(m);
AOS.Damage(m, this, (int)damage, 100, 0, 0, 0, 0);
if (m.Alive && m.Body.IsHuman && !m.Mounted)
m.Animate(20, 7, 1, true, false, 0); // take hit
}
}
public override int GetAngerSound()
{
return Utility.Random(0x2CE, 2);
}
public override int GetIdleSound()
{
return 0x2D2;
}
public override int GetAttackSound()
{
return Utility.Random(0x2C7, 5);
}
public override int GetHurtSound()
{
return 0x2D1;
}
public override int GetDeathSound()
{
return 0x2CC;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,131 @@
using System;
using System.Collections;
using Server.Engines.CannedEvil;
using Server.Items;
namespace Server.Mobiles
{
public class Semidar : BaseChampion
{
[Constructable]
public Semidar()
: base(AIType.AI_Mage)
{
Name = "Semidar";
Body = 174;
BaseSoundID = 0x4B0;
SetStr(502, 600);
SetDex(102, 200);
SetInt(601, 750);
SetHits(10000);
SetStam(103, 250);
SetDamage(29, 35);
SetDamageType(ResistanceType.Physical, 75);
SetDamageType(ResistanceType.Fire, 25);
SetResistance(ResistanceType.Physical, 75, 90);
SetResistance(ResistanceType.Fire, 65, 75);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 65, 75);
SetResistance(ResistanceType.Energy, 65, 75);
SetSkill(SkillName.EvalInt, 95.1, 100.0);
SetSkill(SkillName.Magery, 90.1, 105.0);
SetSkill(SkillName.Meditation, 95.1, 100.0);
SetSkill(SkillName.MagicResist, 120.2, 140.0);
SetSkill(SkillName.Tactics, 90.1, 105.0);
SetSkill(SkillName.Wrestling, 90.1, 105.0);
Fame = 24000;
Karma = -24000;
VirtualArmor = 20;
SetSpecialAbility(SpecialAbility.LifeDrain);
ForceActiveSpeed = 0.3;
ForcePassiveSpeed = 0.6;
}
public Semidar(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Pain;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(GladiatorsCollar) };
}
}
public override Type[] SharedList
{
get
{
return new Type[] { typeof(RoyalGuardSurvivalKnife), typeof(TheMostKnowledgePerson), typeof(LieutenantOfTheBritannianRoyalGuard) };
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(LavaTile), typeof(DemonSkull) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { };
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 4);
AddLoot(LootPack.FilthyRich);
}
public override void CheckReflect(Mobile caster, ref bool reflect)
{
if (!caster.Female && !caster.IsBodyMod)
reflect = true; // Always reflect if caster isn't female
}
/*public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
{
if (caster.Body.IsMale)
scalar = 20; // Male bodies always reflect.. damage scaled 20x
}*/
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,254 @@
using System;
using System.Collections;
using Server.Engines.CannedEvil;
using Server.Items;
namespace Server.Mobiles
{
public class Serado : BaseChampion
{
[Constructable]
public Serado()
: base(AIType.AI_Melee)
{
Name = "Serado";
Title = "the awakened";
Body = 249;
Hue = 0x96C;
SetStr(1000);
SetDex(150);
SetInt(300);
SetHits(9000);
SetMana(300);
SetDamage(29, 35);
SetDamageType(ResistanceType.Physical, 70);
SetDamageType(ResistanceType.Poison, 20);
SetDamageType(ResistanceType.Energy, 10);
SetResistance(ResistanceType.Physical, 30);
SetResistance(ResistanceType.Fire, 60);
SetResistance(ResistanceType.Cold, 60);
SetResistance(ResistanceType.Poison, 90);
SetResistance(ResistanceType.Energy, 50);
SetSkill(SkillName.MagicResist, 120.0);
SetSkill(SkillName.Tactics, 120.0);
SetSkill(SkillName.Wrestling, 70.0);
SetSkill(SkillName.Poisoning, 150.0);
Fame = 22500;
Karma = -22500;
PackItem(Engines.Plants.Seed.RandomBonsaiSeed());
SetWeaponAbility(WeaponAbility.DoubleStrike);
SetAreaEffect(AreaEffect.PoisonBreath);
}
public Serado(Serial serial)
: base(serial)
{
}
public override ChampionSkullType SkullType
{
get
{
return ChampionSkullType.Power;
}
}
public override Type[] UniqueList
{
get
{
return new Type[] { typeof(Pacify) };
}
}
public override Type[] SharedList
{
get
{
return new Type[]
{
typeof(BraveKnightOfTheBritannia),
typeof(DetectiveBoots),
typeof(EmbroideredOakLeafCloak),
typeof(LieutenantOfTheBritannianRoyalGuard)
};
}
}
public override Type[] DecorativeList
{
get
{
return new Type[] { typeof(Futon), typeof(SwampTile) };
}
}
public override MonsterStatuetteType[] StatueTypes
{
get
{
return new MonsterStatuetteType[] { };
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public override Poison HitPoison
{
get
{
return Poison.Lethal;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Lethal;
}
}
public override double HitPoisonChance
{
get
{
return 0.8;
}
}
public override int Feathers
{
get
{
return 30;
}
}
public override bool ShowFameTitle
{
get
{
return false;
}
}
public override bool ClickTitle
{
get
{
return false;
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.UltraRich, 4);
AddLoot(LootPack.FilthyRich);
AddLoot(LootPack.Gems, 6);
}
// TODO: Hit Lightning Area
public override void OnDamagedBySpell(Mobile attacker)
{
base.OnDamagedBySpell(attacker);
ScaleResistances();
DoCounter(attacker);
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
ScaleResistances();
DoCounter(attacker);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
private void ScaleResistances()
{
double hitsLost = (HitsMax - Hits) / (double)HitsMax;
SetResistance(ResistanceType.Physical, 30 + (int)(hitsLost * (95 - 30)));
SetResistance(ResistanceType.Fire, 60 + (int)(hitsLost * (95 - 60)));
SetResistance(ResistanceType.Cold, 60 + (int)(hitsLost * (95 - 60)));
SetResistance(ResistanceType.Poison, 90 + (int)(hitsLost * (95 - 90)));
SetResistance(ResistanceType.Energy, 50 + (int)(hitsLost * (95 - 50)));
}
private void DoCounter(Mobile attacker)
{
if (Map == null || (attacker is BaseCreature && ((BaseCreature)attacker).BardProvoked))
return;
if (0.2 > Utility.RandomDouble())
{
/* Counterattack with Hit Poison Area
* 20-25 damage, unresistable
* Lethal poison, 100% of the time
* Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0"
* Doesn't work on provoked monsters
*/
Mobile target = null;
if (attacker is BaseCreature)
{
Mobile m = ((BaseCreature)attacker).GetMaster();
if (m != null)
target = m;
}
if (target == null || !target.InRange(this, 25))
target = attacker;
Animate(10, 4, 1, true, false, 0);
ArrayList targets = new ArrayList();
IPooledEnumerable eable = target.GetMobilesInRange(8);
foreach (Mobile m in eable)
{
if (m == this || !CanBeHarmful(m))
continue;
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != Team))
targets.Add(m);
else if (m.Player)
targets.Add(m);
}
eable.Free();
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = (Mobile)targets[i];
DoHarmful(m);
AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0);
m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255);
m.ApplyPoison(this, Poison.Lethal);
}
}
}
}
}

View File

@@ -0,0 +1,60 @@
using System;
namespace Server.Mobiles
{
public class ServantOfSemidar : BaseCreature
{
[Constructable]
public ServantOfSemidar()
: base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4)
{
this.Name = "a servant of Semidar";
this.Body = 0x26;
}
public ServantOfSemidar(Serial serial)
: base(serial)
{
}
public override bool DisallowAllMoves
{
get
{
return true;
}
}
public override bool InitialInnocent
{
get
{
return true;
}
}
public override bool CanBeDamaged()
{
return false;
}
public override void AddNameProperties(ObjectPropertyList list)
{
base.AddNameProperties(list);
list.Add(1005494); // enslaved
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.WriteEncodedInt(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadEncodedInt();
}
}
}

View File

@@ -0,0 +1,217 @@
using System;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a shimmering effusion corpse")]
public class ShimmeringEffusion : BasePeerless
{
[Constructable]
public ShimmeringEffusion()
: base(AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "a shimmering effusion";
Body = 0x105;
SetStr(500, 550);
SetDex(350, 400);
SetInt(1500, 1600);
SetHits(20000);
SetDamage(27, 31);
SetDamageType(ResistanceType.Physical, 20);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Cold, 20);
SetDamageType(ResistanceType.Poison, 20);
SetDamageType(ResistanceType.Energy, 20);
SetResistance(ResistanceType.Physical, 60, 80);
SetResistance(ResistanceType.Fire, 60, 80);
SetResistance(ResistanceType.Cold, 60, 80);
SetResistance(ResistanceType.Poison, 60, 80);
SetResistance(ResistanceType.Energy, 60, 80);
SetSkill(SkillName.Wrestling, 100.0, 105.0);
SetSkill(SkillName.Tactics, 100.0, 105.0);
SetSkill(SkillName.MagicResist, 150);
SetSkill(SkillName.Magery, 150.0);
SetSkill(SkillName.EvalInt, 150.0);
SetSkill(SkillName.Meditation, 120.0);
SetSkill(SkillName.Spellweaving, 120.0);
Fame = 30000;
Karma = -30000;
PackResources(8);
PackTalismans(5);
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
{
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
}
}
public override void GenerateLoot()
{
AddLoot(LootPack.SuperBoss, 8);
AddLoot(LootPack.Parrot, 2);
AddLoot(LootPack.HighScrolls, 3);
AddLoot(LootPack.MedScrolls, 3);
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new CapturedEssence());
c.DropItem(new ShimmeringCrystals());
if (Utility.RandomDouble() < 0.05)
{
switch ( Utility.Random(4) )
{
case 0:
c.DropItem(new ShimmeringEffusionStatuette());
break;
case 1:
c.DropItem(new CorporealBrumeStatuette());
break;
case 2:
c.DropItem(new MantraEffervescenceStatuette());
break;
case 3:
c.DropItem(new FetidEssenceStatuette());
break;
}
}
if (Utility.RandomDouble() < 0.05)
c.DropItem(new FerretImprisonedInCrystal());
if (Utility.RandomDouble() < 0.025)
c.DropItem(new CrystallineRing());
}
public override bool AutoDispel
{
get
{
return true;
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public override bool HasFireRing
{
get
{
return true;
}
}
public override double FireRingChance
{
get
{
return 0.1;
}
}
public override int GetIdleSound()
{
return 0x1BF;
}
public override int GetAttackSound()
{
return 0x1C0;
}
public override int GetHurtSound()
{
return 0x1C1;
}
public override int GetDeathSound()
{
return 0x1C2;
}
#region Helpers
public override bool CanSpawnHelpers
{
get
{
return true;
}
}
public override int MaxHelpersWaves
{
get
{
return 4;
}
}
public override double SpawnHelpersChance
{
get
{
return 0.1;
}
}
public override void SpawnHelpers()
{
int amount = 1;
if (Altar != null)
amount = Altar.Fighters.Count;
if (amount > 5)
amount = 5;
for (int i = 0; i < amount; i ++)
{
switch ( Utility.Random(3) )
{
case 0:
SpawnHelper(new MantraEffervescence(), 2);
break;
case 1:
SpawnHelper(new CorporealBrume(), 2);
break;
case 2:
SpawnHelper(new FetidEssence(), 2);
break;
}
}
}
#endregion
public ShimmeringEffusion(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,165 @@
using System;
namespace Server.Mobiles
{
public class Silvani : BaseCreature
{
[Constructable]
public Silvani()
: base(AIType.AI_Mage, FightMode.Evil, 18, 1, 0.1, 0.2)
{
this.Name = "Silvani";
this.Body = 176;
this.BaseSoundID = 0x467;
this.SetStr(253, 400);
this.SetDex(157, 850);
this.SetInt(503, 800);
this.SetHits(600);
this.SetDamage(27, 38);
this.SetDamageType(ResistanceType.Physical, 75);
this.SetDamageType(ResistanceType.Cold, 25);
this.SetResistance(ResistanceType.Physical, 45, 55);
this.SetResistance(ResistanceType.Fire, 30, 40);
this.SetResistance(ResistanceType.Cold, 30, 40);
this.SetResistance(ResistanceType.Poison, 40, 50);
this.SetResistance(ResistanceType.Energy, 40, 50);
this.SetSkill(SkillName.EvalInt, 100.0);
this.SetSkill(SkillName.Magery, 97.6, 107.5);
this.SetSkill(SkillName.Meditation, 100.0);
this.SetSkill(SkillName.MagicResist, 100.5, 150.0);
this.SetSkill(SkillName.Tactics, 97.6, 100.0);
this.SetSkill(SkillName.Wrestling, 97.6, 100.0);
this.Fame = 20000;
this.Karma = 20000;
this.VirtualArmor = 50;
}
public Silvani(Serial serial)
: base(serial)
{
}
public override TribeType Tribe { get { return TribeType.Fey; } }
public override OppositionGroup OppositionGroup
{
get
{
return OppositionGroup.FeyAndUndead;
}
}
public override bool CanFly
{
get
{
return true;
}
}
public override bool Unprovokable
{
get
{
return true;
}
}
public override Poison PoisonImmune
{
get
{
return Poison.Regular;
}
}
public override int TreasureMapLevel
{
get
{
return 5;
}
}
public override void GenerateLoot()
{
this.AddLoot(LootPack.UltraRich, 2);
}
public void SpawnPixies(Mobile target)
{
Map map = this.Map;
if (map == null)
return;
int newPixies = Utility.RandomMinMax(3, 6);
for (int i = 0; i < newPixies; ++i)
{
Pixie pixie = new Pixie();
pixie.Team = this.Team;
pixie.FightMode = FightMode.Closest;
bool validLocation = false;
Point3D loc = this.Location;
for (int j = 0; !validLocation && j < 10; ++j)
{
int x = this.X + Utility.Random(3) - 1;
int y = this.Y + Utility.Random(3) - 1;
int z = map.GetAverageZ(x, y);
if (validLocation = map.CanFit(x, y, this.Z, 16, false, false))
loc = new Point3D(x, y, this.Z);
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
loc = new Point3D(x, y, z);
}
pixie.MoveToWorld(loc, map);
pixie.Combatant = target;
}
}
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
{
if (0.1 >= Utility.RandomDouble())
this.SpawnPixies(caster);
}
public override void OnGaveMeleeAttack(Mobile defender)
{
base.OnGaveMeleeAttack(defender);
defender.Damage(Utility.Random(20, 10), this);
defender.Stam -= Utility.Random(20, 10);
defender.Mana -= Utility.Random(20, 10);
}
public override void OnGotMeleeAttack(Mobile attacker)
{
base.OnGotMeleeAttack(attacker);
if (0.1 >= Utility.RandomDouble())
this.SpawnPixies(attacker);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,205 @@
using System;
using System.Collections;
using Server.Items;
using Server.Spells;
namespace Server.Mobiles
{
[CorpseName("a slasher of veils corpse")]
public class SlasherOfVeils : BaseSABoss
{
private static readonly int[] m_North = new int[]
{
-1, -1,
1, -1,
-1, 2,
1, 2
};
private static readonly int[] m_East = new int[]
{
-1, 0,
2, 0
};
[Constructable]
public SlasherOfVeils()
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "The Slasher of Veils";
Body = 741;
SetStr(901, 1010);
SetDex(127, 153);
SetInt(1078, 1263);
SetHits(50000, 65000);
SetMana(10000);
SetDamage(10, 15);
SetDamageType(ResistanceType.Physical, 20);
SetDamageType(ResistanceType.Fire, 20);
SetDamageType(ResistanceType.Cold, 20);
SetDamageType(ResistanceType.Poison, 20);
SetDamageType(ResistanceType.Energy, 20);
SetResistance(ResistanceType.Physical, 65, 80);
SetResistance(ResistanceType.Fire, 70, 80);
SetResistance(ResistanceType.Cold, 70, 80);
SetResistance(ResistanceType.Poison, 70, 80);
SetResistance(ResistanceType.Energy, 70, 80);
SetSkill(SkillName.Anatomy, 110.8, 129.7);
SetSkill(SkillName.EvalInt, 113.4, 130);
SetSkill(SkillName.Magery, 111.7, 130);
SetSkill(SkillName.Spellweaving, 111.1, 125);
SetSkill(SkillName.Meditation, 113.5, 129.9);
SetSkill(SkillName.MagicResist, 110, 129.8);
SetSkill(SkillName.Tactics, 110.5, 126.3);
SetSkill(SkillName.Wrestling, 110.1, 130);
SetSkill(SkillName.DetectHidden, 127.1);
Fame = 35000;
Karma = -35000;
SetSpecialAbility(SpecialAbility.AngryFire);
SetSpecialAbility(SpecialAbility.ManaDrain);
SetWeaponAbility(WeaponAbility.ParalyzingBlow);
SetSpecialAbility(SpecialAbility.TrueFear);
}
public SlasherOfVeils(Serial serial)
: base(serial)
{
}
public override Type[] UniqueSAList
{
get
{
return new Type[] { typeof(ClawsOfTheBerserker), typeof(Lavaliere), typeof(Mangler), typeof(HumanSignOfChaos), typeof(GargishSignOfChaos), typeof(StandardOfChaosG), typeof(StandardOfChaos) };
}
}
public override Type[] SharedSAList
{
get
{
return new Type[] { typeof(AxesOfFury), typeof(BladeOfBattle), typeof(DemonBridleRing), typeof(PetrifiedSnake), typeof(PillarOfStrength), typeof(SwordOfShatteredHopes), typeof(SummonersKilt) };
}
}
public override bool Unprovokable
{
get
{
return false;
}
}
public override bool BardImmune
{
get
{
return false;
}
}
public override int GetIdleSound()
{
return 1589;
}
public override int GetAngerSound()
{
return 1586;
}
public override int GetHurtSound()
{
return 1588;
}
public override int GetDeathSound()
{
return 1587;
}
public override bool AlwaysMurderer { get { return true; } }
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 4);
AddLoot(LootPack.Gems, 8);
}
public override void OnThink()
{
base.OnThink();
//if (Combatant == null)
// return;
//if (Hits > 0.6 * HitsMax && Utility.RandomDouble() < 0.05)
// FireRing();
}
public override void FireRing()
{
for (int i = 0; i < m_North.Length; i += 2)
{
Point3D p = Location;
p.X += m_North[i];
p.Y += m_North[i + 1];
IPoint3D po = p as IPoint3D;
SpellHelper.GetSurfaceTop(ref po);
Effects.SendLocationEffect(po, Map, 0x3E27, 50);
}
for (int i = 0; i < m_East.Length; i += 2)
{
Point3D p = Location;
p.X += m_East[i];
p.Y += m_East[i + 1];
IPoint3D po = p as IPoint3D;
SpellHelper.GetSurfaceTop(ref po);
Effects.SendLocationEffect(po, Map, 0x3E31, 50);
}
}
public override void OnDamagedBySpell(Mobile caster)
{
if (0.5 > Utility.RandomDouble() && caster.InRange(Location, 10) && Map != null && caster.Alive && caster != this && caster.Map == Map)
{
MoveToWorld(caster.Location, Map);
Timer.DelayCall(() =>
{
Combatant = caster;
});
Effects.PlaySound(Location, Map, 0x1FE);
}
base.OnDamagedBySpell(caster);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,463 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Network;
using Server.Spells;
namespace Server.Mobiles
{
[CorpseName("a stygian dragon corpse")]
public class StygianDragon : BaseSABoss
{
private DateTime m_Delay;
[Constructable]
public StygianDragon()
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5)
{
Name = "Stygian Dragon";
Body = 826;
BaseSoundID = 362;
SetStr(702);
SetDex(250);
SetInt(180);
SetHits(30000);
SetStam(431);
SetMana(180);
SetDamage(33, 55);
SetDamageType(ResistanceType.Physical, 25);
SetDamageType(ResistanceType.Fire, 50);
SetDamageType(ResistanceType.Energy, 25);
SetResistance(ResistanceType.Physical, 80, 90);
SetResistance(ResistanceType.Fire, 80, 90);
SetResistance(ResistanceType.Cold, 60, 70);
SetResistance(ResistanceType.Poison, 80, 90);
SetResistance(ResistanceType.Energy, 80, 90);
SetSkill(SkillName.Anatomy, 100.0);
SetSkill(SkillName.MagicResist, 150.0, 155.0);
SetSkill(SkillName.Tactics, 120.7, 125.0);
SetSkill(SkillName.Wrestling, 115.0, 117.7);
Fame = 15000;
Karma = -15000;
VirtualArmor = 60;
Tamable = false;
SetWeaponAbility(WeaponAbility.Bladeweave);
SetWeaponAbility(WeaponAbility.TalonStrike);
SetSpecialAbility(SpecialAbility.DragonBreath);
}
public StygianDragon(Serial serial)
: base(serial)
{
}
public override Type[] UniqueSAList
{
get
{
return new Type[]
{
typeof(BurningAmber), typeof(DraconisWrath), typeof(DragonHideShield), typeof(FallenMysticsSpellbook),
typeof(LifeSyphon), typeof(GargishSignOfOrder), typeof(HumanSignOfOrder), typeof(VampiricEssence)
};
}
}
public override Type[] SharedSAList
{
get
{
return new Type[]
{
typeof(AxesOfFury), typeof(SummonersKilt), typeof(GiantSteps),
typeof(TokenOfHolyFavor)
};
}
}
public override bool AlwaysMurderer { get { return true; } }
public override bool Unprovokable { get { return false; } }
public override bool BardImmune { get { return false; } }
public override bool AutoDispel { get { return !Controlled; } }
public override int Meat { get { return 19; } }
public override int Hides { get { return 30; } }
public override HideType HideType { get { return HideType.Barbed; } }
public override int Scales { get { return 7; } }
public override ScaleType ScaleType { get { return (Body == 12 ? ScaleType.Yellow : ScaleType.Red); } }
public override int DragonBlood { get { return 48; } }
public override bool CanFlee { get { return false; } }
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 4);
AddLoot(LootPack.Gems, 8);
}
public override void OnThink()
{
base.OnThink();
if (Combatant == null || !(Combatant is Mobile))
return;
if (DateTime.UtcNow > m_Delay)
{
switch (Utility.Random(3))
{
case 0: CrimsonMeteor(this, (Mobile)Combatant, 70, 125); break;
case 1: DoStygianFireball(); break;
case 2: DoFireColumn(); break;
}
m_Delay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
}
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new StygianDragonHead());
if ( Paragon.ChestChance > Utility.RandomDouble() )
c.DropItem( new ParagonChest( Name, 5 ) );
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)1);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
#region Crimson Meteor
public static void CrimsonMeteor(Mobile owner, Mobile combatant, int minDamage, int maxDamage)
{
if (!combatant.Alive || combatant.Map == null || combatant.Map == Map.Internal)
return;
new CrimsonMeteorTimer(owner, combatant.Location, minDamage, maxDamage).Start();
}
public class CrimsonMeteorTimer : Timer
{
private Mobile m_From;
private Map m_Map;
private int m_Count;
private int m_MaxCount;
private bool m_DoneDamage;
private Point3D m_LastTarget;
private Rectangle2D m_ShowerArea;
private List<Mobile> m_ToDamage;
private int m_MinDamage, m_MaxDamage;
public CrimsonMeteorTimer(Mobile from, Point3D loc, int min, int max)
: base(TimeSpan.FromMilliseconds(250.0), TimeSpan.FromMilliseconds(250.0))
{
m_From = from;
m_Map = from.Map;
m_Count = 0;
m_MaxCount = 25; // in ticks
m_LastTarget = loc;
m_DoneDamage = false;
m_ShowerArea = new Rectangle2D(loc.X - 2, loc.Y - 2, 4, 4);
m_MinDamage = min;
m_MaxDamage = max;
m_ToDamage = new List<Mobile>();
IPooledEnumerable eable = m_Map.GetMobilesInBounds(m_ShowerArea);
foreach (Mobile m in eable)
{
if (m != from && m_From.CanBeHarmful(m))
m_ToDamage.Add(m);
}
eable.Free();
}
protected override void OnTick()
{
if (m_From == null || m_From.Deleted || m_Map == null || m_Map == Map.Internal)
{
Stop();
return;
}
if (0.33 > Utility.RandomDouble())
{
var field = new FireField(m_From, 25, Utility.RandomBool());
field.MoveToWorld(m_LastTarget, m_Map);
}
Point3D start = new Point3D();
Point3D finish = new Point3D();
finish.X = m_ShowerArea.X + Utility.Random(m_ShowerArea.Width);
finish.Y = m_ShowerArea.Y + Utility.Random(m_ShowerArea.Height);
finish.Z = m_From.Z;
SpellHelper.AdjustField(ref finish, m_Map, 16, false);
//objects move from upper right/right to left as per OSI
start.X = finish.X + Utility.RandomMinMax(-4, 4);
start.Y = finish.Y - 15;
start.Z = finish.Z + 50;
Effects.SendMovingParticles(
new Entity(Serial.Zero, start, m_Map),
new Entity(Serial.Zero, finish, m_Map),
0x36D4, 15, 0, false, false, 0, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
Effects.PlaySound(finish, m_Map, 0x11D);
m_LastTarget = finish;
m_Count++;
if (m_Count >= m_MaxCount / 2 && !m_DoneDamage)
{
if (m_ToDamage != null && m_ToDamage.Count > 0)
{
int damage;
foreach (Mobile mob in m_ToDamage)
{
damage = Utility.RandomMinMax(m_MinDamage, m_MaxDamage);
m_From.DoHarmful(mob);
AOS.Damage(mob, m_From, damage, 0, 100, 0, 0, 0);
mob.FixedParticles(0x36BD, 1, 15, 9502, 0, 3, (EffectLayer)255);
}
}
m_DoneDamage = true;
return;
}
if (m_Count >= m_MaxCount)
Stop();
}
}
#endregion
#region Fire Column
public void DoFireColumn()
{
var map = Map;
if (map == null)
return;
Direction columnDir = Utility.GetDirection(this, Combatant);
Packet flash = ScreenLightFlash.Instance;
IPooledEnumerable e = Map.GetClientsInRange(Location, Core.GlobalUpdateRange);
foreach (NetState ns in e)
{
if (ns.Mobile != null)
ns.Mobile.Send(flash);
}
e.Free();
int x = X;
int y = Y;
bool south = columnDir == Direction.East || columnDir == Direction.West;
Movement.Movement.Offset(columnDir, ref x, ref y);
Point3D p = new Point3D(x, y, Z);
SpellHelper.AdjustField(ref p, map, 16, false);
var fire = new FireField(this, Utility.RandomMinMax(25, 32), south);
fire.MoveToWorld(p, map);
for (int i = 0; i < 7; i++)
{
Movement.Movement.Offset(columnDir, ref x, ref y);
p = new Point3D(x, y, Z);
SpellHelper.AdjustField(ref p, map, 16, false);
fire = new FireField(this, Utility.RandomMinMax(25, 32), south);
fire.MoveToWorld(p, map);
}
}
#endregion
#region Fire Field
public class FireField : Item
{
private Mobile m_Owner;
private Timer m_Timer;
private DateTime m_Destroy;
[Constructable]
public FireField(Mobile owner, int duration, bool south)
: base(GetItemID(south))
{
Movable = false;
m_Destroy = DateTime.UtcNow + TimeSpan.FromSeconds(duration);
m_Owner = owner;
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), new TimerCallback(OnTick));
}
private static int GetItemID(bool south)
{
if (south)
return 0x398C;
else
return 0x3996;
}
public override void OnAfterDelete()
{
if (m_Timer != null)
m_Timer.Stop();
}
private void OnTick()
{
if (DateTime.UtcNow > m_Destroy)
{
Delete();
}
else
{
IPooledEnumerable eable = GetMobilesInRange(0);
List<Mobile> list = new List<Mobile>();
foreach (Mobile m in eable)
{
if (m == null)
{
continue;
}
if (m_Owner == null || CanTargetMob(m))
{
list.Add(m);
}
}
eable.Free();
foreach (var mob in list)
{
DealDamage(mob);
}
ColUtility.Free(list);
}
}
public override bool OnMoveOver(Mobile m)
{
DealDamage(m);
return true;
}
public void DealDamage(Mobile m)
{
if (m != m_Owner && (m_Owner == null || CanTargetMob(m)))
AOS.Damage(m, m_Owner, Utility.RandomMinMax(2, 4), 0, 100, 0, 0, 0);
}
public bool CanTargetMob(Mobile m)
{
return m != m_Owner && m_Owner.CanBeHarmful(m, false) && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile));
}
public FireField(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
// Unsaved.
}
public override void Deserialize(GenericReader reader)
{
}
}
#endregion
#region Stygian Fireball
public void DoStygianFireball()
{
if (!(Combatant is Mobile) || !InRange(Combatant.Location, 10))
return;
new StygianFireballTimer(this, (Mobile)Combatant);
PlaySound(0x1F3);
}
private class StygianFireballTimer : Timer
{
private StygianDragon m_Dragon;
private Mobile m_Combatant;
private int m_Ticks;
public StygianFireballTimer(StygianDragon dragon, Mobile combatant)
: base(TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(200))
{
m_Dragon = dragon;
m_Combatant = combatant;
m_Ticks = 0;
Start();
}
protected override void OnTick()
{
m_Dragon.MovingParticles(m_Combatant, 0x46E6, 7, 0, false, true, 1265, 0, 9502, 4019, 0x026, 0);
if (m_Ticks >= 10)
{
int damage = Utility.RandomMinMax(120, 150);
Timer.DelayCall(TimeSpan.FromSeconds(.20), new TimerStateCallback(DoDamage_Callback), new object[] { m_Combatant, m_Dragon, damage });
Stop();
}
m_Ticks++;
}
public void DoDamage_Callback(object state)
{
object[] obj = (object[])state;
Mobile c = (Mobile)obj[0];
Mobile d = (Mobile)obj[1];
int dam = (int)obj[2];
d.DoHarmful(c);
AOS.Damage(c, d, dam, false, 0, 0, 0, 0, 0, 100, 0, false);
}
}
#endregion
}
}

View File

@@ -0,0 +1,440 @@
using System;
using System.Collections.Generic;
using Server.Items;
namespace Server.Mobiles
{
[CorpseName("a travesty's corpse")]
public class Travesty : BasePeerless
{
public override WeaponAbility GetWeaponAbility()
{
if (Weapon == null)
return null;
BaseWeapon weapon = Weapon as BaseWeapon;
return Utility.RandomBool() ? weapon.PrimaryAbility : weapon.SecondaryAbility;
}
private DateTime m_NextBodyChange;
private DateTime m_NextMirrorImage;
private bool m_SpawnedHelpers;
private Timer m_Timer;
private bool _CanDiscord;
private bool _CanPeace;
private bool _CanProvoke;
public override bool CanDiscord { get { return _CanDiscord; } }
public override bool CanPeace { get { return _CanPeace; } }
public override bool CanProvoke { get { return _CanProvoke; } }
[Constructable]
public Travesty()
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Name = "Travesty";
Body = 0x108;
BaseSoundID = 0x46E;
SetStr(900, 950);
SetDex(900, 950);
SetInt(900, 950);
SetHits(35000);
SetDamage(11, 18);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 50, 70);
SetResistance(ResistanceType.Fire, 50, 70);
SetResistance(ResistanceType.Cold, 50, 70);
SetResistance(ResistanceType.Poison, 50, 70);
SetResistance(ResistanceType.Energy, 50, 70);
SetSkill(SkillName.Wrestling, 300.0, 320.0);
SetSkill(SkillName.Tactics, 100.0, 120.0);
SetSkill(SkillName.MagicResist, 100.0, 120.0);
SetSkill(SkillName.Anatomy, 100.0, 120.0);
SetSkill(SkillName.Healing, 100.0, 120.0);
SetSkill(SkillName.Poisoning, 100.0, 120.0);
SetSkill(SkillName.DetectHidden, 100.0);
SetSkill(SkillName.Hiding, 100.0);
SetSkill(SkillName.Parry, 100.0, 110.0);
SetSkill(SkillName.Magery, 100.0, 120.0);
SetSkill(SkillName.EvalInt, 100.0, 120.0);
SetSkill(SkillName.Meditation, 100.0, 120.0);
SetSkill(SkillName.Necromancy, 100.0, 120.0);
SetSkill(SkillName.SpiritSpeak, 100.0, 120.0);
SetSkill(SkillName.Focus, 100.0, 120.0);
SetSkill(SkillName.Spellweaving, 100.0, 120.0);
SetSkill(SkillName.Discordance, 100.0, 120.0);
SetSkill(SkillName.Bushido, 100.0, 120.0);
SetSkill(SkillName.Ninjitsu, 100.0, 120.0);
SetSkill(SkillName.Chivalry, 100.0, 120.0);
SetSkill(SkillName.Musicianship, 100.0, 120.0);
SetSkill(SkillName.Discordance, 100.0, 120.0);
SetSkill(SkillName.Provocation, 100.0, 120.0);
SetSkill(SkillName.Peacemaking, 100.0, 120.0);
Fame = 30000;
Karma = -30000;
VirtualArmor = 50;
PackTalismans(5);
PackResources(8);
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
{
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
}
}
public override bool ShowFameTitle { get { return false; } }
public Travesty(Serial serial)
: base(serial)
{
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.DropItem(new EyeOfTheTravesty());
c.DropItem(new OrdersFromMinax());
switch (Utility.Random(3))
{
case 0:
c.DropItem(new TravestysSushiPreparations());
break;
case 1:
c.DropItem(new TravestysFineTeakwoodTray());
break;
case 2:
c.DropItem(new TravestysCollectionOfShells());
break;
}
if (Utility.RandomDouble() < 0.6)
c.DropItem(new ParrotItem());
if (Utility.RandomDouble() < 0.1)
c.DropItem(new TragicRemainsOfTravesty());
if (Utility.RandomDouble() < 0.05)
c.DropItem(new ImprisonedDog());
if (Utility.RandomDouble() < 0.05)
c.DropItem(new MarkOfTravesty());
if (Utility.RandomDouble() < 0.025)
{
c.DropItem(new MalekisHonor());
}
}
public override void OnDamage(int amount, Mobile from, bool willKill)
{
if (0.1 > Utility.RandomDouble() && m_NextMirrorImage < DateTime.UtcNow)
{
new Server.Spells.Ninjitsu.MirrorImage(this, null).Cast();
m_NextMirrorImage = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(20, 45));
}
if (0.25 > Utility.RandomDouble() && DateTime.UtcNow > m_NextBodyChange)
{
ChangeBody();
}
base.OnDamage(amount, from, willKill);
}
public override void GenerateLoot()
{
AddLoot(LootPack.AosSuperBoss, 8);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
public void ChangeBody()
{
List<Mobile> list = new List<Mobile>();
IPooledEnumerable eable = Map.GetMobilesInRange(Location, 5);
foreach (Mobile m in eable)
{
if (m.Player && m.AccessLevel == AccessLevel.Player && m.Alive)
list.Add(m);
}
eable.Free();
if (list.Count == 0 || IsBodyMod)
{
return;
}
Mobile attacker = list[Utility.Random(list.Count)];
BodyMod = attacker.Body;
HueMod = attacker.Hue;
NameMod = attacker.Name;
Female = attacker.Female;
Title = "(Travesty)";
HairItemID = attacker.HairItemID;
HairHue = attacker.HairHue;
FacialHairItemID = attacker.FacialHairItemID;
FacialHairHue = attacker.FacialHairHue;
foreach (Item item in attacker.Items)
{
if (item.Layer < Layer.Mount &&
item.Layer != Layer.Backpack &&
item.Layer != Layer.Mount &&
item.Layer != Layer.Bank &&
item.Layer != Layer.Hair &&
item.Layer != Layer.Face &&
item.Layer != Layer.FacialHair)
{
if (FindItemOnLayer(item.Layer) == null)
{
if (item is BaseRanged)
{
Item i = FindItemOnLayer(Layer.TwoHanded);
if (i != null)
i.Delete();
i = FindItemOnLayer(Layer.OneHanded);
if (i != null)
i.Delete();
AddItem(Loot.Construct(item.GetType()));
}
else
{
AddItem(new ClonedItem(item));
}
}
}
}
if (attacker.Skills[SkillName.Swords].Value >= 50.0 || attacker.Skills[SkillName.Fencing].Value >= 50.0 || attacker.Skills[SkillName.Macing].Value >= 50.0)
ChangeAIType(AIType.AI_Melee);
if (attacker.Skills[SkillName.Archery].Value >= 50.0)
ChangeAIType(AIType.AI_Archer);
if (attacker.Skills[SkillName.Spellweaving].Value >= 50.0)
ChangeAIType(AIType.AI_Spellweaving);
if (attacker.Skills[SkillName.Mysticism].Value >= 50.0)
ChangeAIType(AIType.AI_Mystic);
if (attacker.Skills[SkillName.Magery].Value >= 50.0)
ChangeAIType(AIType.AI_Mage);
if (attacker.Skills[SkillName.Necromancy].Value >= 50.0)
ChangeAIType(AIType.AI_Necro);
if (attacker.Skills[SkillName.Ninjitsu].Value >= 50.0)
ChangeAIType(AIType.AI_Ninja);
if (attacker.Skills[SkillName.Bushido].Value >= 50.0)
ChangeAIType(AIType.AI_Samurai);
if (attacker.Skills[SkillName.Necromancy].Value >= 50.0 && attacker.Skills[SkillName.Magery].Value >= 50.0)
ChangeAIType(AIType.AI_NecroMage);
PlaySound(0x511);
FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist);
m_NextBodyChange = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
if (attacker.Skills[SkillName.Healing].Base > 20)
{
SetSpecialAbility(SpecialAbility.Heal);
}
if (attacker.Skills[SkillName.Discordance].Base > 50)
{
_CanDiscord = true;
}
if (attacker.Skills[SkillName.Peacemaking].Base > 50)
{
_CanPeace = true;
}
if (attacker.Skills[SkillName.Provocation].Base > 50)
{
_CanProvoke = true;
}
if (m_Timer != null)
m_Timer.Stop();
m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(1.0), new TimerCallback(RestoreBody));
}
public void DeleteItems()
{
ColUtility.SafeDelete(Items, item => item is ClonedItem || item is BaseRanged);
if (Backpack != null)
{
ColUtility.SafeDelete(Backpack.Items, item => item is ClonedItem || item is BaseRanged);
}
}
public virtual void RestoreBody()
{
BodyMod = 0;
HueMod = -1;
NameMod = null;
Female = false;
Title = null;
_CanDiscord = false;
_CanPeace = false;
_CanProvoke = false;
if (HasAbility(SpecialAbility.Heal))
{
RemoveSpecialAbility(SpecialAbility.Heal);
}
DeleteItems();
ChangeAIType(AIType.AI_Mage);
if (m_Timer != null)
{
m_Timer.Stop();
m_Timer = null;
}
}
public override bool OnBeforeDeath()
{
RestoreBody();
return base.OnBeforeDeath();
}
public override void OnAfterDelete()
{
if (m_Timer != null)
m_Timer.Stop();
base.OnAfterDelete();
}
#region Spawn Helpers
public override bool CanSpawnHelpers { get { return true; } }
public override int MaxHelpersWaves { get { return 1; } }
public override bool CanSpawnWave()
{
if (Hits > 2000)
m_SpawnedHelpers = false;
return !m_SpawnedHelpers && Hits < 2000;
}
public override void SpawnHelpers()
{
m_SpawnedHelpers = true;
SpawnNinjaGroup(new Point3D(80, 1964, 0));
SpawnNinjaGroup(new Point3D(80, 1949, 0));
SpawnNinjaGroup(new Point3D(92, 1948, 0));
SpawnNinjaGroup(new Point3D(92, 1962, 0));
if (Map != null && Map != Map.Internal && Region.IsPartOf("TheCitadel"))
{
var loc = _WarpLocs[Utility.Random(_WarpLocs.Length)];
MoveToWorld(loc, Map);
}
}
public void SpawnNinjaGroup(Point3D _location)
{
SpawnHelper(new DragonsFlameMage(), _location);
SpawnHelper(new SerpentsFangAssassin(), _location);
SpawnHelper(new TigersClawThief(), _location);
}
#endregion
private Point3D[] _WarpLocs =
{
new Point3D(71, 1939, 0),
new Point3D(71, 1955, 0),
new Point3D(69, 1972, 0),
new Point3D(86, 1971, 0),
new Point3D(103, 1972, 0),
new Point3D(86, 1939, 0),
new Point3D(102, 1938, 0),
};
private class ClonedItem : Item
{
public ClonedItem(Item oItem)
: base(oItem.ItemID)
{
Name = oItem.Name;
Weight = oItem.Weight;
Hue = oItem.Hue;
Layer = oItem.Layer;
}
public override DeathMoveResult OnParentDeath(Mobile parent)
{
return DeathMoveResult.RemainEquiped;
}
public override DeathMoveResult OnInventoryDeath(Mobile parent)
{
Delete();
return base.OnInventoryDeath(parent);
}
public ClonedItem(Serial serial)
: base(serial)
{
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write((int)0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}
}