Fixes code according to modern code style. Fixes a few expression bugs.

This commit is contained in:
Kamron Batman 2018-09-15 09:58:51 -07:00
parent 89eea25e5f
commit 970fd563b2
3324 changed files with 441118 additions and 433755 deletions

View file

@ -1,411 +1,419 @@
using System;
using System.Collections.Generic;
using Server.Mobiles;
using Server.Targeting;
using Server.Items;
using Server.Engines.Quests;
using Server.Engines.Quests.Necro;
using Server.Items;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class AnimateDeadSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Animate Dead", "Uus Corp",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.5 );
public override double RequiredSkill => 40.0;
public override int RequiredMana => 23;
public AnimateDeadSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
Caster.SendLocalizedMessage( 1061083 ); // Animate what corpse?
}
private class CreatureGroup
{
public Type[] m_Types;
public SummonEntry[] m_Entries;
public CreatureGroup( Type[] types, SummonEntry[] entries )
{
m_Types = types;
m_Entries = entries;
}
}
private class SummonEntry
{
public Type[] m_ToSummon;
public int m_Requirement;
public SummonEntry( int requirement, params Type[] toSummon )
{
m_ToSummon = toSummon;
m_Requirement = requirement;
}
}
private static CreatureGroup FindGroup( Type type )
{
for ( int i = 0; i < m_Groups.Length; ++i )
{
CreatureGroup group = m_Groups[i];
Type[] types = group.m_Types;
bool contains = ( types.Length == 0 );
for ( int j = 0; !contains && j < types.Length; ++j )
contains = types[j].IsAssignableFrom( type );
if ( contains )
return group;
}
return null;
}
private static CreatureGroup[] m_Groups = {
// Undead group--empty
new CreatureGroup( SlayerGroup.GetEntryByName( SlayerName.Silver ).Types, new SummonEntry[0] ),
// Insects
new CreatureGroup( new[]
{
typeof( DreadSpider ), typeof( FrostSpider ), typeof( GiantSpider ), typeof( GiantBlackWidow ),
typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ),
typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ),
typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ),
typeof( RedSolenQueen ), typeof( RedSolenWarrior ), typeof( RedSolenWorker ),
typeof( TerathanAvenger ), typeof( TerathanDrone ), typeof( TerathanMatriarch ),
typeof( TerathanWarrior )
// TODO: Giant beetle? Ant lion? Ophidians?
},
new[]
{
new SummonEntry( 0, typeof( MoundOfMaggots ) )
} ),
// Mounts
new CreatureGroup( new[]
{
typeof( Horse ), typeof( Nightmare ), typeof( FireSteed ),
typeof( Kirin ), typeof( Unicorn )
}, new[]
{
new SummonEntry( 10000, typeof( HellSteed ) ),
new SummonEntry( 0, typeof( SkeletalMount ) )
} ),
// Elementals
new CreatureGroup( new[]
{
typeof( BloodElemental ), typeof( EarthElemental ), typeof( SummonedEarthElemental ),
typeof( AgapiteElemental ), typeof( BronzeElemental ), typeof( CopperElemental ),
typeof( DullCopperElemental ), typeof( GoldenElemental ), typeof( ShadowIronElemental ),
typeof( ValoriteElemental ), typeof( VeriteElemental ), typeof( PoisonElemental ),
typeof( FireElemental ), typeof( SummonedFireElemental ), typeof( SnowElemental ),
typeof( AirElemental ), typeof( SummonedAirElemental ), typeof( WaterElemental ),
typeof( SummonedAirElemental ), typeof ( AcidElemental )
}, new[]
{
new SummonEntry( 5000, typeof( WailingBanshee ) ),
new SummonEntry( 0, typeof( Wraith ) )
} ),
// Dragons
new CreatureGroup( new[]
{
typeof( AncientWyrm ), typeof( Dragon ), typeof( GreaterDragon ), typeof( SerpentineDragon ),
typeof( ShadowWyrm ), typeof( SkeletalDragon ), typeof( WhiteWyrm ),
typeof( Drake ), typeof( Wyvern ), typeof( LesserHiryu ), typeof( Hiryu )
}, new[]
{
new SummonEntry( 18000, typeof( SkeletalDragon ) ),
new SummonEntry( 10000, typeof( FleshGolem ) ),
new SummonEntry( 5000, typeof( Lich ) ),
new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ),
new SummonEntry( 2000, typeof( Mummy ) ),
new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ),
new SummonEntry( 0, typeof( PatchworkSkeleton ) )
} ),
// Default group
new CreatureGroup( new Type[0], new[]
{
new SummonEntry( 18000, typeof( LichLord ) ),
new SummonEntry( 10000, typeof( FleshGolem ) ),
new SummonEntry( 5000, typeof( Lich ) ),
new SummonEntry( 3000, typeof( SkeletalKnight ), typeof( BoneKnight ) ),
new SummonEntry( 2000, typeof( Mummy ) ),
new SummonEntry( 1000, typeof( SkeletalMage ), typeof( BoneMagi ) ),
new SummonEntry( 0, typeof( PatchworkSkeleton ) )
} ),
};
public void Target( object obj )
{
MaabusCoffinComponent comp = obj as MaabusCoffinComponent;
MaabusCoffin addon = comp?.Addon as MaabusCoffin;
if ( addon != null )
{
PlayerMobile pm = Caster as PlayerMobile;
QuestSystem qs = pm?.Quest;
if ( qs is DarkTidesQuest )
{
QuestObjective objective = qs.FindObjective( typeof( AnimateMaabusCorpseObjective ) );
if ( objective != null && !objective.Completed )
{
addon.Awake( Caster );
objective.Complete();
}
}
return;
}
Corpse c = obj as Corpse;
if ( c == null )
{
Caster.SendLocalizedMessage( 1061084 ); // You cannot animate that.
}
else
{
Type type = null;
if ( c.Owner != null )
{
type = c.Owner.GetType();
}
if ( c.ItemID != 0x2006 || c.Animated || type == typeof( PlayerMobile ) || type == null || ( c.Owner != null && c.Owner.Fame < 100 ) || ( c.Owner is BaseCreature && ( ( ( BaseCreature )c.Owner ).Summoned || ( ( BaseCreature )c.Owner ).IsBonded ) ) )
{
Caster.SendLocalizedMessage( 1061085 ); // There's not enough life force there to animate.
}
else
{
CreatureGroup group = FindGroup( type );
if ( group != null )
{
if ( group.m_Entries.Length == 0 || type == typeof( DemonKnight ) )
{
Caster.SendLocalizedMessage( 1061086 ); // You cannot animate undead remains.
}
else if ( CheckSequence() )
{
Point3D p = c.GetWorldLocation();
Map map = c.Map;
if ( map != null )
{
Effects.PlaySound( p, map, 0x1FB );
Effects.SendLocationParticles( EffectItem.Create( p, map, EffectItem.DefaultDuration ), 0x3789, 1, 40, 0x3F, 3, 9907, 0 );
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( SummonDelay_Callback ), new object[] { Caster, c, p, map, group } );
}
}
}
}
}
FinishSequence();
}
private static Dictionary<Mobile, List<Mobile>> m_Table = new Dictionary<Mobile, List<Mobile>>();
public static void Unregister( Mobile master, Mobile summoned )
{
if ( master == null )
return;
m_Table.TryGetValue( master, out List<Mobile> list );
if ( list == null )
return;
public class AnimateDeadSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Animate Dead", "Uus Corp",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood
);
private static CreatureGroup[] m_Groups =
{
// Undead group--empty
new CreatureGroup(SlayerGroup.GetEntryByName(SlayerName.Silver).Types, new SummonEntry[0]),
// Insects
new CreatureGroup(new[]
{
typeof(DreadSpider), typeof(FrostSpider), typeof(GiantSpider), typeof(GiantBlackWidow),
typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior),
typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker),
typeof(RedSolenInfiltratorQueen), typeof(RedSolenInfiltratorWarrior),
typeof(RedSolenQueen), typeof(RedSolenWarrior), typeof(RedSolenWorker),
typeof(TerathanAvenger), typeof(TerathanDrone), typeof(TerathanMatriarch),
typeof(TerathanWarrior)
// TODO: Giant beetle? Ant lion? Ophidians?
},
new[]
{
new SummonEntry(0, typeof(MoundOfMaggots))
}),
// Mounts
new CreatureGroup(new[]
{
typeof(Horse), typeof(Nightmare), typeof(FireSteed),
typeof(Kirin), typeof(Unicorn)
}, new[]
{
new SummonEntry(10000, typeof(HellSteed)),
new SummonEntry(0, typeof(SkeletalMount))
}),
// Elementals
new CreatureGroup(new[]
{
typeof(BloodElemental), typeof(EarthElemental), typeof(SummonedEarthElemental),
typeof(AgapiteElemental), typeof(BronzeElemental), typeof(CopperElemental),
typeof(DullCopperElemental), typeof(GoldenElemental), typeof(ShadowIronElemental),
typeof(ValoriteElemental), typeof(VeriteElemental), typeof(PoisonElemental),
typeof(FireElemental), typeof(SummonedFireElemental), typeof(SnowElemental),
typeof(AirElemental), typeof(SummonedAirElemental), typeof(WaterElemental),
typeof(SummonedAirElemental), typeof(AcidElemental)
}, new[]
{
new SummonEntry(5000, typeof(WailingBanshee)),
new SummonEntry(0, typeof(Wraith))
}),
// Dragons
new CreatureGroup(new[]
{
typeof(AncientWyrm), typeof(Dragon), typeof(GreaterDragon), typeof(SerpentineDragon),
typeof(ShadowWyrm), typeof(SkeletalDragon), typeof(WhiteWyrm),
typeof(Drake), typeof(Wyvern), typeof(LesserHiryu), typeof(Hiryu)
}, new[]
{
new SummonEntry(18000, typeof(SkeletalDragon)),
new SummonEntry(10000, typeof(FleshGolem)),
new SummonEntry(5000, typeof(Lich)),
new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)),
new SummonEntry(2000, typeof(Mummy)),
new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)),
new SummonEntry(0, typeof(PatchworkSkeleton))
}),
// Default group
new CreatureGroup(new Type[0], new[]
{
new SummonEntry(18000, typeof(LichLord)),
new SummonEntry(10000, typeof(FleshGolem)),
new SummonEntry(5000, typeof(Lich)),
new SummonEntry(3000, typeof(SkeletalKnight), typeof(BoneKnight)),
new SummonEntry(2000, typeof(Mummy)),
new SummonEntry(1000, typeof(SkeletalMage), typeof(BoneMagi)),
new SummonEntry(0, typeof(PatchworkSkeleton))
})
};
private static Dictionary<Mobile, List<Mobile>> m_Table = new Dictionary<Mobile, List<Mobile>>();
public AnimateDeadSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5);
public override double RequiredSkill => 40.0;
public override int RequiredMana => 23;
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
Caster.SendLocalizedMessage(1061083); // Animate what corpse?
}
private static CreatureGroup FindGroup(Type type)
{
for (int i = 0; i < m_Groups.Length; ++i)
{
CreatureGroup group = m_Groups[i];
Type[] types = group.m_Types;
bool contains = types.Length == 0;
for (int j = 0; !contains && j < types.Length; ++j)
contains = types[j].IsAssignableFrom(type);
if (contains)
return group;
}
return null;
}
public void Target(object obj)
{
MaabusCoffinComponent comp = obj as MaabusCoffinComponent;
MaabusCoffin addon = comp?.Addon as MaabusCoffin;
if (addon != null)
{
PlayerMobile pm = Caster as PlayerMobile;
QuestSystem qs = pm?.Quest;
if (qs is DarkTidesQuest)
{
QuestObjective objective = qs.FindObjective(typeof(AnimateMaabusCorpseObjective));
if (objective != null && !objective.Completed)
{
addon.Awake(Caster);
objective.Complete();
}
}
return;
}
Corpse c = obj as Corpse;
if (c == null)
{
Caster.SendLocalizedMessage(1061084); // You cannot animate that.
}
else
{
Type type = null;
if (c.Owner != null) type = c.Owner.GetType();
if (c.ItemID != 0x2006 || c.Animated || type == typeof(PlayerMobile) || type == null ||
c.Owner != null && c.Owner.Fame < 100 || c.Owner is BaseCreature &&
(((BaseCreature)c.Owner).Summoned || ((BaseCreature)c.Owner).IsBonded))
{
Caster.SendLocalizedMessage(1061085); // There's not enough life force there to animate.
}
else
{
CreatureGroup group = FindGroup(type);
if (group != null)
{
if (group.m_Entries.Length == 0 || type == typeof(DemonKnight))
{
Caster.SendLocalizedMessage(1061086); // You cannot animate undead remains.
}
else if (CheckSequence())
{
Point3D p = c.GetWorldLocation();
Map map = c.Map;
if (map != null)
{
Effects.PlaySound(p, map, 0x1FB);
Effects.SendLocationParticles(EffectItem.Create(p, map, EffectItem.DefaultDuration), 0x3789,
1, 40, 0x3F, 3, 9907, 0);
list.Remove( summoned );
Timer.DelayCall(TimeSpan.FromSeconds(2.0), new TimerStateCallback(SummonDelay_Callback),
new object[] { Caster, c, p, map, group });
}
}
}
}
}
if ( list.Count == 0 )
m_Table.Remove( master );
}
FinishSequence();
}
public static void Register( Mobile master, Mobile summoned )
{
if ( master == null )
return;
public static void Unregister(Mobile master, Mobile summoned)
{
if (master == null)
return;
m_Table.TryGetValue( master, out List<Mobile> list );
m_Table.TryGetValue(master, out List<Mobile> list);
if ( list == null )
m_Table[master] = list = new List<Mobile>();
if (list == null)
return;
for ( int i = list.Count - 1; i >= 0; --i )
{
if ( i >= list.Count )
continue;
list.Remove(summoned);
Mobile mob = list[i];
if (list.Count == 0)
m_Table.Remove(master);
}
if ( mob.Deleted )
list.RemoveAt( i-- );
}
public static void Register(Mobile master, Mobile summoned)
{
if (master == null)
return;
list.Add( summoned );
m_Table.TryGetValue(master, out List<Mobile> list);
if ( list.Count > 3 )
Timer.DelayCall( TimeSpan.Zero, list[0].Kill );
if (list == null)
m_Table[master] = list = new List<Mobile>();
Timer.DelayCall( TimeSpan.FromSeconds( 2.0 ), TimeSpan.FromSeconds( 2.0 ), new TimerStateCallback( Summoned_Damage ), summoned );
}
for (int i = list.Count - 1; i >= 0; --i)
{
if (i >= list.Count)
continue;
private static void Summoned_Damage( object state )
{
Mobile mob = (Mobile)state;
Mobile mob = list[i];
if ( mob.Hits > 0 )
--mob.Hits;
else
mob.Kill();
}
if (mob.Deleted)
list.RemoveAt(i--);
}
private static void SummonDelay_Callback( object state )
{
object[] states = (object[])state;
list.Add(summoned);
Mobile caster = (Mobile)states[0];
Corpse corpse = (Corpse)states[1];
Point3D loc = (Point3D)states[2];
Map map = (Map)states[3];
CreatureGroup group = (CreatureGroup)states[4];
if (list.Count > 3)
Timer.DelayCall(TimeSpan.Zero, list[0].Kill);
if ( corpse.Animated )
return;
Timer.DelayCall(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0), new TimerStateCallback(Summoned_Damage),
summoned);
}
Mobile owner = corpse.Owner;
private static void Summoned_Damage(object state)
{
Mobile mob = (Mobile)state;
if ( owner == null )
return;
if (mob.Hits > 0)
--mob.Hits;
else
mob.Kill();
}
double necromancy = caster.Skills[SkillName.Necromancy].Value;
double spiritSpeak = caster.Skills[SkillName.SpiritSpeak].Value;
private static void SummonDelay_Callback(object state)
{
object[] states = (object[])state;
int casterAbility = 0;
Mobile caster = (Mobile)states[0];
Corpse corpse = (Corpse)states[1];
Point3D loc = (Point3D)states[2];
Map map = (Map)states[3];
CreatureGroup group = (CreatureGroup)states[4];
casterAbility += (int)(necromancy * 30);
casterAbility += (int)(spiritSpeak * 70);
casterAbility /= 10;
casterAbility *= 18;
if (corpse.Animated)
return;
if ( casterAbility > owner.Fame )
casterAbility = owner.Fame;
Mobile owner = corpse.Owner;
if ( casterAbility < 0 )
casterAbility = 0;
if (owner == null)
return;
Type toSummon = null;
SummonEntry[] entries = group.m_Entries;
double necromancy = caster.Skills[SkillName.Necromancy].Value;
double spiritSpeak = caster.Skills[SkillName.SpiritSpeak].Value;
for ( int i = 0; toSummon == null && i < entries.Length; ++i )
{
SummonEntry entry = entries[i];
int casterAbility = 0;
if ( casterAbility < entry.m_Requirement )
continue;
casterAbility += (int)(necromancy * 30);
casterAbility += (int)(spiritSpeak * 70);
casterAbility /= 10;
casterAbility *= 18;
Type[] animates = entry.m_ToSummon;
if (casterAbility > owner.Fame)
casterAbility = owner.Fame;
if ( animates.Length >= 0 )
toSummon = animates[Utility.Random( animates.Length )];
}
if (casterAbility < 0)
casterAbility = 0;
if ( toSummon == null )
return;
Type toSummon = null;
SummonEntry[] entries = group.m_Entries;
Mobile summoned = null;
for (int i = 0; toSummon == null && i < entries.Length; ++i)
{
SummonEntry entry = entries[i];
try{ summoned = Activator.CreateInstance( toSummon ) as Mobile; }
catch{}
if (casterAbility < entry.m_Requirement)
continue;
if ( summoned == null )
return;
Type[] animates = entry.m_ToSummon;
if ( summoned is BaseCreature )
{
BaseCreature bc = (BaseCreature)summoned;
if (animates.Length >= 0)
toSummon = animates[Utility.Random(animates.Length)];
}
// to be sure
bc.Tamable = false;
if (toSummon == null)
return;
if ( bc is BaseMount )
bc.ControlSlots = 1;
else
bc.ControlSlots = 0;
Mobile summoned = null;
Effects.PlaySound( loc, map, bc.GetAngerSound() );
try
{
summoned = Activator.CreateInstance(toSummon) as Mobile;
}
catch
{
}
BaseCreature.Summon( (BaseCreature)summoned, false, caster, loc, 0x28, TimeSpan.FromDays( 1.0 ) );
}
if (summoned == null)
return;
if ( summoned is SkeletalDragon )
Scale( (SkeletalDragon)summoned, 50 ); // lose 50% hp and strength
if (summoned is BaseCreature)
{
BaseCreature bc = (BaseCreature)summoned;
summoned.Fame = 0;
summoned.Karma = -1500;
// to be sure
bc.Tamable = false;
summoned.MoveToWorld( loc, map );
if (bc is BaseMount)
bc.ControlSlots = 1;
else
bc.ControlSlots = 0;
corpse.Hue = 1109;
corpse.Animated = true;
Effects.PlaySound(loc, map, bc.GetAngerSound());
Register( caster, summoned );
}
BaseCreature.Summon((BaseCreature)summoned, false, caster, loc, 0x28, TimeSpan.FromDays(1.0));
}
public static void Scale( BaseCreature bc, int scalar )
{
int toScale;
if (summoned is SkeletalDragon)
Scale((SkeletalDragon)summoned, 50); // lose 50% hp and strength
toScale = bc.RawStr;
bc.RawStr = AOS.Scale( toScale, scalar );
summoned.Fame = 0;
summoned.Karma = -1500;
toScale = bc.HitsMaxSeed;
summoned.MoveToWorld(loc, map);
if ( toScale > 0 )
bc.HitsMaxSeed = AOS.Scale( toScale, scalar );
corpse.Hue = 1109;
corpse.Animated = true;
bc.Hits = bc.Hits; // refresh hits
}
Register(caster, summoned);
}
private class InternalTarget : Target
{
private AnimateDeadSpell m_Owner;
public static void Scale(BaseCreature bc, int scalar)
{
int toScale;
public InternalTarget( AnimateDeadSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.None )
{
m_Owner = owner;
}
toScale = bc.RawStr;
bc.RawStr = AOS.Scale(toScale, scalar);
protected override void OnTarget( Mobile from, object o )
{
m_Owner.Target( o );
}
toScale = bc.HitsMaxSeed;
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
if (toScale > 0)
bc.HitsMaxSeed = AOS.Scale(toScale, scalar);
bc.Hits = bc.Hits; // refresh hits
}
private class CreatureGroup
{
public SummonEntry[] m_Entries;
public Type[] m_Types;
public CreatureGroup(Type[] types, SummonEntry[] entries)
{
m_Types = types;
m_Entries = entries;
}
}
private class SummonEntry
{
public int m_Requirement;
public Type[] m_ToSummon;
public SummonEntry(int requirement, params Type[] toSummon)
{
m_ToSummon = toSummon;
m_Requirement = requirement;
}
}
private class InternalTarget : Target
{
private AnimateDeadSpell m_Owner;
public InternalTarget(AnimateDeadSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.None)
{
m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
m_Owner.Target(o);
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -5,183 +5,184 @@ using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class BloodOathSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Blood Oath", "In Jux Mani Xen",
203,
9031,
Reagent.DaemonBlood
);
public class BloodOathSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Blood Oath", "In Jux Mani Xen",
203,
9031,
Reagent.DaemonBlood
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.5 );
private static Hashtable m_OathTable = new Hashtable();
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 20.0;
public override int RequiredMana => 13;
public BloodOathSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public BloodOathSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5);
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override double RequiredSkill => 20.0;
public override int RequiredMana => 13;
public void Target( Mobile m )
{
if ( Caster == m || !(m is PlayerMobile || m is BaseCreature) ) // only PlayerMobile and BaseCreature implement blood oath checking
{
Caster.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
else if ( m_OathTable.Contains( Caster ) )
{
Caster.SendLocalizedMessage( 1061607 ); // You are already bonded in a Blood Oath.
}
else if ( m_OathTable.Contains( m ) )
{
if ( m.Player )
Caster.SendLocalizedMessage( 1061608 ); // That player is already bonded in a Blood Oath.
else
Caster.SendLocalizedMessage( 1061609 ); // That creature is already bonded in a Blood Oath.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
/* Temporarily creates a dark pact between the caster and the target.
* Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds.
*
* NOTE: The above algorithm must be fixed point, it should be:
* ((ss-rm)/8)+8
*/
public void Target(Mobile m)
{
if (Caster == m || !(m is PlayerMobile || m is BaseCreature)
) // only PlayerMobile and BaseCreature implement blood oath checking
{
Caster.SendLocalizedMessage(1060508); // You can't curse that.
}
else if (m_OathTable.Contains(Caster))
{
Caster.SendLocalizedMessage(1061607); // You are already bonded in a Blood Oath.
}
else if (m_OathTable.Contains(m))
{
if (m.Player)
Caster.SendLocalizedMessage(1061608); // That player is already bonded in a Blood Oath.
else
Caster.SendLocalizedMessage(1061609); // That creature is already bonded in a Blood Oath.
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
ExpireTimer timer = (ExpireTimer)m_Table[m];
timer?.DoExpire();
/* Temporarily creates a dark pact between the caster and the target.
* Any damage dealt by the target to the caster is increased, but the target receives the same amount of damage.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 80 ) + 8 seconds.
*
* NOTE: The above algorithm must be fixed point, it should be:
* ((ss-rm)/8)+8
*/
m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster;
ExpireTimer timer = (ExpireTimer)m_Table[m];
timer?.DoExpire();
m.Spell?.OnCasterHurt();
m_OathTable[Caster] = Caster;
m_OathTable[m] = Caster;
Caster.PlaySound( 0x175 );
m.Spell?.OnCasterHurt();
Caster.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist );
Caster.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 );
Caster.PlaySound(0x175);
m.FixedParticles( 0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist );
m.FixedParticles( 0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255 );
Caster.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist);
Caster.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255);
TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 8) + 8 );
m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain
m.FixedParticles(0x375A, 1, 17, 9919, 33, 7, EffectLayer.Waist);
m.FixedParticles(0x3728, 1, 13, 9502, 33, 7, (EffectLayer)255);
timer = new ExpireTimer ( Caster, m, duration );
timer.Start ();
TimeSpan duration = TimeSpan.FromSeconds((GetDamageSkill(Caster) - GetResistSkill(m)) / 8 + 8);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
BuffInfo.AddBuff ( Caster, new BuffInfo ( BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name.ToString () ) );
BuffInfo.AddBuff ( m, new BuffInfo ( BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name.ToString () ) );
timer = new ExpireTimer(Caster, m, duration);
timer.Start();
m_Table[m] = timer;
HarmfulSpell( m );
}
BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.BloodOathCaster, 1075659, duration, Caster, m.Name));
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.BloodOathCurse, 1075661, duration, m, Caster.Name));
FinishSequence();
}
m_Table[m] = timer;
HarmfulSpell(m);
}
public static bool RemoveCurse( Mobile m )
{
ExpireTimer t = (ExpireTimer)m_Table[m];
FinishSequence();
}
if ( t == null )
return false;
public static bool RemoveCurse(Mobile m)
{
ExpireTimer t = (ExpireTimer)m_Table[m];
t.DoExpire();
return true;
}
if (t == null)
return false;
private static Hashtable m_OathTable = new Hashtable();
private static Hashtable m_Table = new Hashtable ();
t.DoExpire();
return true;
}
public static Mobile GetBloodOath( Mobile m )
{
if ( m == null )
return null;
public static Mobile GetBloodOath(Mobile m)
{
if (m == null)
return null;
Mobile oath = (Mobile)m_OathTable[m];
Mobile oath = (Mobile)m_OathTable[m];
if ( oath == m )
oath = null;
if (oath == m)
oath = null;
return oath;
}
return oath;
}
private class ExpireTimer : Timer
{
private Mobile m_Caster;
private Mobile m_Target;
private DateTime m_End;
private class ExpireTimer : Timer
{
private Mobile m_Caster;
private DateTime m_End;
private Mobile m_Target;
public ExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.UtcNow + delay;
public ExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0),
TimeSpan.FromSeconds(1.0))
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.UtcNow + delay;
Priority = TimerPriority.TwoFiftyMS;
}
Priority = TimerPriority.TwoFiftyMS;
}
protected override void OnTick()
{
if ( m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive || DateTime.UtcNow >= m_End )
{
DoExpire ();
}
}
public void DoExpire()
{
if ( m_OathTable.Contains( m_Caster ) )
{
m_Caster.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken.
m_OathTable.Remove ( m_Caster );
}
protected override void OnTick()
{
if (m_Caster.Deleted || m_Target.Deleted || !m_Caster.Alive || !m_Target.Alive ||
DateTime.UtcNow >= m_End) DoExpire();
}
if ( m_OathTable.Contains( m_Target ) )
{
m_Target.SendLocalizedMessage( 1061620 ); // Your Blood Oath has been broken.
m_OathTable.Remove ( m_Target );
}
public void DoExpire()
{
if (m_OathTable.Contains(m_Caster))
{
m_Caster.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Caster);
}
Stop ();
if (m_OathTable.Contains(m_Target))
{
m_Target.SendLocalizedMessage(1061620); // Your Blood Oath has been broken.
m_OathTable.Remove(m_Target);
}
BuffInfo.RemoveBuff ( m_Caster, BuffIcon.BloodOathCaster );
BuffInfo.RemoveBuff ( m_Target, BuffIcon.BloodOathCurse );
Stop();
m_Table.Remove ( m_Caster );
}
}
BuffInfo.RemoveBuff(m_Caster, BuffIcon.BloodOathCaster);
BuffInfo.RemoveBuff(m_Target, BuffIcon.BloodOathCurse);
private class InternalTarget : Target
{
private BloodOathSpell m_Owner;
m_Table.Remove(m_Caster);
}
}
public InternalTarget( BloodOathSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
private class InternalTarget : Target
{
private BloodOathSpell m_Owner;
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
else
from.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
public InternalTarget(BloodOathSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
else
from.SendLocalizedMessage(1060508); // You can't curse that.
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -4,151 +4,151 @@ using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class CorpseSkinSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Corpse Skin", "In Agle Corp Ylem",
203,
9051,
Reagent.BatWing,
Reagent.GraveDust
);
public class CorpseSkinSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Corpse Skin", "In Agle Corp Ylem",
203,
9051,
Reagent.BatWing,
Reagent.GraveDust
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.5 );
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 20.0;
public override int RequiredMana => 11;
public CorpseSkinSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public CorpseSkinSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5);
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override double RequiredSkill => 20.0;
public override int RequiredMana => 11;
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
/* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh,
* making them more vulnerable to Fire and Poison damage,
* but increasing their resistance to Physical and Cold damage.
*
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds.
*
* NOTE: Algorithm above is fixed point, should be:
* ((ss-mr)/2.5) + 40
*
* NOTE: Resistance is not checked if targeting yourself
*/
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
ExpireTimer timer = (ExpireTimer)m_Table[m];
/* Transmogrifies the flesh of the target creature or player to resemble rotted corpse flesh,
* making them more vulnerable to Fire and Poison damage,
* but increasing their resistance to Physical and Cold damage.
*
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 25 ) + 40 seconds.
*
* NOTE: Algorithm above is fixed point, should be:
* ((ss-mr)/2.5) + 40
*
* NOTE: Resistance is not checked if targeting yourself
*/
if ( timer != null )
timer.DoExpire();
else
m.SendLocalizedMessage( 1061689 ); // Your skin turns dry and corpselike.
ExpireTimer timer = (ExpireTimer)m_Table[m];
m.Spell?.OnCasterHurt();
if (timer != null)
timer.DoExpire();
else
m.SendLocalizedMessage(1061689); // Your skin turns dry and corpselike.
m.FixedParticles( 0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head );
m.PlaySound( 0x1BB );
m.Spell?.OnCasterHurt();
double ss = GetDamageSkill( Caster );
double mr = ( Caster == m ? 0.0 : GetResistSkill( m ) );
m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain
m.FixedParticles(0x373A, 1, 15, 9913, 67, 7, EffectLayer.Head);
m.PlaySound(0x1BB);
TimeSpan duration = TimeSpan.FromSeconds( ((ss - mr) / 2.5) + 40.0 );
double ss = GetDamageSkill(Caster);
double mr = Caster == m ? 0.0 : GetResistSkill(m);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
ResistanceMod[] mods = new ResistanceMod[4]
{
new ResistanceMod( ResistanceType.Fire, -15 ),
new ResistanceMod( ResistanceType.Poison, -15 ),
new ResistanceMod( ResistanceType.Cold, +10 ),
new ResistanceMod( ResistanceType.Physical, +10 )
};
TimeSpan duration = TimeSpan.FromSeconds((ss - mr) / 2.5 + 40.0);
timer = new ExpireTimer( m, mods, duration );
timer.Start();
ResistanceMod[] mods = new ResistanceMod[4]
{
new ResistanceMod(ResistanceType.Fire, -15),
new ResistanceMod(ResistanceType.Poison, -15),
new ResistanceMod(ResistanceType.Cold, +10),
new ResistanceMod(ResistanceType.Physical, +10)
};
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.CorpseSkin, 1075663, duration, m ) );
timer = new ExpireTimer(m, mods, duration);
timer.Start();
m_Table[m] = timer;
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.CorpseSkin, 1075663, duration, m));
for ( int i = 0; i < mods.Length; ++i )
m.AddResistanceMod( mods[i] );
m_Table[m] = timer;
HarmfulSpell( m );
}
for (int i = 0; i < mods.Length; ++i)
m.AddResistanceMod(mods[i]);
FinishSequence();
}
HarmfulSpell(m);
}
private static Hashtable m_Table = new Hashtable();
FinishSequence();
}
public static bool RemoveCurse( Mobile m )
{
ExpireTimer t = (ExpireTimer)m_Table[m];
public static bool RemoveCurse(Mobile m)
{
ExpireTimer t = (ExpireTimer)m_Table[m];
if ( t == null )
return false;
if (t == null)
return false;
m.SendLocalizedMessage( 1061688 ); // Your skin returns to normal.
t.DoExpire();
return true;
}
m.SendLocalizedMessage(1061688); // Your skin returns to normal.
t.DoExpire();
return true;
}
private class ExpireTimer : Timer
{
private Mobile m_Mobile;
private ResistanceMod[] m_Mods;
private class ExpireTimer : Timer
{
private Mobile m_Mobile;
private ResistanceMod[] m_Mods;
public ExpireTimer( Mobile m, ResistanceMod[] mods, TimeSpan delay ) : base( delay )
{
m_Mobile = m;
m_Mods = mods;
}
public ExpireTimer(Mobile m, ResistanceMod[] mods, TimeSpan delay) : base(delay)
{
m_Mobile = m;
m_Mods = mods;
}
public void DoExpire()
{
for ( int i = 0; i < m_Mods.Length; ++i )
m_Mobile.RemoveResistanceMod( m_Mods[i] );
public void DoExpire()
{
for (int i = 0; i < m_Mods.Length; ++i)
m_Mobile.RemoveResistanceMod(m_Mods[i]);
Stop();
BuffInfo.RemoveBuff( m_Mobile, BuffIcon.CorpseSkin );
m_Table.Remove( m_Mobile );
}
Stop();
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.CorpseSkin);
m_Table.Remove(m_Mobile);
}
protected override void OnTick()
{
m_Mobile.SendLocalizedMessage( 1061688 ); // Your skin returns to normal.
DoExpire();
}
}
protected override void OnTick()
{
m_Mobile.SendLocalizedMessage(1061688); // Your skin returns to normal.
DoExpire();
}
}
private class InternalTarget : Target
{
private CorpseSkinSpell m_Owner;
private class InternalTarget : Target
{
private CorpseSkinSpell m_Owner;
public InternalTarget( CorpseSkinSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
public InternalTarget(CorpseSkinSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -4,100 +4,100 @@ using Server.Items;
namespace Server.Spells.Necromancy
{
public class CurseWeaponSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Curse Weapon", "An Sanct Gra Char",
203,
9031,
Reagent.PigIron
);
public class CurseWeaponSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Curse Weapon", "An Sanct Gra Char",
203,
9031,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 0.75 );
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 0.0;
public override int RequiredMana => 7;
public CurseWeaponSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public CurseWeaponSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75);
public override void OnCast()
{
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
public override double RequiredSkill => 0.0;
public override int RequiredMana => 7;
if ( weapon == null || weapon is Fists )
{
Caster.SendLocalizedMessage( 501078 ); // You must be holding a weapon.
}
else if ( CheckSequence() )
{
/* Temporarily imbues a weapon with a life draining effect.
* Half the damage that the weapon inflicts is added to the necromancer's health.
* The effects lasts for (Spirit Speak skill level / 34) + 1 seconds.
*
* NOTE: Above algorithm is fixed point, should be :
* (Spirit Speak skill level / 3.4) + 1
*
* TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect?
*/
public override void OnCast()
{
BaseWeapon weapon = Caster.Weapon as BaseWeapon;
Caster.PlaySound( 0x387 );
Caster.FixedParticles( 0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head );
Caster.FixedParticles( 0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255 );
new SoundEffectTimer( Caster ).Start();
if (weapon == null || weapon is Fists)
{
Caster.SendLocalizedMessage(501078); // You must be holding a weapon.
}
else if (CheckSequence())
{
/* Temporarily imbues a weapon with a life draining effect.
* Half the damage that the weapon inflicts is added to the necromancer's health.
* The effects lasts for (Spirit Speak skill level / 34) + 1 seconds.
*
* NOTE: Above algorithm is fixed point, should be :
* (Spirit Speak skill level / 3.4) + 1
*
* TODO: What happens if you curse a weapon then give it to someone else? Should they get the drain effect?
*/
TimeSpan duration = TimeSpan.FromSeconds( (Caster.Skills[SkillName.SpiritSpeak].Value / 3.4) + 1.0 );
Caster.PlaySound(0x387);
Caster.FixedParticles(0x3779, 1, 15, 9905, 32, 2, EffectLayer.Head);
Caster.FixedParticles(0x37B9, 1, 14, 9502, 32, 5, (EffectLayer)255);
new SoundEffectTimer(Caster).Start();
TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills[SkillName.SpiritSpeak].Value / 3.4 + 1.0);
Timer t = (Timer)m_Table[weapon];
Timer t = (Timer)m_Table[weapon];
t?.Stop();
t?.Stop();
weapon.Cursed = true;
weapon.Cursed = true;
m_Table[weapon] = t = new ExpireTimer( weapon, duration );
m_Table[weapon] = t = new ExpireTimer(weapon, duration);
t.Start();
}
t.Start();
}
FinishSequence();
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private class ExpireTimer : Timer
{
private BaseWeapon m_Weapon;
private class ExpireTimer : Timer
{
private BaseWeapon m_Weapon;
public ExpireTimer(BaseWeapon weapon, TimeSpan delay) : base(delay)
{
m_Weapon = weapon;
Priority = TimerPriority.OneSecond;
}
public ExpireTimer( BaseWeapon weapon, TimeSpan delay ) : base( delay )
{
m_Weapon = weapon;
Priority = TimerPriority.OneSecond;
}
protected override void OnTick()
{
m_Weapon.Cursed = false;
Effects.PlaySound(m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA);
m_Table.Remove(this);
}
}
protected override void OnTick()
{
m_Weapon.Cursed = false;
Effects.PlaySound( m_Weapon.GetWorldLocation(), m_Weapon.Map, 0xFA );
m_Table.Remove( this );
}
}
private class SoundEffectTimer : Timer
{
private Mobile m_Mobile;
private class SoundEffectTimer : Timer
{
private Mobile m_Mobile;
public SoundEffectTimer(Mobile m) : base(TimeSpan.FromSeconds(0.75))
{
m_Mobile = m;
Priority = TimerPriority.FiftyMS;
}
public SoundEffectTimer( Mobile m ) : base( TimeSpan.FromSeconds( 0.75 ) )
{
m_Mobile = m;
Priority = TimerPriority.FiftyMS;
}
protected override void OnTick()
{
m_Mobile.PlaySound( 0xFA );
}
}
}
}
protected override void OnTick()
{
m_Mobile.PlaySound(0xFA);
}
}
}
}

