Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user