Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
426
Scripts/Mobiles/Bosses/AbyssalInfernal.cs
Normal file
426
Scripts/Mobiles/Bosses/AbyssalInfernal.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
360
Scripts/Mobiles/Bosses/Barracoon.cs
Normal file
360
Scripts/Mobiles/Bosses/Barracoon.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
302
Scripts/Mobiles/Bosses/BaseChampion.cs
Normal file
302
Scripts/Mobiles/Bosses/BaseChampion.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
182
Scripts/Mobiles/Bosses/ChiefParoxysmus.cs
Normal file
182
Scripts/Mobiles/Bosses/ChiefParoxysmus.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
364
Scripts/Mobiles/Bosses/CrimsonDragon.cs
Normal file
364
Scripts/Mobiles/Bosses/CrimsonDragon.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
490
Scripts/Mobiles/Bosses/DespiseBosses.cs
Normal file
490
Scripts/Mobiles/Bosses/DespiseBosses.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
299
Scripts/Mobiles/Bosses/DreadHorn.cs
Normal file
299
Scripts/Mobiles/Bosses/DreadHorn.cs
Normal 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); // *Dreadhorns 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
564
Scripts/Mobiles/Bosses/Harrower/Harrower.cs
Normal file
564
Scripts/Mobiles/Bosses/Harrower/Harrower.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Scripts/Mobiles/Bosses/Harrower/HarrowerTentacles.cs
Normal file
261
Scripts/Mobiles/Bosses/Harrower/HarrowerTentacles.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
288
Scripts/Mobiles/Bosses/LadyMelisande.cs
Normal file
288
Scripts/Mobiles/Bosses/LadyMelisande.cs
Normal 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
|
||||
}
|
||||
}
|
||||
332
Scripts/Mobiles/Bosses/LordOaks.cs
Normal file
332
Scripts/Mobiles/Bosses/LordOaks.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
809
Scripts/Mobiles/Bosses/Medusa.cs
Normal file
809
Scripts/Mobiles/Bosses/Medusa.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Scripts/Mobiles/Bosses/Mephitis.cs
Normal file
123
Scripts/Mobiles/Bosses/Mephitis.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
347
Scripts/Mobiles/Bosses/MonstrousInterredGrizzle.cs
Normal file
347
Scripts/Mobiles/Bosses/MonstrousInterredGrizzle.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Scripts/Mobiles/Bosses/Navery/EyeOfNavrey.cs
Normal file
42
Scripts/Mobiles/Bosses/Navery/EyeOfNavrey.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
185
Scripts/Mobiles/Bosses/Navery/Navrey.cs
Normal file
185
Scripts/Mobiles/Bosses/Navery/Navrey.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
387
Scripts/Mobiles/Bosses/Neira.cs
Normal file
387
Scripts/Mobiles/Bosses/Neira.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
520
Scripts/Mobiles/Bosses/PrimevalLich.cs
Normal file
520
Scripts/Mobiles/Bosses/PrimevalLich.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
223
Scripts/Mobiles/Bosses/Rikktor.cs
Normal file
223
Scripts/Mobiles/Bosses/Rikktor.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
131
Scripts/Mobiles/Bosses/Semidar.cs
Normal file
131
Scripts/Mobiles/Bosses/Semidar.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
254
Scripts/Mobiles/Bosses/Serado.cs
Normal file
254
Scripts/Mobiles/Bosses/Serado.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Scripts/Mobiles/Bosses/ServantOfSemidar.cs
Normal file
60
Scripts/Mobiles/Bosses/ServantOfSemidar.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/Mobiles/Bosses/ShimmeringEffusion.cs
Normal file
217
Scripts/Mobiles/Bosses/ShimmeringEffusion.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Scripts/Mobiles/Bosses/Silvani.cs
Normal file
165
Scripts/Mobiles/Bosses/Silvani.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
205
Scripts/Mobiles/Bosses/SlasherOfVeils.cs
Normal file
205
Scripts/Mobiles/Bosses/SlasherOfVeils.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
463
Scripts/Mobiles/Bosses/StygianDragon.cs
Normal file
463
Scripts/Mobiles/Bosses/StygianDragon.cs
Normal 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
|
||||
}
|
||||
}
|
||||
440
Scripts/Mobiles/Bosses/Travesty.cs
Normal file
440
Scripts/Mobiles/Bosses/Travesty.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user