View file

@ -5,128 +5,127 @@ using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class EvilOmenSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Evil Omen", "Pas Tym An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal
);
public class EvilOmenSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Evil Omen", "Pas Tym An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75);
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 20.0;
public override int RequiredMana => 11;
public EvilOmenSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public EvilOmenSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(0.75);
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public override double RequiredSkill => 20.0;
public override int RequiredMana => 11;
public void Target(Mobile m)
{
if (!(m is BaseCreature || m is PlayerMobile))
{
Caster.SendLocalizedMessage(1060508); // You can't curse that.
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
/* Curses the target so that the next harmful event that affects them is magnified.
* Damage to the target's hit points is increased 25%,
* the poison level of the attack will be 1 higher
* and the Resist Magic skill of the target will be fixed on 50.
*
* The effect lasts for one harmful event only.
*/
public void Target(Mobile m)
{
if (!(m is BaseCreature || m is PlayerMobile))
{
Caster.SendLocalizedMessage(1060508); // You can't curse that.
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
m.Spell?.OnCasterHurt();
/* Curses the target so that the next harmful event that affects them is magnified.
* Damage to the target's hit points is increased 25%,
* the poison level of the attack will be 1 higher
* and the Resist Magic skill of the target will be fixed on 50.
*
* The effect lasts for one harmful event only.
*/
m.PlaySound(0xFC);
m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head);
m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head);
m.Spell?.OnCasterHurt();
if (!m_Table.Contains(m))
{
SkillMod mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0);
m.PlaySound(0xFC);
m.FixedParticles(0x3728, 1, 13, 9912, 1150, 7, EffectLayer.Head);
m.FixedParticles(0x3779, 1, 15, 9502, 67, 7, EffectLayer.Head);
if (m.Skills[SkillName.MagicResist].Base > 50.0)
m.AddSkillMod(mod);
if (!m_Table.Contains(m))
{
SkillMod mod = new DefaultSkillMod(SkillName.MagicResist, false, 50.0);
m_Table[m] = mod;
}
if (m.Skills[SkillName.MagicResist].Base > 50.0)
m.AddSkillMod(mod);
TimeSpan duration = TimeSpan.FromSeconds((Caster.Skills[SkillName.SpiritSpeak].Value / 12) + 1.0);
m_Table[m] = mod;
}
Timer.DelayCall(duration, new TimerStateCallback(EffectExpire_Callback), m);
TimeSpan duration = TimeSpan.FromSeconds(Caster.Skills[SkillName.SpiritSpeak].Value / 12 + 1.0);
HarmfulSpell( m );
Timer.DelayCall(duration, new TimerStateCallback(EffectExpire_Callback), m);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m));
HarmfulSpell(m);
}
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.EvilOmen, 1075647, 1075648, duration, m));
}
FinishSequence();
}
FinishSequence();
}
private static Hashtable m_Table = new Hashtable();
private static void EffectExpire_Callback(object state)
{
TryEndEffect((Mobile)state);
}
private static void EffectExpire_Callback(object state)
{
TryEndEffect((Mobile)state);
}
/*
* The naming here was confusing. Its a 1-off effect spell.
* So, we dont actually "checkeffect"; we endeffect with bool
* return to determine external behaviors.
*
* -refactored.
*/
/*
* The naming here was confusing. Its a 1-off effect spell.
* So, we dont actually "checkeffect"; we endeffect with bool
* return to determine external behaviors.
*
* -refactored.
*/
public static bool TryEndEffect(Mobile m)
{
SkillMod mod = (SkillMod)m_Table[m];
public static bool TryEndEffect(Mobile m)
{
SkillMod mod = (SkillMod)m_Table[m];
if (mod == null)
return false;
if (mod == null)
return false;
m_Table.Remove(m);
mod.Remove();
m_Table.Remove(m);
mod.Remove();
return true;
}
return true;
}
private class InternalTarget : Target
{
private EvilOmenSpell m_Owner;
private class InternalTarget : Target
{
private EvilOmenSpell m_Owner;
public InternalTarget(EvilOmenSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
public InternalTarget(EvilOmenSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
else
from.SendLocalizedMessage(1060508); // You can't curse that.
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
else
from.SendLocalizedMessage(1060508); // You can't curse that.
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -1,196 +1,202 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Engines.CannedEvil;
using Server.Guilds;
using Server.Factions;
using Server.Engines.PartySystem;
using Server.Factions;
using Server.Guilds;
using Server.Items;
using Server.Regions;
namespace Server.Spells.Necromancy
{
public class ExorcismSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Exorcism", "Ort Corp Grav",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust
);
public class ExorcismSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Exorcism", "Ort Corp Grav",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
private static readonly int Range = Core.ML ? 48 : 18;
public override double RequiredSkill => 80.0;
public override int RequiredMana => 40;
private static readonly Point3D[] m_BritanniaLocs =
{
new Point3D(1470, 843, 0),
new Point3D(1857, 865, -1),
new Point3D(4220, 563, 36),
new Point3D(1732, 3528, 0),
new Point3D(1300, 644, 8),
new Point3D(3355, 302, 9),
new Point3D(1606, 2490, 5),
new Point3D(2500, 3931, 3),
new Point3D(4264, 3707, 0)
};
public ExorcismSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
private static readonly Point3D[] m_IllshLocs =
{
new Point3D(1222, 474, -17),
new Point3D(718, 1360, -60),
new Point3D(297, 1014, -19),
new Point3D(986, 1006, -36),
new Point3D(1180, 1288, -30),
new Point3D(1538, 1341, -3),
new Point3D(528, 223, -38)
};
public override bool CheckCast()
{
if ( Caster.Skills.SpiritSpeak.Value < 100.0 )
{
Caster.SendLocalizedMessage( 1072112 ); // You must have GM Spirit Speak to use this spell
return false;
}
private static readonly Point3D[] m_MalasLocs =
{
new Point3D(976, 517, -30)
};
return base.CheckCast();
}
private static readonly Point3D[] m_TokunoLocs =
{
new Point3D(710, 1162, 25),
new Point3D(1034, 515, 18),
new Point3D(295, 712, 55)
};
public ExorcismSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override double RequiredSkill => 80.0;
public override int RequiredMana => 40;
public override bool DelayedDamage => false;
public override bool DelayedDamage => false;
private static readonly int Range = (Core.ML ? 48 : 18);
public override bool CheckCast()
{
if (Caster.Skills.SpiritSpeak.Value < 100.0)
{
Caster.SendLocalizedMessage(1072112); // You must have GM Spirit Speak to use this spell
return false;
}
public override int ComputeKarmaAward()
{
return 0; //no karma lost from this spell!
}
return base.CheckCast();
}
public override void OnCast()
{
ChampionSpawnRegion r = Caster.Region.GetRegion( typeof( ChampionSpawnRegion ) ) as ChampionSpawnRegion;
public override int ComputeKarmaAward()
{
return 0; //no karma lost from this spell!
}
if ( r == null || !Caster.InRange( r.ChampionSpawn, Range ) )
{
Caster.SendLocalizedMessage( 1072111 ); // You are not in a valid exorcism region.
}
else if ( CheckSequence() )
{
Map map = Caster.Map;
public override void OnCast()
{
ChampionSpawnRegion r = Caster.Region.GetRegion(typeof(ChampionSpawnRegion)) as ChampionSpawnRegion;
if ( map != null )
{
List<Mobile> targets = new List<Mobile>();
if (r == null || !Caster.InRange(r.ChampionSpawn, Range))
{
Caster.SendLocalizedMessage(1072111); // You are not in a valid exorcism region.
}
else if (CheckSequence())
{
Map map = Caster.Map;
foreach( Mobile m in r.ChampionSpawn.GetMobilesInRange( Range ) )
if ( IsValidTarget( m ) )
targets.Add( m );
if (map != null)
{
List<Mobile> targets = new List<Mobile>();
for( int i = 0; i < targets.Count; ++i )
{
Mobile m = targets[i];
foreach (Mobile m in r.ChampionSpawn.GetMobilesInRange(Range))
if (IsValidTarget(m))
targets.Add(m);
//Suprisingly, no sparkle type effects
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = targets[i];
m.Location = GetNearestShrine( m );
}
}
}
//Suprisingly, no sparkle type effects
FinishSequence();
}
m.Location = GetNearestShrine(m);
}
}
}
private bool IsValidTarget( Mobile m )
{
if ( !m.Player || m.Alive )
return false;
FinishSequence();
}
Corpse c = m.Corpse as Corpse;
Map map = m.Map;
private bool IsValidTarget(Mobile m)
{
if (!m.Player || m.Alive)
return false;
if ( c != null && !c.Deleted && map != null && c.Map == map )
{
if ( SpellHelper.IsAnyT2A( map, c.Location ) && SpellHelper.IsAnyT2A( map, m.Location ) )
return false; //Same Map, both in T2A, ie, same 'sub server'.
Corpse c = m.Corpse as Corpse;
Map map = m.Map;
if ( m.Region.IsPartOf( typeof( DungeonRegion ) ) == Region.Find( c.Location, map ).IsPartOf( typeof( DungeonRegion ) ) )
return false; //Same Map, both in Dungeon region OR They're both NOT in a dungeon region.
if (c != null && !c.Deleted && map != null && c.Map == map)
{
if (SpellHelper.IsAnyT2A(map, c.Location) && SpellHelper.IsAnyT2A(map, m.Location))
return false; //Same Map, both in T2A, ie, same 'sub server'.
//Just an approximation cause RunUO doens't divide up the world the same way OSI does ;p
if (m.Region.IsPartOf(typeof(DungeonRegion)) == Region.Find(c.Location, map).IsPartOf(typeof(DungeonRegion)))
return false; //Same Map, both in Dungeon region OR They're both NOT in a dungeon region.
}
//Just an approximation cause RunUO doens't divide up the world the same way OSI does ;p
}
Party p = Party.Get( m );
Party p = Party.Get(m);
if ( p != null && p.Contains( Caster ) )
return false;
if (p != null && p.Contains(Caster))
return false;
if ( m.Guild != null && Caster.Guild != null )
{
Guild mGuild = m.Guild as Guild;
Guild cGuild = Caster.Guild as Guild;
if (m.Guild != null && Caster.Guild != null)
{
Guild mGuild = m.Guild as Guild;
Guild cGuild = Caster.Guild as Guild;
if ( mGuild.IsAlly( cGuild ) )
return false;
if (mGuild.IsAlly(cGuild))
return false;
if ( mGuild == cGuild )
return false;
}
if (mGuild == cGuild)
return false;
}
Faction f = Faction.Find( m );
Faction f = Faction.Find(m);
if ( Faction.Facet == m.Map && f != null && f == Faction.Find( Caster ) )
return false;
if (Faction.Facet == m.Map && f != null && f == Faction.Find(Caster))
return false;
return true;
}
return true;
}
private static Point3D GetNearestShrine( Mobile m )
{
Map map = m.Map;
private static Point3D GetNearestShrine(Mobile m)
{
Map map = m.Map;
Point3D[] locList;
Point3D[] locList;
if ( map == Map.Felucca || map == Map.Trammel )
locList = m_BritanniaLocs;
else if ( map == Map.Ilshenar )
locList = m_IllshLocs;
else if ( map == Map.Tokuno )
locList = m_TokunoLocs;
else if ( map == Map.Malas )
locList = m_MalasLocs;
else
locList = new Point3D[0];
if (map == Map.Felucca || map == Map.Trammel)
locList = m_BritanniaLocs;
else if (map == Map.Ilshenar)
locList = m_IllshLocs;
else if (map == Map.Tokuno)
locList = m_TokunoLocs;
else if (map == Map.Malas)
locList = m_MalasLocs;
else
locList = new Point3D[0];
Point3D closest = Point3D.Zero;
double minDist = double.MaxValue;
Point3D closest = Point3D.Zero;
double minDist = double.MaxValue;
for( int i = 0; i < locList.Length; i++ )
{
Point3D p = locList[i];
for (int i = 0; i < locList.Length; i++)
{
Point3D p = locList[i];
double dist = m.GetDistanceToSqrt( p );
if ( minDist > dist )
{
closest = p;
minDist = dist;
}
}
double dist = m.GetDistanceToSqrt(p);
if (minDist > dist)
{
closest = p;
minDist = dist;
}
}
return closest;
}
private static readonly Point3D[] m_BritanniaLocs = {
new Point3D( 1470, 843, 0 ),
new Point3D( 1857, 865, -1 ),
new Point3D( 4220, 563, 36 ),
new Point3D( 1732, 3528, 0 ),
new Point3D( 1300, 644, 8 ),
new Point3D( 3355, 302, 9 ),
new Point3D( 1606, 2490, 5 ),
new Point3D( 2500, 3931, 3 ),
new Point3D( 4264, 3707, 0 )
};
private static readonly Point3D[] m_IllshLocs = {
new Point3D( 1222, 474, -17 ),
new Point3D( 718, 1360, -60),
new Point3D( 297, 1014, -19 ),
new Point3D( 986, 1006, -36 ),
new Point3D( 1180, 1288, -30 ),
new Point3D( 1538, 1341, -3 ),
new Point3D( 528, 223, -38 )
};
private static readonly Point3D[] m_MalasLocs = {
new Point3D ( 976, 517, -30 )
};
private static readonly Point3D[] m_TokunoLocs = {
new Point3D( 710, 1162, 25 ),
new Point3D( 1034, 515, 18 ),
new Point3D( 295, 712, 55 )
};
}
}
return closest;
}
}
}

View file

@ -2,39 +2,39 @@ using System;
namespace Server.Spells.Necromancy
{
public class HorrificBeastSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Horrific Beast", "Rel Xen Vas Bal",
203,
9031,
Reagent.BatWing,
Reagent.DaemonBlood
);
public class HorrificBeastSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Horrific Beast", "Rel Xen Vas Bal",
203,
9031,
Reagent.BatWing,
Reagent.DaemonBlood
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public HorrificBeastSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 40.0;
public override int RequiredMana => 11;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override int Body => 746;
public override double RequiredSkill => 40.0;
public override int RequiredMana => 11;
public HorrificBeastSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override int Body => 746;
public override void DoEffect( Mobile m )
{
m.PlaySound( 0x165 );
m.FixedParticles( 0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head );
public override void DoEffect(Mobile m)
{
m.PlaySound(0x165);
m.FixedParticles(0x3728, 1, 13, 9918, 92, 3, EffectLayer.Head);
m.Delta( MobileDelta.WeaponDamage );
m.CheckStatTimers();
}
m.Delta(MobileDelta.WeaponDamage);
m.CheckStatTimers();
}
public override void RemoveEffect( Mobile m )
{
m.Delta( MobileDelta.WeaponDamage );
}
}
}
public override void RemoveEffect(Mobile m)
{
m.Delta(MobileDelta.WeaponDamage);
}
}
}

View file

@ -2,43 +2,43 @@ using System;
namespace Server.Spells.Necromancy
{
public class LichFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Lich Form", "Rel Xen Corp Ort",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public class LichFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Lich Form", "Rel Xen Corp Ort",
203,
9031,
Reagent.GraveDust,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public LichFormSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 70.0;
public override int RequiredMana => 23;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override int Body => 749;
public override double RequiredSkill => 70.0;
public override int RequiredMana => 23;
public override int FireResistOffset => -10;
public override int ColdResistOffset => +10;
public override int PoisResistOffset => +10;
public override int Body => 749;
public override double TickRate => 2.5;
public override int FireResistOffset => -10;
public override int ColdResistOffset => +10;
public override int PoisResistOffset => +10;
public LichFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override double TickRate => 2.5;
public override void DoEffect( Mobile m )
{
m.PlaySound( 0x19C );
m.FixedParticles( 0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot );
}
public override void DoEffect(Mobile m)
{
m.PlaySound(0x19C);
m.FixedParticles(0x3709, 1, 30, 9904, 1108, 6, EffectLayer.RightFoot);
}
public override void OnTick( Mobile m )
{
--m.Hits;
}
}
}
public override void OnTick(Mobile m)
{
--m.Hits;
}
}
}

View file

@ -4,176 +4,180 @@ using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class MindRotSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Mind Rot", "Wis An Ben",
203,
9031,
Reagent.BatWing,
Reagent.PigIron,
Reagent.DaemonBlood
);
public class MindRotSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Mind Rot", "Wis An Ben",
203,
9031,
Reagent.BatWing,
Reagent.PigIron,
Reagent.DaemonBlood
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.5 );
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 30.0;
public override int RequiredMana => 17;
public MindRotSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public MindRotSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5);
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override double RequiredSkill => 30.0;
public override int RequiredMana => 17;
public void Target( Mobile m )
{
if ( HasMindRotScalar( m ) )
{
Caster.SendLocalizedMessage( 1005559 ); // This spell is already in effect.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
/* Attempts to place a curse on the Target that increases the mana cost of any spells they cast,
* for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds.
*/
public void Target(Mobile m)
{
if (HasMindRotScalar(m))
{
Caster.SendLocalizedMessage(1005559); // This spell is already in effect.
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
m.Spell?.OnCasterHurt();
/* Attempts to place a curse on the Target that increases the mana cost of any spells they cast,
* for a duration based off a comparison between the Caster's Spirit Speak skill and the Target's Resisting Spells skill.
* The effect lasts for ((Spirit Speak skill level - target's Resist Magic skill level) / 50 ) + 20 seconds.
*/
m.PlaySound( 0x1FB );
m.PlaySound( 0x258 );
m.FixedParticles( 0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head );
m.Spell?.OnCasterHurt();
TimeSpan duration = TimeSpan.FromSeconds( (((GetDamageSkill( Caster ) - GetResistSkill( m )) / 5.0) + 20.0) * (m.Player ? 1.0 : 2.0 ) );
m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain
m.PlaySound(0x1FB);
m.PlaySound(0x258);
m.FixedParticles(0x373A, 1, 17, 9903, 15, 4, EffectLayer.Head);
if ( m.Player )
SetMindRotScalar( Caster, m, 1.25, duration );
else
SetMindRotScalar( Caster, m, 2.00, duration );
TimeSpan duration =
TimeSpan.FromSeconds(
((GetDamageSkill(Caster) - GetResistSkill(m)) / 5.0 + 20.0) * (m.Player ? 1.0 : 2.0));
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
HarmfulSpell( m );
}
if (m.Player)
SetMindRotScalar(Caster, m, 1.25, duration);
else
SetMindRotScalar(Caster, m, 2.00, duration);
FinishSequence();
}
HarmfulSpell(m);
}
private static Hashtable m_Table = new Hashtable();
FinishSequence();
}
public static void ClearMindRotScalar( Mobile m )
{
if (!m_Table.ContainsKey(m))
return;
public static void ClearMindRotScalar(Mobile m)
{
if (!m_Table.ContainsKey(m))
return;
BuffInfo.RemoveBuff( m, BuffIcon.Mindrot );
MRBucket tmpB = (MRBucket)m_Table[m];
MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer;
tmpT.Stop();
m_Table.Remove(m);
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
}
BuffInfo.RemoveBuff(m, BuffIcon.Mindrot);
MRBucket tmpB = (MRBucket)m_Table[m];
MRExpireTimer tmpT = tmpB.m_MRExpireTimer;
tmpT.Stop();
m_Table.Remove(m);
m.SendLocalizedMessage(1060872); // Your mind feels normal again.
}
public static bool HasMindRotScalar( Mobile m )
{
return m_Table.ContainsKey(m);
}
public static bool HasMindRotScalar(Mobile m)
{
return m_Table.ContainsKey(m);
}
public static bool GetMindRotScalar( Mobile m, ref double scalar )
{
if (!m_Table.ContainsKey(m))
return false;
public static bool GetMindRotScalar(Mobile m, ref double scalar)
{
if (!m_Table.ContainsKey(m))
return false;
MRBucket tmpB = (MRBucket)m_Table[m];
scalar = tmpB.m_Scalar;
return true;
}
MRBucket tmpB = (MRBucket)m_Table[m];
scalar = tmpB.m_Scalar;
return true;
}
public static void SetMindRotScalar( Mobile caster, Mobile target, double scalar, TimeSpan duration )
{
if (!m_Table.ContainsKey(target))
{
m_Table.Add(target, new MRBucket(scalar, new MRExpireTimer(caster, target, duration)));
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
MRBucket tmpB = (MRBucket)m_Table[target];
MRExpireTimer tmpT = (MRExpireTimer)tmpB.m_MRExpireTimer;
tmpT.Start();
target.SendLocalizedMessage(1074384);
}
}
public static void SetMindRotScalar(Mobile caster, Mobile target, double scalar, TimeSpan duration)
{
if (!m_Table.ContainsKey(target))
{
m_Table.Add(target, new MRBucket(scalar, new MRExpireTimer(caster, target, duration)));
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.Mindrot, 1075665, duration, target));
MRBucket tmpB = (MRBucket)m_Table[target];
MRExpireTimer tmpT = tmpB.m_MRExpireTimer;
tmpT.Start();
target.SendLocalizedMessage(1074384);
}
}
private class InternalTarget : Target
{
private MindRotSpell m_Owner;
private class InternalTarget : Target
{
private MindRotSpell m_Owner;
public InternalTarget( MindRotSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
public InternalTarget(MindRotSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
else
from.SendLocalizedMessage( 1060508 ); // You can't curse that.
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
else
from.SendLocalizedMessage(1060508); // You can't curse that.
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
public class MRExpireTimer : Timer
{
private Mobile m_Caster;
private Mobile m_Target;
private DateTime m_End;
public class MRExpireTimer : Timer
{
private Mobile m_Caster;
private DateTime m_End;
private Mobile m_Target;
public MRExpireTimer( Mobile caster, Mobile target, TimeSpan delay ) : base( TimeSpan.FromSeconds( 1.0 ), TimeSpan.FromSeconds( 1.0 ) )
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.UtcNow + delay;
Priority = TimerPriority.TwoFiftyMS;
}
public MRExpireTimer(Mobile caster, Mobile target, TimeSpan delay) : base(TimeSpan.FromSeconds(1.0),
TimeSpan.FromSeconds(1.0))
{
m_Caster = caster;
m_Target = target;
m_End = DateTime.UtcNow + delay;
Priority = TimerPriority.TwoFiftyMS;
}
public void RenewDelay(TimeSpan delay)
{
m_End = DateTime.UtcNow + delay;
}
public void RenewDelay(TimeSpan delay)
{
m_End = DateTime.UtcNow + delay;
}
public void Halt()
{
Stop();
}
public void Halt()
{
Stop();
}
protected override void OnTick()
{
if ( m_Target.Deleted || !m_Target.Alive || DateTime.UtcNow >= m_End )
{
MindRotSpell.ClearMindRotScalar( m_Target );
Stop();
}
}
}
protected override void OnTick()
{
if (m_Target.Deleted || !m_Target.Alive || DateTime.UtcNow >= m_End)
{
MindRotSpell.ClearMindRotScalar(m_Target);
Stop();
}
}
}
public class MRBucket
{
public MRBucket(double theScalar, MRExpireTimer theTimer)
{
m_Scalar = theScalar;
m_MRExpireTimer = theTimer;
}
public class MRBucket
{
public MRExpireTimer m_MRExpireTimer;
public double m_Scalar;
public MRExpireTimer m_MRExpireTimer;
}
}
public double m_Scalar;
public MRBucket(double theScalar, MRExpireTimer theTimer)
{
m_Scalar = theScalar;
m_MRExpireTimer = theTimer;
}
}
}

View file

@ -2,56 +2,60 @@ using Server.Items;
namespace Server.Spells.Necromancy
{
public abstract class NecromancerSpell : Spell
{
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
public abstract class NecromancerSpell : Spell
{
public NecromancerSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
{
}
public override SkillName CastSkill => SkillName.Necromancy;
public override SkillName DamageSkill => SkillName.SpiritSpeak;
public abstract double RequiredSkill{ get; }
public abstract int RequiredMana{ get; }
//public override int CastDelayBase => base.CastDelayBase; // Reference, 3
public override SkillName CastSkill => SkillName.Necromancy;
public override SkillName DamageSkill => SkillName.SpiritSpeak;
public override bool ClearHandsOnCast => false;
//public override int CastDelayBase => base.CastDelayBase; // Reference, 3
public override double CastDelayFastScalar => (Core.SE? base.CastDelayFastScalar : 0); // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
public override bool ClearHandsOnCast => false;
public NecromancerSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public override double CastDelayFastScalar =>
Core.SE
? base.CastDelayFastScalar
: 0; // Necromancer spells are not affected by fast cast items, though they are by fast cast recovery
public override int ComputeKarmaAward()
{
//TODO: Verify this formula being that Necro spells don't HAVE a circle.
//int karma = -(70 + (10 * (int)Circle));
int karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick)));
public override int ComputeKarmaAward()
{
//TODO: Verify this formula being that Necro spells don't HAVE a circle.
//int karma = -(70 + (10 * (int)Circle));
int karma = -(40 + (int)(10 * (CastDelayBase.TotalSeconds / CastDelaySecondsPerTick)));
if ( Core.ML ) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells."
karma += AOS.Scale( karma, AosAttributes.GetValue( Caster, AosAttribute.IncreasedKarmaLoss ) );
if (Core.ML
) // Pub 36: "Added a new property called Increased Karma Loss which grants higher karma loss for casting necromancy spells."
karma += AOS.Scale(karma, AosAttributes.GetValue(Caster, AosAttribute.IncreasedKarmaLoss));
return karma;
}
return karma;
}
public override void GetCastSkills( out double min, out double max )
{
min = RequiredSkill;
max = Scroll != null ? min : RequiredSkill + 40.0;
}
public override void GetCastSkills(out double min, out double max)
{
min = RequiredSkill;
max = Scroll != null ? min : RequiredSkill + 40.0;
}
public override bool ConsumeReagents()
{
if ( base.ConsumeReagents() )
return true;
public override bool ConsumeReagents()
{
if (base.ConsumeReagents())
return true;
if ( ArcaneGem.ConsumeCharges( Caster, 1 ) )
return true;
if (ArcaneGem.ConsumeCharges(Caster, 1))
return true;
return false;
}
return false;
}
public override int GetMana()
{
return RequiredMana;
}
}
}
public override int GetMana()
{
return RequiredMana;
}
}
}

View file

@ -1,138 +1,139 @@
using System;
using System.Collections;
using Server.Misc;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class PainSpikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Pain Spike", "In Sar",
203,
9031,
Reagent.GraveDust,
Reagent.PigIron
);
public class PainSpikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Pain Spike", "In Sar",
203,
9031,
Reagent.GraveDust,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.0 );
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 20.0;
public override int RequiredMana => 5;
public PainSpikeSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public PainSpikeSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.0);
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override double RequiredSkill => 20.0;
public override int RequiredMana => 5;
public override bool DelayedDamage => false;
public override bool DelayedDamage => false;
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
//SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent asfter AoS
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
/* Temporarily causes intense physical pain to the target, dealing direct damage.
* After 10 seconds the spell wears off, and if the target is still alive,
* some of the Hit Points lost through Pain Spike are restored.
*/
//SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent asfter AoS
m.FixedParticles( 0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head );
m.FixedParticles( 0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head );
m.PlaySound( 0x210 );
/* Temporarily causes intense physical pain to the target, dealing direct damage.
* After 10 seconds the spell wears off, and if the target is still alive,
* some of the Hit Points lost through Pain Spike are restored.
*/
double damage = ((GetDamageSkill( Caster ) - GetResistSkill( m )) / 10) + (m.Player ? 18 : 30);
m.CheckSkill( SkillName.MagicResist, 0.0, 120.0 ); //Skill check for gain
m.FixedParticles(0x37C4, 1, 8, 9916, 39, 3, EffectLayer.Head);
m.FixedParticles(0x37C4, 1, 8, 9502, 39, 4, EffectLayer.Head);
m.PlaySound(0x210);
if ( damage < 1 )
damage = 1;
double damage = (GetDamageSkill(Caster) - GetResistSkill(m)) / 10 + (m.Player ? 18 : 30);
m.CheckSkill(SkillName.MagicResist, 0.0, 120.0); //Skill check for gain
TimeSpan buffTime = TimeSpan.FromSeconds( 10.0 );
if (damage < 1)
damage = 1;
if ( m_Table.Contains( m ) )
{
damage = Utility.RandomMinMax( 3, 7 );
Timer t = m_Table[m] as Timer;
TimeSpan buffTime = TimeSpan.FromSeconds(10.0);
if ( t != null )
{
t.Delay += TimeSpan.FromSeconds( 2.0 );
if (m_Table.Contains(m))
{
damage = Utility.RandomMinMax(3, 7);
Timer t = m_Table[m] as Timer;
buffTime = t.Next - DateTime.UtcNow;
}
}
else
{
new InternalTimer( m, damage ).Start();
}
if (t != null)
{
t.Delay += TimeSpan.FromSeconds(2.0);
BuffInfo.AddBuff( m, new BuffInfo( BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString( (int)damage ) ) );
buffTime = t.Next - DateTime.UtcNow;
}
}
else
{
new InternalTimer(m, damage).Start();
}
Misc.WeightOverloading.DFA = Misc.DFAlgorithm.PainSpike;
m.Damage( (int) damage, Caster );
SpellHelper.DoLeech( (int)damage, Caster, m );
Misc.WeightOverloading.DFA = Misc.DFAlgorithm.Standard;
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.PainSpike, 1075667, buffTime, m, Convert.ToString((int)damage)));
//SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike );
HarmfulSpell( m );
}
WeightOverloading.DFA = DFAlgorithm.PainSpike;
m.Damage((int)damage, Caster);
SpellHelper.DoLeech((int)damage, Caster, m);
WeightOverloading.DFA = DFAlgorithm.Standard;
FinishSequence();
}
//SpellHelper.Damage( this, m, damage, 100, 0, 0, 0, 0, Misc.DFAlgorithm.PainSpike );
HarmfulSpell(m);
}
private static Hashtable m_Table = new Hashtable();
FinishSequence();
}
private class InternalTimer : Timer
{
private Mobile m_Mobile;
private int m_ToRestore;
private class InternalTimer : Timer
{
private Mobile m_Mobile;
private int m_ToRestore;
public InternalTimer( Mobile m, double toRestore ) : base( TimeSpan.FromSeconds( 10.0 ) )
{
Priority = TimerPriority.OneSecond;
public InternalTimer(Mobile m, double toRestore) : base(TimeSpan.FromSeconds(10.0))
{
Priority = TimerPriority.OneSecond;
m_Mobile = m;
m_ToRestore = (int)toRestore;
m_Mobile = m;
m_ToRestore = (int)toRestore;
m_Table[m] = this;
}
m_Table[m] = this;
}
protected override void OnTick()
{
m_Table.Remove( m_Mobile );
protected override void OnTick()
{
m_Table.Remove(m_Mobile);
if ( m_Mobile.Alive && !m_Mobile.IsDeadBondedPet )
m_Mobile.Hits += m_ToRestore;
if (m_Mobile.Alive && !m_Mobile.IsDeadBondedPet)
m_Mobile.Hits += m_ToRestore;
BuffInfo.RemoveBuff( m_Mobile, BuffIcon.PainSpike );
}
}
BuffInfo.RemoveBuff(m_Mobile, BuffIcon.PainSpike);
}
}
private class InternalTarget : Target
{
private PainSpikeSpell m_Owner;
private class InternalTarget : Target
{
private PainSpikeSpell m_Owner;
public InternalTarget( PainSpikeSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
public InternalTarget(PainSpikeSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -1,117 +1,120 @@
using System;
using System.Collections.Generic;
using Server.Items;
using Server.Targeting;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class PoisonStrikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Poison Strike", "In Vas Nox",
203,
9031,
Reagent.NoxCrystal
);
public class PoisonStrikeSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Poison Strike", "In Vas Nox",
203,
9031,
Reagent.NoxCrystal
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( (Core.ML ? 1.75 : 1.5) );
public PoisonStrikeSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 50.0;
public override int RequiredMana => 17;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(Core.ML ? 1.75 : 1.5);
public PoisonStrikeSpell( Mobile caster, Item scroll )
: base( caster, scroll, m_Info )
{
}
public override double RequiredSkill => 50.0;
public override int RequiredMana => 17;
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override bool DelayedDamage => false;
public override bool DelayedDamage => false;
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
/* Creates a blast of poisonous energy centered on the target.
* The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect.
* One tile from main target receives 50% damage, two tiles from target receives 33% damage.
*/
/* Creates a blast of poisonous energy centered on the target.
* The main target is inflicted with a large amount of Poison damage, and all valid targets in a radius of 2 tiles around the main target are inflicted with a lesser effect.
* One tile from main target receives 50% damage, two tiles from target receives 33% damage.
*/
//CheckResisted( m ); // Check magic resist for skill, but do not use return value //reports from OSI: Necro spells don't give Resist gain
//CheckResisted( m ); // Check magic resist for skill, but do not use return value //reports from OSI: Necro spells don't give Resist gain
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x36B0, 1, 14, 63, 7, 9915, 0 );
Effects.PlaySound( m.Location, m.Map, 0x229 );
Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x36B0, 1,
14, 63, 7, 9915, 0);
Effects.PlaySound(m.Location, m.Map, 0x229);
double damage = Utility.RandomMinMax( (Core.ML ? 32 : 36), 40 ) * ((300 + (GetDamageSkill( Caster ) * 9)) / 1000);
double damage = Utility.RandomMinMax(Core.ML ? 32 : 36, 40) * ((300 + GetDamageSkill(Caster) * 9) / 1000);
double sdiBonus = (double)AosAttributes.GetValue( Caster, AosAttribute.SpellDamage )/100;
double pvmDamage = damage * (1 + sdiBonus);
double sdiBonus = (double)AosAttributes.GetValue(Caster, AosAttribute.SpellDamage) / 100;
double pvmDamage = damage * (1 + sdiBonus);
if ( Core.ML && sdiBonus > 0.15 )
sdiBonus = 0.15;
double pvpDamage = damage * (1 + sdiBonus);
if (Core.ML && sdiBonus > 0.15)
sdiBonus = 0.15;
double pvpDamage = damage * (1 + sdiBonus);
Map map = m.Map;
Map map = m.Map;
if ( map != null )
{
List<Mobile> targets = new List<Mobile>();
if (map != null)
{
List<Mobile> targets = new List<Mobile>();
if ( Caster.CanBeHarmful(m, false ) )
targets.Add( m );
if (Caster.CanBeHarmful(m, false))
targets.Add(m);
foreach( Mobile targ in m.GetMobilesInRange( 2 ) )
if (!(Caster is BaseCreature && targ is BaseCreature ))
if ( ( targ != Caster && m != targ ) && ( SpellHelper.ValidIndirectTarget( Caster, targ ) && Caster.CanBeHarmful( targ, false) ) )
targets.Add( targ );
foreach (Mobile targ in m.GetMobilesInRange(2))
if (!(Caster is BaseCreature && targ is BaseCreature))
if (targ != Caster && m != targ && SpellHelper.ValidIndirectTarget(Caster, targ) &&
Caster.CanBeHarmful(targ, false))
targets.Add(targ);
for( int i = 0; i < targets.Count; ++i )
{
Mobile targ = targets[i];
int num;
for (int i = 0; i < targets.Count; ++i)
{
Mobile targ = targets[i];
int num;
if ( targ.InRange( m.Location, 0 ) )
num = 1;
else if ( targ.InRange( m.Location, 1 ) )
num = 2;
else
num = 3;
if (targ.InRange(m.Location, 0))
num = 1;
else if (targ.InRange(m.Location, 1))
num = 2;
else
num = 3;
Caster.DoHarmful( targ );
SpellHelper.Damage( this, targ, ((m.Player && Caster.Player) ? pvpDamage : pvmDamage) / num, 0, 0, 0, 100, 0 );
}
}
}
Caster.DoHarmful(targ);
SpellHelper.Damage(this, targ, (m.Player && Caster.Player ? pvpDamage : pvmDamage) / num, 0, 0, 0,
100, 0);
}
}
}
FinishSequence();
}
FinishSequence();
}
private class InternalTarget : Target
{
private PoisonStrikeSpell m_Owner;
private class InternalTarget : Target
{
private PoisonStrikeSpell m_Owner;
public InternalTarget( PoisonStrikeSpell owner )
: base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
public InternalTarget(PoisonStrikeSpell owner)
: base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile)o );
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -4,235 +4,237 @@ using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class StrangleSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Strangle", "In Bal Nox",
209,
9031,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public class StrangleSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Strangle", "In Bal Nox",
209,
9031,
Reagent.DaemonBlood,
Reagent.NoxCrystal
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
private static Hashtable m_Table = new Hashtable();
public override double RequiredSkill => 65.0;
public override int RequiredMana => 29;
public StrangleSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public StrangleSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override double RequiredSkill => 65.0;
public override int RequiredMana => 29;
public void Target( Mobile m )
{
if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
//SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS
public void Target(Mobile m)
{
if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
/* Temporarily chokes off the air suply of the target with poisonous fumes.
* The target is inflicted with poison damage over time.
* The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina.
* The less Stamina the target has, the more damage is done by Strangle.
* Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds.
* The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds.
* The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1.
* Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2).
* Example:
* For a target at full Stamina the damage multiplier is 1,
* for a target at 50% Stamina the damage multiplier is 2 and
* for a target at 20% Stamina the damage multiplier is 2.6
*/
//SpellHelper.CheckReflect( (int)this.Circle, Caster, ref m ); //Irrelevent after AoS
m.Spell?.OnCasterHurt();
/* Temporarily chokes off the air suply of the target with poisonous fumes.
* The target is inflicted with poison damage over time.
* The amount of damage dealt each "hit" is based off of the caster's Spirit Speak skill and the Target's current Stamina.
* The less Stamina the target has, the more damage is done by Strangle.
* Duration of the effect is Spirit Speak skill level / 10 rounds, with a minimum number of 4 rounds.
* The first round of damage is dealt after 5 seconds, and every next round after that comes 1 second sooner than the one before, until there is only 1 second between rounds.
* The base damage of the effect lies between (Spirit Speak skill level / 10) - 2 and (Spirit Speak skill level / 10) + 1.
* Base damage is multiplied by the following formula: (3 - (target's current Stamina / target's maximum Stamina) * 2).
* Example:
* For a target at full Stamina the damage multiplier is 1,
* for a target at 50% Stamina the damage multiplier is 2 and
* for a target at 20% Stamina the damage multiplier is 2.6
*/
m.PlaySound( 0x22F );
m.FixedParticles( 0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head );
m.FixedParticles( 0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255 );
m.Spell?.OnCasterHurt();
if ( !m_Table.Contains( m ) )
{
Timer t = new InternalTimer( m, Caster );
t.Start();
m.PlaySound(0x22F);
m.FixedParticles(0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head);
m.FixedParticles(0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255);
m_Table[m] = t;
}
if (!m_Table.Contains(m))
{
Timer t = new InternalTimer(m, Caster);
t.Start();
HarmfulSpell( m );
}
m_Table[m] = t;
}
//Calculations for the buff bar
double spiritlevel = Caster.Skills[SkillName.SpiritSpeak].Value / 10;
if (spiritlevel < 4)
spiritlevel = 4;
int d_MinDamage = 4;
int d_MaxDamage = ((int)spiritlevel + 1) * 3;
string args = $"{d_MinDamage}\t{d_MaxDamage}";
HarmfulSpell(m);
}
int i_Count = (int)spiritlevel;
int i_MaxCount = i_Count;
int i_HitDelay = 5;
int i_Length = i_HitDelay;
//Calculations for the buff bar
double spiritlevel = Caster.Skills[SkillName.SpiritSpeak].Value / 10;
if (spiritlevel < 4)
spiritlevel = 4;
int d_MinDamage = 4;
int d_MaxDamage = ((int)spiritlevel + 1) * 3;
string args = $"{d_MinDamage}\t{d_MaxDamage}";
while (i_Count > 1)
{
--i_Count;
if (i_HitDelay > 1)
{
if (i_MaxCount < 5)
{
--i_HitDelay;
}
else
{
int delay = (int)(Math.Ceiling((1.0 + (5 * i_Count)) / i_MaxCount));
int i_Count = (int)spiritlevel;
int i_MaxCount = i_Count;
int i_HitDelay = 5;
int i_Length = i_HitDelay;
if (delay <= 5)
i_HitDelay = delay;
else
i_HitDelay = 5;
}
}
i_Length += i_HitDelay;
}
TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args.ToString()));
while (i_Count > 1)
{
--i_Count;
if (i_HitDelay > 1)
{
if (i_MaxCount < 5)
{
--i_HitDelay;
}
else
{
int delay = (int)Math.Ceiling((1.0 + 5 * i_Count) / i_MaxCount);
FinishSequence();
}
if (delay <= 5)
i_HitDelay = delay;
else
i_HitDelay = 5;
}
}
private static Hashtable m_Table = new Hashtable();
i_Length += i_HitDelay;
}
public static bool RemoveCurse( Mobile m )
{
Timer t = (Timer)m_Table[m];
TimeSpan t_Duration = TimeSpan.FromSeconds(i_Length);
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Strangle, 1075794, 1075795, t_Duration, m, args));
if ( t == null )
return false;
FinishSequence();
}
t.Stop();
m.SendLocalizedMessage( 1061687 ); // You can breath normally again.
public static bool RemoveCurse(Mobile m)
{
Timer t = (Timer)m_Table[m];
m_Table.Remove( m );
return true;
}
if (t == null)
return false;
private class InternalTimer : Timer
{
private Mobile m_Target, m_From;
private double m_MinBaseDamage, m_MaxBaseDamage;
t.Stop();
m.SendLocalizedMessage(1061687); // You can breath normally again.
private DateTime m_NextHit;
private int m_HitDelay;
m_Table.Remove(m);
return true;
}
private int m_Count, m_MaxCount;
private class InternalTimer : Timer
{
private int m_Count, m_MaxCount;
private int m_HitDelay;
private double m_MinBaseDamage, m_MaxBaseDamage;
public InternalTimer( Mobile target, Mobile from ) : base( TimeSpan.FromSeconds( 0.1 ), TimeSpan.FromSeconds( 0.1 ) )
{
Priority = TimerPriority.FiftyMS;
private DateTime m_NextHit;
private Mobile m_Target, m_From;
m_Target = target;
m_From = from;
public InternalTimer(Mobile target, Mobile from) : base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
{
Priority = TimerPriority.FiftyMS;
double spiritLevel = from.Skills[SkillName.SpiritSpeak].Value / 10;
m_Target = target;
m_From = from;
m_MinBaseDamage = spiritLevel - 2;
m_MaxBaseDamage = spiritLevel + 1;
double spiritLevel = from.Skills[SkillName.SpiritSpeak].Value / 10;
m_HitDelay = 5;
m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds( m_HitDelay );
m_MinBaseDamage = spiritLevel - 2;
m_MaxBaseDamage = spiritLevel + 1;
m_Count = (int)spiritLevel;
m_HitDelay = 5;
m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay);
if ( m_Count < 4 )
m_Count = 4;
m_Count = (int)spiritLevel;
m_MaxCount = m_Count;
}
if (m_Count < 4)
m_Count = 4;
protected override void OnTick()
{
if ( !m_Target.Alive )
{
m_Table.Remove( m_Target );
Stop();
}
m_MaxCount = m_Count;
}
if ( !m_Target.Alive || DateTime.UtcNow < m_NextHit )
return;
protected override void OnTick()
{
if (!m_Target.Alive)
{
m_Table.Remove(m_Target);
Stop();
}
--m_Count;
if (!m_Target.Alive || DateTime.UtcNow < m_NextHit)
return;
if ( m_HitDelay > 1 )
{
if ( m_MaxCount < 5 )
{
--m_HitDelay;
}
else
{
int delay = (int)(Math.Ceiling( (1.0 + (5 * m_Count)) / m_MaxCount ) );
--m_Count;
if ( delay <= 5 )
m_HitDelay = delay;
else
m_HitDelay = 5;
}
}
if (m_HitDelay > 1)
{
if (m_MaxCount < 5)
{
--m_HitDelay;
}
else
{
int delay = (int)Math.Ceiling((1.0 + 5 * m_Count) / m_MaxCount);
if ( m_Count == 0 )
{
m_Target.SendLocalizedMessage( 1061687 ); // You can breath normally again.
m_Table.Remove( m_Target );
Stop();
}
else
{
m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds( m_HitDelay );
if (delay <= 5)
m_HitDelay = delay;
else
m_HitDelay = 5;
}
}
double damage = m_MinBaseDamage + (Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage));
if (m_Count == 0)
{
m_Target.SendLocalizedMessage(1061687); // You can breath normally again.
m_Table.Remove(m_Target);
Stop();
}
else
{
m_NextHit = DateTime.UtcNow + TimeSpan.FromSeconds(m_HitDelay);
damage *= (3 - (((double)m_Target.Stam / m_Target.StamMax) * 2));
double damage = m_MinBaseDamage + Utility.RandomDouble() * (m_MaxBaseDamage - m_MinBaseDamage);
if ( damage < 1 )
damage = 1;
damage *= 3 - (double)m_Target.Stam / m_Target.StamMax * 2;
if ( !m_Target.Player )
damage *= 1.75;
if (damage < 1)
damage = 1;
AOS.Damage( m_Target, m_From, (int)damage, 0, 0, 0, 100, 0 );
if (!m_Target.Player)
damage *= 1.75;
if ( 0.60 <= Utility.RandomDouble() ) // OSI: randomly revealed between first and third damage tick, guessing 60% chance
m_Target.RevealingAction();
}
}
}
AOS.Damage(m_Target, m_From, (int)damage, 0, 0, 0, 100, 0);
private class InternalTarget : Target
{
private StrangleSpell m_Owner;
if (0.60 <= Utility.RandomDouble()
) // OSI: randomly revealed between first and third damage tick, guessing 60% chance
m_Target.RevealingAction();
}
}
}
public InternalTarget( StrangleSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
private class InternalTarget : Target
{
private StrangleSpell m_Owner;
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
public InternalTarget(StrangleSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -1,203 +1,208 @@
using System;
using System.Collections;
using Server.Network;
using Server.Gumps;
using Server.Mobiles;
using Server.Network;
namespace Server.Spells.Necromancy
{
public class SummonFamiliarSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Summon Familiar", "Kal Xen Bal",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.DaemonBlood
);
public class SummonFamiliarSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Summon Familiar", "Kal Xen Bal",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.DaemonBlood
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public SummonFamiliarSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 30.0;
public override int RequiredMana => 17;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public SummonFamiliarSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override double RequiredSkill => 30.0;
public override int RequiredMana => 17;
public static Hashtable Table { get; } = new Hashtable();
public static Hashtable Table{ get; } = new Hashtable();
public override bool CheckCast()
{
BaseCreature check = (BaseCreature)Table[Caster];
public static SummonFamiliarEntry[] Entries{ get; } =
{
new SummonFamiliarEntry(typeof(HordeMinionFamiliar), 1060146, 30.0, 30.0), // Horde Minion
new SummonFamiliarEntry(typeof(ShadowWispFamiliar), 1060142, 50.0, 50.0), // Shadow Wisp
new SummonFamiliarEntry(typeof(DarkWolfFamiliar), 1060143, 60.0, 60.0), // Dark Wolf
new SummonFamiliarEntry(typeof(DeathAdder), 1060145, 80.0, 80.0), // Death Adder
new SummonFamiliarEntry(typeof(VampireBatFamiliar), 1060144, 100.0, 100.0) // Vampire Bat
};
if ( check != null && !check.Deleted )
{
Caster.SendLocalizedMessage( 1061605 ); // You already have a familiar.
return false;
}
public override bool CheckCast()
{
BaseCreature check = (BaseCreature)Table[Caster];
return base.CheckCast();
}
if (check != null && !check.Deleted)
{
Caster.SendLocalizedMessage(1061605); // You already have a familiar.
return false;
}
public override void OnCast()
{
if ( CheckSequence() )
{
Caster.CloseGump( typeof( SummonFamiliarGump ) );
Caster.SendGump( new SummonFamiliarGump( Caster, Entries, this ) );
}
return base.CheckCast();
}
FinishSequence();
}
public override void OnCast()
{
if (CheckSequence())
{
Caster.CloseGump(typeof(SummonFamiliarGump));
Caster.SendGump(new SummonFamiliarGump(Caster, Entries, this));
}
public static SummonFamiliarEntry[] Entries { get; } =
{
new SummonFamiliarEntry( typeof( HordeMinionFamiliar ), 1060146, 30.0, 30.0 ), // Horde Minion
new SummonFamiliarEntry( typeof( ShadowWispFamiliar ), 1060142, 50.0, 50.0 ), // Shadow Wisp
new SummonFamiliarEntry( typeof( DarkWolfFamiliar ), 1060143, 60.0, 60.0 ), // Dark Wolf
new SummonFamiliarEntry( typeof( DeathAdder ), 1060145, 80.0, 80.0 ), // Death Adder
new SummonFamiliarEntry( typeof( VampireBatFamiliar ), 1060144, 100.0, 100.0 ) // Vampire Bat
};
}
FinishSequence();
}
}
public class SummonFamiliarEntry
{
public Type Type { get; }
public class SummonFamiliarEntry
{
public SummonFamiliarEntry(Type type, object name, double reqNecromancy, double reqSpiritSpeak)
{
Type = type;
Name = name;
ReqNecromancy = reqNecromancy;
ReqSpiritSpeak = reqSpiritSpeak;
}
public object Name { get; }
public Type Type{ get; }
public double ReqNecromancy { get; }
public object Name{ get; }
public double ReqSpiritSpeak { get; }
public double ReqNecromancy{ get; }
public SummonFamiliarEntry( Type type, object name, double reqNecromancy, double reqSpiritSpeak )
{
Type = type;
Name = name;
ReqNecromancy = reqNecromancy;
ReqSpiritSpeak = reqSpiritSpeak;
}
}
public double ReqSpiritSpeak{ get; }
}
public class SummonFamiliarGump : Gump
{
private Mobile m_From;
private SummonFamiliarEntry[] m_Entries;
public class SummonFamiliarGump : Gump
{
private const int EnabledColor16 = 0x0F20;
private const int DisabledColor16 = 0x262A;
private SummonFamiliarSpell m_Spell;
private const int EnabledColor32 = 0x18CD00;
private const int DisabledColor32 = 0x4A8B52;
private const int EnabledColor16 = 0x0F20;
private const int DisabledColor16 = 0x262A;
private static Hashtable m_Table = new Hashtable();
private SummonFamiliarEntry[] m_Entries;
private Mobile m_From;
private const int EnabledColor32 = 0x18CD00;
private const int DisabledColor32 = 0x4A8B52;
private SummonFamiliarSpell m_Spell;
public SummonFamiliarGump( Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell ) : base( 200, 100 )
{
m_From = from;
m_Entries = entries;
m_Spell = spell;
public SummonFamiliarGump(Mobile from, SummonFamiliarEntry[] entries, SummonFamiliarSpell spell) : base(200, 100)
{
m_From = from;
m_Entries = entries;
m_Spell = spell;
AddPage( 0 );
AddPage(0);
AddBackground( 10, 10, 250, 178, 9270 );
AddAlphaRegion( 20, 20, 230, 158 );
AddBackground(10, 10, 250, 178, 9270);
AddAlphaRegion(20, 20, 230, 158);
AddImage( 220, 20, 10464 );
AddImage( 220, 72, 10464 );
AddImage( 220, 124, 10464 );
AddImage(220, 20, 10464);
AddImage(220, 72, 10464);
AddImage(220, 124, 10464);
AddItem( 188, 16, 6883 );
AddItem( 198, 168, 6881 );
AddItem( 8, 15, 6882 );
AddItem( 2, 168, 6880 );
AddItem(188, 16, 6883);
AddItem(198, 168, 6881);
AddItem(8, 15, 6882);
AddItem(2, 168, 6880);
AddHtmlLocalized( 30, 26, 200, 20, 1060147, EnabledColor16, false, false ); // Chose thy familiar...
AddHtmlLocalized(30, 26, 200, 20, 1060147, EnabledColor16, false, false); // Chose thy familiar...
double necro = from.Skills[SkillName.Necromancy].Value;
double spirit = from.Skills[SkillName.SpiritSpeak].Value;
double necro = from.Skills[SkillName.Necromancy].Value;
double spirit = from.Skills[SkillName.SpiritSpeak].Value;
for ( int i = 0; i < entries.Length; ++i )
{
object name = entries[i].Name;
for (int i = 0; i < entries.Length; ++i)
{
object name = entries[i].Name;
bool enabled = ( necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak );
bool enabled = necro >= entries[i].ReqNecromancy && spirit >= entries[i].ReqSpiritSpeak;
AddButton( 27, 53 + (i * 21), 9702, 9703, i + 1, GumpButtonType.Reply, 0 );
AddButton(27, 53 + i * 21, 9702, 9703, i + 1, GumpButtonType.Reply, 0);
if ( name is int )
AddHtmlLocalized( 50, 51 + (i * 21), 150, 20, (int)name, enabled ? EnabledColor16 : DisabledColor16, false, false );
else if ( name is string )
AddHtml( 50, 51 + (i * 21), 150, 20,
$"<BASEFONT COLOR=#{(enabled ? EnabledColor32 : DisabledColor32):X6}>{name}</BASEFONT>", false, false );
}
}
if (name is int)
AddHtmlLocalized(50, 51 + i * 21, 150, 20, (int)name, enabled ? EnabledColor16 : DisabledColor16, false,
false);
else if (name is string)
AddHtml(50, 51 + i * 21, 150, 20,
$"<BASEFONT COLOR=#{(enabled ? EnabledColor32 : DisabledColor32):X6}>{name}</BASEFONT>", false,
false);
}
}
private static Hashtable m_Table = new Hashtable();
public override void OnResponse(NetState sender, RelayInfo info)
{
int index = info.ButtonID - 1;
public override void OnResponse( NetState sender, RelayInfo info )
{
int index = info.ButtonID - 1;
if (index >= 0 && index < m_Entries.Length)
{
SummonFamiliarEntry entry = m_Entries[index];
if ( index >= 0 && index < m_Entries.Length )
{
SummonFamiliarEntry entry = m_Entries[index];
double necro = m_From.Skills[SkillName.Necromancy].Value;
double spirit = m_From.Skills[SkillName.SpiritSpeak].Value;
double necro = m_From.Skills[SkillName.Necromancy].Value;
double spirit = m_From.Skills[SkillName.SpiritSpeak].Value;
BaseCreature check = (BaseCreature)SummonFamiliarSpell.Table[m_From];
BaseCreature check = (BaseCreature)SummonFamiliarSpell.Table[m_From];
#region Dueling
#region Dueling
if ( (m_From as PlayerMobile)?.DuelContext != null && !( (PlayerMobile)m_From ).DuelContext.AllowSpellCast( m_From, m_Spell ) )
{
}
#endregion
else if ( check != null && !check.Deleted )
{
m_From.SendLocalizedMessage( 1061605 ); // You already have a familiar.
}
else if ( necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak )
{
// That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak.
m_From.SendLocalizedMessage( 1061606, $"{entry.ReqNecromancy:F1}\t{entry.ReqSpiritSpeak:F1}");
if ((m_From as PlayerMobile)?.DuelContext != null &&
!((PlayerMobile)m_From).DuelContext.AllowSpellCast(m_From, m_Spell))
{
}
m_From.CloseGump( typeof( SummonFamiliarGump ) );
m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) );
}
else if ( entry.Type == null )
{
m_From.SendMessage( "That familiar has not yet been defined." );
#endregion
m_From.CloseGump( typeof( SummonFamiliarGump ) );
m_From.SendGump( new SummonFamiliarGump( m_From, SummonFamiliarSpell.Entries, m_Spell ) );
}
else
{
try
{
BaseCreature bc = (BaseCreature)Activator.CreateInstance( entry.Type );
else if (check != null && !check.Deleted)
{
m_From.SendLocalizedMessage(1061605); // You already have a familiar.
}
else if (necro < entry.ReqNecromancy || spirit < entry.ReqSpiritSpeak)
{
// That familiar requires ~1_NECROMANCY~ Necromancy and ~2_SPIRIT~ Spirit Speak.
m_From.SendLocalizedMessage(1061606, $"{entry.ReqNecromancy:F1}\t{entry.ReqSpiritSpeak:F1}");
bc.Skills.MagicResist = m_From.Skills.MagicResist;
m_From.CloseGump(typeof(SummonFamiliarGump));
m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell));
}
else if (entry.Type == null)
{
m_From.SendMessage("That familiar has not yet been defined.");
if ( BaseCreature.Summon( bc, m_From, m_From.Location, -1, TimeSpan.FromDays( 1.0 ) ) )
{
m_From.FixedParticles( 0x3728, 1, 10, 9910, EffectLayer.Head );
bc.PlaySound( bc.GetIdleSound() );
SummonFamiliarSpell.Table[m_From] = bc;
}
}
catch
{
}
}
}
else
{
m_From.SendLocalizedMessage( 1061825 ); // You decide not to summon a familiar.
}
}
}
}
m_From.CloseGump(typeof(SummonFamiliarGump));
m_From.SendGump(new SummonFamiliarGump(m_From, SummonFamiliarSpell.Entries, m_Spell));
}
else
{
try
{
BaseCreature bc = (BaseCreature)Activator.CreateInstance(entry.Type);
bc.Skills.MagicResist = m_From.Skills.MagicResist;
if (BaseCreature.Summon(bc, m_From, m_From.Location, -1, TimeSpan.FromDays(1.0)))
{
m_From.FixedParticles(0x3728, 1, 10, 9910, EffectLayer.Head);
bc.PlaySound(bc.GetIdleSound());
SummonFamiliarSpell.Table[m_From] = bc;
}
}
catch
{
}
}
}
else
{
m_From.SendLocalizedMessage(1061825); // You decide not to summon a familiar.
}
}
}
}

View file

@ -1,49 +1,48 @@
namespace Server.Spells.Necromancy
{
public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell
{
public abstract int Body{ get; }
public virtual int Hue => 0;
public abstract class TransformationSpell : NecromancerSpell, ITransformationSpell
{
public TransformationSpell(Mobile caster, Item scroll, SpellInfo info) : base(caster, scroll, info)
{
}
public virtual int PhysResistOffset => 0;
public virtual int FireResistOffset => 0;
public virtual int ColdResistOffset => 0;
public virtual int PoisResistOffset => 0;
public virtual int NrgyResistOffset => 0;
public override bool BlockedByHorrificBeast => false;
public abstract int Body{ get; }
public virtual int Hue => 0;
public TransformationSpell( Mobile caster, Item scroll, SpellInfo info ) : base( caster, scroll, info )
{
}
public virtual int PhysResistOffset => 0;
public virtual int FireResistOffset => 0;
public virtual int ColdResistOffset => 0;
public virtual int PoisResistOffset => 0;
public virtual int NrgyResistOffset => 0;
public override bool BlockedByHorrificBeast => false;
public virtual double TickRate => 1.0;
public override bool CheckCast()
{
if ( !TransformationSpellHelper.CheckCast( Caster, this ) )
return false;
public virtual void OnTick(Mobile m)
{
}
return base.CheckCast();
}
public virtual void DoEffect(Mobile m)
{
}
public override void OnCast()
{
TransformationSpellHelper.OnCast( Caster, this );
public virtual void RemoveEffect(Mobile m)
{
}
FinishSequence();
}
public override bool CheckCast()
{
if (!TransformationSpellHelper.CheckCast(Caster, this))
return false;
public virtual double TickRate => 1.0;
return base.CheckCast();
}
public virtual void OnTick( Mobile m )
{
}
public override void OnCast()
{
TransformationSpellHelper.OnCast(Caster, this);
public virtual void DoEffect( Mobile m )
{
}
public virtual void RemoveEffect( Mobile m )
{
}
}
}
FinishSequence();
}
}
}

View file

@ -3,49 +3,51 @@ using Server.Items;
namespace Server.Spells.Necromancy
{
public class VampiricEmbraceSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vampiric Embrace", "Rel Xen An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal,
Reagent.PigIron
);
public class VampiricEmbraceSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vampiric Embrace", "Rel Xen An Sanct",
203,
9031,
Reagent.BatWing,
Reagent.NoxCrystal,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public VampiricEmbraceSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 99.0;
public override int RequiredMana => 23;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override int Body => Caster.Female ? 745 : 744;
public override int Hue => 0x847E;
public override double RequiredSkill => 99.0;
public override int RequiredMana => 23;
public override int FireResistOffset => -25;
public override int Body => Caster.Female ? 745 : 744;
public override int Hue => 0x847E;
public VampiricEmbraceSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override int FireResistOffset => -25;
public override void GetCastSkills( out double min, out double max )
{
if ( Caster.Skills[CastSkill].Value >= RequiredSkill )
{
min = 80.0;
max = 120.0;
}
else
{
base.GetCastSkills( out min, out max );
}
}
public override void GetCastSkills(out double min, out double max)
{
if (Caster.Skills[CastSkill].Value >= RequiredSkill)
{
min = 80.0;
max = 120.0;
}
else
{
base.GetCastSkills(out min, out max);
}
}
public override void DoEffect( Mobile m )
{
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x373A, 1, 17, 1108, 7, 9914, 0 );
Effects.SendLocationParticles( EffectItem.Create( m.Location, m.Map, EffectItem.DefaultDuration ), 0x376A, 1, 22, 67, 7, 9502, 0 );
Effects.PlaySound( m.Location, m.Map, 0x4B1 );
}
}
}
public override void DoEffect(Mobile m)
{
Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x373A, 1, 17,
1108, 7, 9914, 0);
Effects.SendLocationParticles(EffectItem.Create(m.Location, m.Map, EffectItem.DefaultDuration), 0x376A, 1, 22,
67, 7, 9502, 0);
Effects.PlaySound(m.Location, m.Map, 0x4B1);
}
}
}

View file

@ -1,94 +1,95 @@
using System;
using Server.Targeting;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Spells.Necromancy
{
public class VengefulSpiritSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vengeful Spirit", "Kal Xen Bal Beh",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.PigIron
);
public class VengefulSpiritSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Vengeful Spirit", "Kal Xen Bal Beh",
203,
9031,
Reagent.BatWing,
Reagent.GraveDust,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public VengefulSpiritSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 80.0;
public override int RequiredMana => 41;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public VengefulSpiritSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override double RequiredSkill => 80.0;
public override int RequiredMana => 41;
public override void OnCast()
{
Caster.Target = new InternalTarget( this );
}
public override void OnCast()
{
Caster.Target = new InternalTarget(this);
}
public override bool CheckCast()
{
if ( !base.CheckCast() )
return false;
public override bool CheckCast()
{
if (!base.CheckCast())
return false;
if ( (Caster.Followers + 3) > Caster.FollowersMax )
{
Caster.SendLocalizedMessage( 1049645 ); // You have too many followers to summon that creature.
return false;
}
if (Caster.Followers + 3 > Caster.FollowersMax)
{
Caster.SendLocalizedMessage(1049645); // You have too many followers to summon that creature.
return false;
}
return true;
}
return true;
}
public void Target( Mobile m )
{
if ( Caster == m )
{
Caster.SendLocalizedMessage( 1061832 ); // You cannot exact vengeance on yourself.
}
else if ( CheckHSequence( m ) )
{
SpellHelper.Turn( Caster, m );
public void Target(Mobile m)
{
if (Caster == m)
{
Caster.SendLocalizedMessage(1061832); // You cannot exact vengeance on yourself.
}
else if (CheckHSequence(m))
{
SpellHelper.Turn(Caster, m);
/* Summons a Revenant which haunts the target until either the target or the Revenant is dead.
* Revenants have the ability to track down their targets wherever they may travel.
* A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster.
* The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds.
*/
/* Summons a Revenant which haunts the target until either the target or the Revenant is dead.
* Revenants have the ability to track down their targets wherever they may travel.
* A Revenant's strength is determined by the Necromancy and Spirit Speak skills of the Caster.
* The effect lasts for ((Spirit Speak skill level * 80) / 120) + 10 seconds.
*/
TimeSpan duration = TimeSpan.FromSeconds( ((GetDamageSkill( Caster ) * 80) / 120) + 10 );
TimeSpan duration = TimeSpan.FromSeconds(GetDamageSkill(Caster) * 80 / 120 + 10);
Revenant rev = new Revenant( Caster, m, duration );
Revenant rev = new Revenant(Caster, m, duration);
if ( BaseCreature.Summon( rev, false, Caster, m.Location, 0x81, TimeSpan.FromSeconds( duration.TotalSeconds + 2.0 ) ) )
rev.FixedParticles( 0x373A, 1, 15, 9909, EffectLayer.Waist );
}
if (BaseCreature.Summon(rev, false, Caster, m.Location, 0x81,
TimeSpan.FromSeconds(duration.TotalSeconds + 2.0)))
rev.FixedParticles(0x373A, 1, 15, 9909, EffectLayer.Waist);
}
FinishSequence();
}
FinishSequence();
}
private class InternalTarget : Target
{
private VengefulSpiritSpell m_Owner;
private class InternalTarget : Target
{
private VengefulSpiritSpell m_Owner;
public InternalTarget( VengefulSpiritSpell owner ) : base( Core.ML ? 10 : 12, false, TargetFlags.Harmful )
{
m_Owner = owner;
}
public InternalTarget(VengefulSpiritSpell owner) : base(Core.ML ? 10 : 12, false, TargetFlags.Harmful)
{
m_Owner = owner;
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile )
m_Owner.Target( (Mobile) o );
}
protected override void OnTarget(Mobile from, object o)
{
if (o is Mobile)
m_Owner.Target((Mobile)o);
}
protected override void OnTargetFinish( Mobile from )
{
m_Owner.FinishSequence();
}
}
}
}
protected override void OnTargetFinish(Mobile from)
{
m_Owner.FinishSequence();
}
}
}
}

View file

@ -5,105 +5,105 @@ using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class WitherSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wither", "Kal Vas An Flam",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust,
Reagent.PigIron
);
public class WitherSpell : NecromancerSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wither", "Kal Vas An Flam",
203,
9031,
Reagent.NoxCrystal,
Reagent.GraveDust,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 1.5 );
public WitherSpell(Mobile caster, Item scroll)
: base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 60.0;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(1.5);
public override int RequiredMana => 23;
public override double RequiredSkill => 60.0;
public WitherSpell( Mobile caster, Item scroll )
: base( caster, scroll, m_Info )
{
}
public override int RequiredMana => 23;
public override bool DelayedDamage => false;
public override bool DelayedDamage => false;
public override void OnCast()
{
if ( CheckSequence() )
{
/* Creates a withering frost around the Caster,
* which deals Cold Damage to all valid targets in a radius of 5 tiles.
*/
public override void OnCast()
{
if (CheckSequence())
{
/* Creates a withering frost around the Caster,
* which deals Cold Damage to all valid targets in a radius of 5 tiles.
*/
Map map = Caster.Map;
Map map = Caster.Map;
if ( map != null )
{
List<Mobile> targets = new List<Mobile>();
if (map != null)
{
List<Mobile> targets = new List<Mobile>();
BaseCreature cbc = Caster as BaseCreature;
bool isMonster = ( cbc != null && !cbc.Controlled && !cbc.Summoned );
BaseCreature cbc = Caster as BaseCreature;
bool isMonster = cbc != null && !cbc.Controlled && !cbc.Summoned;
foreach( Mobile m in Caster.GetMobilesInRange( Core.ML ? 4 : 5 ) )
{
if ( Caster != m && Caster.InLOS( m ) && ( isMonster || SpellHelper.ValidIndirectTarget( Caster, m ) ) && Caster.CanBeHarmful( m, false ) )
{
if ( isMonster )
{
if ( m is BaseCreature )
{
BaseCreature bc = (BaseCreature)m;
foreach (Mobile m in Caster.GetMobilesInRange(Core.ML ? 4 : 5))
if (Caster != m && Caster.InLOS(m) && (isMonster || SpellHelper.ValidIndirectTarget(Caster, m)) &&
Caster.CanBeHarmful(m, false))
{
if (isMonster)
{
if (m is BaseCreature)
{
BaseCreature bc = (BaseCreature)m;
if ( !bc.Controlled && !bc.Summoned && bc.Team == cbc.Team )
continue;
}
else if ( !m.Player )
{
continue;
}
}
if (!bc.Controlled && !bc.Summoned && bc.Team == cbc.Team)
continue;
}
else if (!m.Player)
{
continue;
}
}
targets.Add( m );
}
}
targets.Add(m);
}
Effects.PlaySound( Caster.Location, map, 0x1FB );
Effects.PlaySound( Caster.Location, map, 0x10B );
Effects.SendLocationParticles( EffectItem.Create( Caster.Location, map, EffectItem.DefaultDuration ), 0x37CC, 1, 40, 97, 3, 9917, 0 );
Effects.PlaySound(Caster.Location, map, 0x1FB);
Effects.PlaySound(Caster.Location, map, 0x10B);
Effects.SendLocationParticles(EffectItem.Create(Caster.Location, map, EffectItem.DefaultDuration),
0x37CC, 1, 40, 97, 3, 9917, 0);
for( int i = 0; i < targets.Count; ++i )
{
Mobile m = targets[ i ];
for (int i = 0; i < targets.Count; ++i)
{
Mobile m = targets[i];
Caster.DoHarmful( m );
m.FixedParticles( 0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255 );
Caster.DoHarmful(m);
m.FixedParticles(0x374A, 1, 15, 9502, 97, 3, (EffectLayer)255);
double damage = Utility.RandomMinMax( 30, 35 );
double damage = Utility.RandomMinMax(30, 35);
damage *= ( 300 + ( m.Karma / 100 ) + ( GetDamageSkill( Caster ) * 10 ) );
damage /= 1000;
damage *= 300 + m.Karma / 100 + GetDamageSkill(Caster) * 10;
damage /= 1000;
int sdiBonus = AosAttributes.GetValue( Caster, AosAttribute.SpellDamage );
int sdiBonus = AosAttributes.GetValue(Caster, AosAttribute.SpellDamage);
// PvP spell damage increase cap of 15% from an item<65>s magic property in Publish 33(SE)
if ( Core.SE && m.Player && Caster.Player && sdiBonus > 15 )
sdiBonus = 15;
// PvP spell damage increase cap of 15% from an item<65>s magic property in Publish 33(SE)
if (Core.SE && m.Player && Caster.Player && sdiBonus > 15)
sdiBonus = 15;
damage *= ( 100 + sdiBonus );
damage /= 100;
damage *= 100 + sdiBonus;
damage /= 100;
// TODO: cap?
//if ( damage > 40 )
// damage = 40;
// TODO: cap?
//if ( damage > 40 )
// damage = 40;
SpellHelper.Damage( this, m, damage, 0, 0, 100, 0, 0 );
}
}
}
SpellHelper.Damage(this, m, damage, 0, 0, 100, 0, 0);
}
}
}
FinishSequence();
}
}
}
FinishSequence();
}
}
}

View file

@ -3,47 +3,47 @@ using Server.Mobiles;
namespace Server.Spells.Necromancy
{
public class WraithFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wraith Form", "Rel Xen Um",
203,
9031,
Reagent.NoxCrystal,
Reagent.PigIron
);
public class WraithFormSpell : TransformationSpell
{
private static SpellInfo m_Info = new SpellInfo(
"Wraith Form", "Rel Xen Um",
203,
9031,
Reagent.NoxCrystal,
Reagent.PigIron
);
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds( 2.0 );
public WraithFormSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info)
{
}
public override double RequiredSkill => 20.0;
public override int RequiredMana => 17;
public override TimeSpan CastDelayBase => TimeSpan.FromSeconds(2.0);
public override int Body => Caster.Female ? 747 : 748;
public override int Hue => Caster.Female ? 0 : 0x4001;
public override double RequiredSkill => 20.0;
public override int RequiredMana => 17;
public override int PhysResistOffset => +15;
public override int FireResistOffset => -5;
public override int ColdResistOffset => 0;
public override int PoisResistOffset => 0;
public override int NrgyResistOffset => -5;
public override int Body => Caster.Female ? 747 : 748;
public override int Hue => Caster.Female ? 0 : 0x4001;
public WraithFormSpell( Mobile caster, Item scroll ) : base( caster, scroll, m_Info )
{
}
public override int PhysResistOffset => +15;
public override int FireResistOffset => -5;
public override int ColdResistOffset => 0;
public override int PoisResistOffset => 0;
public override int NrgyResistOffset => -5;
public override void DoEffect( Mobile m )
{
if ( m is PlayerMobile )
((PlayerMobile)m).IgnoreMobiles = true;
public override void DoEffect(Mobile m)
{
if (m is PlayerMobile)
((PlayerMobile)m).IgnoreMobiles = true;
m.PlaySound( 0x17F );
m.FixedParticles( 0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist );
}
m.PlaySound(0x17F);
m.FixedParticles(0x374A, 1, 15, 9902, 1108, 4, EffectLayer.Waist);
}
public override void RemoveEffect( Mobile m )
{
if ( m is PlayerMobile && m.AccessLevel == AccessLevel.Player )
((PlayerMobile)m).IgnoreMobiles = false;
}
}
}
public override void RemoveEffect(Mobile m)
{
if (m is PlayerMobile && m.AccessLevel == AccessLevel.Player)
((PlayerMobile)m).IgnoreMobiles = false;
}
}
}