Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
54
Scripts/Mobiles/AI/AIControlMobileTarget.cs
Normal file
54
Scripts/Mobiles/AI/AIControlMobileTarget.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
#region References
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Targets
|
||||
{
|
||||
public class AIControlMobileTarget : Target
|
||||
{
|
||||
private readonly List<BaseAI> m_List;
|
||||
private readonly OrderType m_Order;
|
||||
private readonly BaseCreature m_Mobile;
|
||||
|
||||
public AIControlMobileTarget(BaseAI ai, OrderType order)
|
||||
: base(-1, false, (order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None))
|
||||
{
|
||||
m_List = new List<BaseAI>();
|
||||
m_Order = order;
|
||||
|
||||
AddAI(ai);
|
||||
m_Mobile = ai.m_Mobile;
|
||||
}
|
||||
|
||||
public OrderType Order { get { return m_Order; } }
|
||||
|
||||
public void AddAI(BaseAI ai)
|
||||
{
|
||||
if (!m_List.Contains(ai))
|
||||
m_List.Add(ai);
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object o)
|
||||
{
|
||||
if (o is IDamageable)
|
||||
{
|
||||
var dam = o as IDamageable;
|
||||
|
||||
for (var i = 0; i < m_List.Count; ++i)
|
||||
m_List[i].EndPickTarget(from, dam, m_Order);
|
||||
}
|
||||
else if (o is MoonglowDonationBox && m_Order == OrderType.Transfer && from is PlayerMobile)
|
||||
{
|
||||
var pm = (PlayerMobile)from;
|
||||
var box = (MoonglowDonationBox)o;
|
||||
|
||||
pm.SendGump(new ConfirmTransferPetGump(box, from.Location, m_Mobile));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Scripts/Mobiles/AI/AnimalAI.cs
Normal file
136
Scripts/Mobiles/AI/AnimalAI.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
|
||||
|
||||
// Ideas
|
||||
// When you run on animals the panic
|
||||
// When if ( distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills[SkillName.AnimalTaming].Value )
|
||||
// More your close, the more it can panic
|
||||
/*
|
||||
* AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI...
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class AnimalAI : BaseAI
|
||||
{
|
||||
public AnimalAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
// Old:
|
||||
#if false
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay( "There is something near, I go away" );
|
||||
Action = ActionType.Backoff;
|
||||
}
|
||||
else if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null )
|
||||
{
|
||||
m_Mobile.DebugSay( "I am hurt or being attacked, I flee" );
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
// New, only flee @ 10%
|
||||
var hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
|
||||
|
||||
if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health
|
||||
{
|
||||
m_Mobile.DebugSay("I am low on health!");
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var combatant = m_Mobile.Combatant;
|
||||
|
||||
if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is gone..");
|
||||
|
||||
Action = ActionType.Wander;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
m_Mobile.DebugSay("I cannot find {0}", combatant.Name);
|
||||
|
||||
Action = ActionType.Wander;
|
||||
|
||||
return true;
|
||||
}
|
||||
m_Mobile.DebugSay("I should be closer to {0}", combatant.Name);
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
var hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
|
||||
|
||||
if (hitPercent < 0.1)
|
||||
{
|
||||
m_Mobile.DebugSay("I am low on health!");
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionBackoff()
|
||||
{
|
||||
var hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
|
||||
|
||||
if (!m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee) // Less than 10% health
|
||||
{
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true))
|
||||
{
|
||||
if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2))
|
||||
{
|
||||
m_Mobile.DebugSay("Well, here I am safe");
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I have lost my focus, lets relax");
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Scripts/Mobiles/AI/ArcherAI.cs
Normal file
121
Scripts/Mobiles/AI/ArcherAI.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class ArcherAI : BaseAI
|
||||
{
|
||||
public ArcherAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I have no combatant");
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0} and I will attack", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
return base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant;
|
||||
|
||||
if (c == null || c.Deleted || !c.Alive || (c is Mobile && ((Mobile)c).IsDeadBondedPet))
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is deleted");
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Core.TickCount - m_Mobile.LastMoveTime > 1000)
|
||||
{
|
||||
if (WalkMobileRange(c, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(c.Location);
|
||||
}
|
||||
else if (c != null)
|
||||
{
|
||||
m_Mobile.DebugSay("I am still not in range of {0}", c.Name);
|
||||
|
||||
if ((int)m_Mobile.GetDistanceToSqrt(c) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
m_Mobile.DebugSay("I have lost {0}", c.Name);
|
||||
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if ( m_Mobile.Hits > (m_Mobile.HitsMax / 2))
|
||||
{
|
||||
// If I have a target, go back and fight them
|
||||
if (c != null && m_Mobile.GetDistanceToSqrt(c) <= m_Mobile.RangePerception * 2)
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, reengaging {0}", c.Name);
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, my guard is up");
|
||||
Action = ActionType.Guard;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionFlee();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
3127
Scripts/Mobiles/AI/BaseAI.cs
Normal file
3127
Scripts/Mobiles/AI/BaseAI.cs
Normal file
File diff suppressed because it is too large
Load Diff
82
Scripts/Mobiles/AI/BerserkAI.cs
Normal file
82
Scripts/Mobiles/AI/BerserkAI.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class BerserkAI : BaseAI
|
||||
{
|
||||
public BerserkAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I have No Combatant");
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Closest, false, true, true))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I have detected " + m_Mobile.FocusMob.Name + " and I will attack");
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
if (m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is deleted");
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Combatant != null)
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I am still not in range of " + m_Mobile.Combatant.Name);
|
||||
|
||||
if ((int)m_Mobile.GetDistanceToSqrt(m_Mobile.Combatant) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I have lost " + m_Mobile.Combatant.Name);
|
||||
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
177
Scripts/Mobiles/AI/HealerAI.cs
Normal file
177
Scripts/Mobiles/AI/HealerAI.cs
Normal file
@@ -0,0 +1,177 @@
|
||||
#region References
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Spells.Second;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class HealerAI : BaseAI
|
||||
{
|
||||
private static readonly NeedDelegate m_Cure = NeedCure;
|
||||
private static readonly NeedDelegate m_GHeal = NeedGHeal;
|
||||
private static readonly NeedDelegate m_LHeal = NeedLHeal;
|
||||
private static readonly NeedDelegate[] m_ACure = {m_Cure};
|
||||
private static readonly NeedDelegate[] m_AGHeal = {m_GHeal};
|
||||
private static readonly NeedDelegate[] m_ALHeal = {m_LHeal};
|
||||
private static readonly NeedDelegate[] m_All = {m_Cure, m_GHeal, m_LHeal};
|
||||
|
||||
public HealerAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
private delegate bool NeedDelegate(Mobile m);
|
||||
|
||||
public override bool Think()
|
||||
{
|
||||
if (m_Mobile.Deleted)
|
||||
return false;
|
||||
|
||||
var targ = m_Mobile.Target;
|
||||
|
||||
if (targ != null)
|
||||
{
|
||||
if (targ is CureSpell.InternalTarget)
|
||||
{
|
||||
ProcessTarget(targ, m_ACure);
|
||||
}
|
||||
else if (targ is GreaterHealSpell.InternalTarget)
|
||||
{
|
||||
ProcessTarget(targ, m_AGHeal);
|
||||
}
|
||||
else if (targ is HealSpell.InternalTarget)
|
||||
{
|
||||
ProcessTarget(targ, m_ALHeal);
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var toHelp = Find(m_All);
|
||||
|
||||
if (toHelp != null)
|
||||
{
|
||||
if (NeedCure(toHelp))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} needs a cure", toHelp.Name);
|
||||
|
||||
if (!(new CureSpell(m_Mobile, null)).Cast())
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (NeedGHeal(toHelp))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} needs a greater heal", toHelp.Name);
|
||||
|
||||
if (!(new GreaterHealSpell(m_Mobile, null)).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (NeedLHeal(toHelp))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} needs a lesser heal", toHelp.Name);
|
||||
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, FightMode.Weakest, false, true, false))
|
||||
{
|
||||
WalkMobileRange(m_Mobile.FocusMob, 1, false, 4, 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
WalkRandomInHome(3, 2, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool NeedCure(Mobile m)
|
||||
{
|
||||
return m.Poisoned;
|
||||
}
|
||||
|
||||
private static bool NeedGHeal(Mobile m)
|
||||
{
|
||||
return m.Hits < m.HitsMax - 40;
|
||||
}
|
||||
|
||||
private static bool NeedLHeal(Mobile m)
|
||||
{
|
||||
return m.Hits < m.HitsMax - 10;
|
||||
}
|
||||
|
||||
private void ProcessTarget(Target targ, NeedDelegate[] func)
|
||||
{
|
||||
var toHelp = Find(func);
|
||||
|
||||
if (toHelp != null)
|
||||
{
|
||||
if (targ.Range != -1 && !m_Mobile.InRange(toHelp, targ.Range))
|
||||
{
|
||||
DoMove(m_Mobile.GetDirectionTo(toHelp) | Direction.Running);
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Invoke(m_Mobile, toHelp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
|
||||
private Mobile Find(params NeedDelegate[] funcs)
|
||||
{
|
||||
if (m_Mobile.Deleted)
|
||||
return null;
|
||||
|
||||
var map = m_Mobile.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
var prio = 0.0;
|
||||
Mobile found = null;
|
||||
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (!m_Mobile.CanSee(m) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team)
|
||||
continue;
|
||||
|
||||
for (var i = 0; i < funcs.Length; ++i)
|
||||
{
|
||||
if (funcs[i](m))
|
||||
{
|
||||
var val = -m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (found == null || val > prio)
|
||||
{
|
||||
prio = val;
|
||||
found = m;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
1606
Scripts/Mobiles/AI/Magical AI/MageAI.cs
Normal file
1606
Scripts/Mobiles/AI/Magical AI/MageAI.cs
Normal file
File diff suppressed because it is too large
Load Diff
172
Scripts/Mobiles/AI/Magical AI/MysticAI.cs
Normal file
172
Scripts/Mobiles/AI/Magical AI/MysticAI.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
#region References
|
||||
using Server.Spells;
|
||||
using Server.Spells.Mysticism;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class MysticAI : MageAI
|
||||
{
|
||||
public override SkillName CastSkill { get { return SkillName.Mysticism; } }
|
||||
|
||||
public override bool UsesMagery
|
||||
{
|
||||
get { return m_Mobile.Skills[SkillName.Magery].Base >= 20.0 && !m_Mobile.Controlled; }
|
||||
}
|
||||
|
||||
public MysticAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override Spell GetRandomDamageSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomDamageSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 50)
|
||||
select = 5;
|
||||
else if (mana >= 20)
|
||||
select = 3;
|
||||
else if (mana >= 9)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new NetherBoltSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new EagleStrikeSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new BombardSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new HailStormSpell(m_Mobile, null);
|
||||
case 4:
|
||||
return new NetherCycloneSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomCurseSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomCurseSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 40)
|
||||
select = 4;
|
||||
else if (mana >= 14)
|
||||
select = 3;
|
||||
else if (mana >= 8)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new PurgeMagicSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new SleepSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new MassSleepSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new SpellPlagueSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetHealSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetHealSpell();
|
||||
}
|
||||
|
||||
if (m_Mobile.Mana >= 20)
|
||||
return new CleansingWindsSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetCureSpell()
|
||||
{
|
||||
if (UsesMagery)
|
||||
{
|
||||
return base.GetCureSpell();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomBuffSpell()
|
||||
{
|
||||
if (UsesMagery)
|
||||
{
|
||||
return base.GetRandomBuffSpell();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell RandomCombatSpell()
|
||||
{
|
||||
var spell = CheckCastHealingSpell();
|
||||
|
||||
if (spell != null)
|
||||
return spell;
|
||||
|
||||
switch (Utility.Random(6))
|
||||
{
|
||||
case 0: // Curse
|
||||
{
|
||||
m_Mobile.DebugSay("Cursing Thou!");
|
||||
spell = GetRandomCurseSpell();
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5: // damage
|
||||
{
|
||||
m_Mobile.DebugSay("Just doing damage");
|
||||
spell = GetRandomDamageSpell();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
protected override bool ProcessTarget()
|
||||
{
|
||||
var t = m_Mobile.Target;
|
||||
|
||||
if (t == null)
|
||||
return false;
|
||||
|
||||
if (t is HailStormSpell.InternalTarget || t is NetherCycloneSpell.InternalTarget)
|
||||
{
|
||||
if (m_Mobile.Combatant != null && m_Mobile.InRange(m_Mobile.Combatant.Location, 8))
|
||||
{
|
||||
t.Invoke(m_Mobile, m_Mobile.Combatant);
|
||||
}
|
||||
else
|
||||
t.Invoke(m_Mobile, m_Mobile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.ProcessTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Scripts/Mobiles/AI/Magical AI/NecroAI.cs
Normal file
107
Scripts/Mobiles/AI/Magical AI/NecroAI.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
#region References
|
||||
using Server.Spells;
|
||||
using Server.Spells.Necromancy;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class NecroAI : MageAI
|
||||
{
|
||||
public override SkillName CastSkill { get { return SkillName.Necromancy; } }
|
||||
public override bool UsesMagery { get { return false; } }
|
||||
|
||||
public NecroAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override Spell GetRandomDamageSpell()
|
||||
{
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 29)
|
||||
select = 4;
|
||||
else if (mana >= 23)
|
||||
select = 3;
|
||||
else if (mana >= 17)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new PainSpikeSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new PoisonStrikeSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new WitherSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new StrangleSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomSummonSpell()
|
||||
{
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.Mana >= 23)
|
||||
{
|
||||
return new AnimateDeadSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomCurseSpell()
|
||||
{
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 17)
|
||||
select = 5;
|
||||
else if (mana >= 13)
|
||||
select = 4;
|
||||
else if (mana >= 11)
|
||||
select = 3;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new CurseWeaponSpell(m_Mobile, null);
|
||||
case 1:
|
||||
Spell spell;
|
||||
|
||||
if (NecroMageAI.CheckCastCorpseSkin(m_Mobile))
|
||||
spell = new CorpseSkinSpell(m_Mobile, null);
|
||||
else
|
||||
spell = new CurseWeaponSpell(m_Mobile, null);
|
||||
|
||||
return spell;
|
||||
case 2:
|
||||
return new EvilOmenSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new BloodOathSpell(m_Mobile, null);
|
||||
case 4:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetCureSpell()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomBuffSpell()
|
||||
{
|
||||
return new CurseWeaponSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
public override Spell GetHealSpell()
|
||||
{
|
||||
m_Mobile.UseSkill(SkillName.SpiritSpeak);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
190
Scripts/Mobiles/AI/Magical AI/NecromageAI.cs
Normal file
190
Scripts/Mobiles/AI/Magical AI/NecromageAI.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
#region References
|
||||
using Server.Spells;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Spells.Second;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class NecroMageAI : MageAI
|
||||
{
|
||||
/*private Mobile m_Animated;
|
||||
|
||||
public Mobile Animated
|
||||
{
|
||||
get { return m_Animated; }
|
||||
set { m_Animated = value; }
|
||||
}*/
|
||||
|
||||
public override SkillName CastSkill { get { return SkillName.Magery; } }
|
||||
|
||||
public NecroMageAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override Spell GetRandomDamageSpell()
|
||||
{
|
||||
if (0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomDamageSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 29)
|
||||
select = 4;
|
||||
else if (mana >= 23)
|
||||
select = 3;
|
||||
else if (mana >= 17)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new PainSpikeSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new PoisonStrikeSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new WitherSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new StrangleSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomCurseSpell()
|
||||
{
|
||||
if (0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomCurseSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 17)
|
||||
select = 4;
|
||||
else if (mana >= 13)
|
||||
select = 3;
|
||||
else if (mana >= 11)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
Spell spell;
|
||||
|
||||
if (CheckCastCorpseSkin(m_Mobile))
|
||||
spell = new CorpseSkinSpell(m_Mobile, null);
|
||||
else
|
||||
spell = new EvilOmenSpell(m_Mobile, null);
|
||||
|
||||
return spell;
|
||||
case 1:
|
||||
return new EvilOmenSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new BloodOathSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomBuffSpell()
|
||||
{
|
||||
if (0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomBuffSpell();
|
||||
}
|
||||
|
||||
if (!SmartAI && Utility.RandomBool())
|
||||
{
|
||||
return new CurseWeaponSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return GetRandomSummonSpell();
|
||||
}
|
||||
|
||||
public override Spell GetRandomSummonSpell()
|
||||
{
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.Mana >= 23)
|
||||
{
|
||||
return new AnimateDeadSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override Spell CheckCastHealingSpell()
|
||||
{
|
||||
if (m_Mobile.Summoned || m_Mobile.Hits >= m_Mobile.HitsMax)
|
||||
return null;
|
||||
|
||||
if (0.1 > Utility.RandomDouble())
|
||||
m_Mobile.UseSkill(SkillName.SpiritSpeak);
|
||||
else
|
||||
return base.CheckCastHealingSpell();
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (!m_Mobile.Summoned)
|
||||
{
|
||||
if (ScaleBySkill(HealChance, SkillName.Necromancy) > Utility.RandomDouble() &&
|
||||
m_Mobile.Hits < m_Mobile.HitsMax - 30)
|
||||
{
|
||||
m_Mobile.UseSkill(SkillName.SpiritSpeak);
|
||||
}
|
||||
else if (ScaleBySkill(HealChance, SkillName.Magery) > Utility.RandomDouble())
|
||||
{
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
if (!new GreaterHealSpell(m_Mobile, null).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
{
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool CheckCastCorpseSkin(BaseCreature bc)
|
||||
{
|
||||
return bc.ColdDamage != 100 && bc.PhysicalDamage != 100;
|
||||
}
|
||||
}
|
||||
}
|
||||
202
Scripts/Mobiles/AI/Magical AI/NinjaAI.cs
Normal file
202
Scripts/Mobiles/AI/Magical AI/NinjaAI.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Ninjitsu;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class NinjaAI : MeleeAI
|
||||
{
|
||||
private DateTime m_NextCastTime;
|
||||
private DateTime m_NextRanged;
|
||||
|
||||
public NinjaAI(BaseCreature bc)
|
||||
: base(bc)
|
||||
{
|
||||
m_NextCastTime = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private void TryPerformHide()
|
||||
{
|
||||
if (!m_Mobile.Alive || m_Mobile.Deleted)
|
||||
return;
|
||||
|
||||
if (!m_Mobile.Hidden && Core.TickCount - m_Mobile.NextSkillTime >= 0)
|
||||
{
|
||||
var chance = 0.05;
|
||||
|
||||
if (m_Mobile.Hits < 20)
|
||||
chance = 0.10;
|
||||
|
||||
if (m_Mobile.Poisoned)
|
||||
chance = 0.01;
|
||||
|
||||
if (Utility.RandomDouble() < chance)
|
||||
HideSelf();
|
||||
}
|
||||
}
|
||||
|
||||
private void HideSelf()
|
||||
{
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration),
|
||||
0x3728,
|
||||
10,
|
||||
10,
|
||||
2023);
|
||||
|
||||
m_Mobile.PlaySound(0x22F);
|
||||
m_Mobile.Hidden = true;
|
||||
|
||||
m_Mobile.UseSkill(SkillName.Stealth);
|
||||
}
|
||||
|
||||
public virtual SpecialMove GetHiddenSpecialMove()
|
||||
{
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value;
|
||||
|
||||
if (skill < 40)
|
||||
return null;
|
||||
|
||||
if (skill >= 60)
|
||||
{
|
||||
//return .5 > Utility.RandomDouble() ? new SupriseAttack() : new Backstab();
|
||||
return .5 > Utility.RandomDouble() ? SpellRegistry.GetSpecialMove(504) : SpellRegistry.GetSpecialMove(505);
|
||||
}
|
||||
|
||||
return SpellRegistry.GetSpecialMove(505); //new Backstab();
|
||||
}
|
||||
|
||||
public virtual SpecialMove GetSpecialMove()
|
||||
{
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value;
|
||||
|
||||
if (skill < 40)
|
||||
return null;
|
||||
|
||||
var avail = 1;
|
||||
|
||||
if (skill >= 85)
|
||||
avail = 3;
|
||||
else if (skill >= 80)
|
||||
avail = 2;
|
||||
|
||||
switch (Utility.Random(avail))
|
||||
{
|
||||
case 0:
|
||||
return SpellRegistry.GetSpecialMove(500); //new FocusAttack();
|
||||
case 1:
|
||||
return SpellRegistry.GetSpecialMove(503); //new KiAttack();
|
||||
case 2:
|
||||
return SpellRegistry.GetSpecialMove(501); //new DeathStrike();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DoRangedAttack()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (c == null)
|
||||
return;
|
||||
|
||||
var list = new List<INinjaWeapon>();
|
||||
var d = (int)m_Mobile.GetDistanceToSqrt(c.Location);
|
||||
|
||||
foreach (var item in m_Mobile.Items)
|
||||
if (item is INinjaWeapon && ((INinjaWeapon)item).UsesRemaining > 0 && d >= ((INinjaWeapon)item).WeaponMinRange &&
|
||||
d <= ((INinjaWeapon)item).WeaponMaxRange)
|
||||
list.Add(item as INinjaWeapon);
|
||||
|
||||
if (m_Mobile.Backpack != null)
|
||||
{
|
||||
foreach (var item in m_Mobile.Backpack.Items)
|
||||
if (item is INinjaWeapon && ((INinjaWeapon)item).UsesRemaining > 0 && d >= ((INinjaWeapon)item).WeaponMinRange &&
|
||||
d <= ((INinjaWeapon)item).WeaponMaxRange)
|
||||
list.Add(item as INinjaWeapon);
|
||||
}
|
||||
|
||||
if (list.Count > 0)
|
||||
{
|
||||
var toUse = list[Utility.Random(list.Count)];
|
||||
|
||||
if (toUse != null)
|
||||
NinjaWeapon.Shoot(m_Mobile, c, toUse);
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
|
||||
m_NextRanged = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 120));
|
||||
}
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
base.DoActionWander();
|
||||
|
||||
if (m_Mobile.Combatant == null)
|
||||
TryPerformHide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
base.DoActionCombat();
|
||||
|
||||
if (m_Mobile.Combatant == null)
|
||||
return true;
|
||||
|
||||
var special = SpecialMove.GetCurrentMove(m_Mobile);
|
||||
|
||||
if (special == null && m_NextCastTime < DateTime.UtcNow && 0.05 > Utility.RandomDouble())
|
||||
{
|
||||
if (0.05 > Utility.RandomDouble())
|
||||
{
|
||||
new MirrorImage(m_Mobile, null).Cast();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Hidden)
|
||||
special = GetHiddenSpecialMove();
|
||||
else
|
||||
special = GetSpecialMove();
|
||||
|
||||
if (special != null)
|
||||
{
|
||||
SpecialMove.SetCurrentMove(m_Mobile, special);
|
||||
m_NextCastTime = DateTime.UtcNow + GetCastDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_NextRanged < DateTime.UtcNow && 0.08 > Utility.RandomDouble())
|
||||
DoRangedAttack();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
base.DoActionFlee();
|
||||
TryPerformHide();
|
||||
return true;
|
||||
}
|
||||
|
||||
public TimeSpan GetCastDelay()
|
||||
{
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value;
|
||||
|
||||
if (skill >= 85)
|
||||
return TimeSpan.FromSeconds(15);
|
||||
if (skill > 40)
|
||||
return TimeSpan.FromSeconds(30);
|
||||
|
||||
return TimeSpan.FromSeconds(45);
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Scripts/Mobiles/AI/Magical AI/PaladinAI.cs
Normal file
85
Scripts/Mobiles/AI/Magical AI/PaladinAI.cs
Normal file
@@ -0,0 +1,85 @@
|
||||
#region References
|
||||
using Server.Spells;
|
||||
using Server.Spells.Chivalry;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class PaladinAI : MageAI
|
||||
{
|
||||
public override SkillName CastSkill { get { return SkillName.Chivalry; } }
|
||||
public override bool UsesMagery { get { return false; } }
|
||||
public override double HealChance { get { return .1; } }
|
||||
|
||||
public PaladinAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override Spell GetRandomDamageSpell()
|
||||
{
|
||||
if (m_Mobile.Mana > 10 && 0.1 > Utility.RandomDouble())
|
||||
return new HolyLightSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomCurseSpell()
|
||||
{
|
||||
if (m_Mobile.Mana > 10)
|
||||
return new DispelEvilSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomBuffSpell()
|
||||
{
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 15)
|
||||
select = 3;
|
||||
|
||||
if (mana >= 20 && !EnemyOfOneSpell.UnderEffect(m_Mobile))
|
||||
select = 4;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new RemoveCurseSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new DivineFurySpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new ConsecrateWeaponSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new EnemyOfOneSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return new ConsecrateWeaponSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
public override Spell GetHealSpell()
|
||||
{
|
||||
if (m_Mobile.Mana > 10)
|
||||
return new CloseWoundsSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetCureSpell()
|
||||
{
|
||||
if (m_Mobile.Mana > 10)
|
||||
return new CleanseByFireSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override bool ProcessTarget()
|
||||
{
|
||||
if (m_Mobile.Target == null)
|
||||
return false;
|
||||
|
||||
m_Mobile.Target.Invoke(m_Mobile, m_Mobile);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
129
Scripts/Mobiles/AI/Magical AI/SamuraiAI.cs
Normal file
129
Scripts/Mobiles/AI/Magical AI/SamuraiAI.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Spells;
|
||||
using Server.Spells.Bushido;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class SamuraiAI : MeleeAI
|
||||
{
|
||||
private DateTime m_NextCastTime;
|
||||
private DateTime m_NextSpecial;
|
||||
|
||||
public SamuraiAI(BaseCreature bc)
|
||||
: base(bc)
|
||||
{
|
||||
m_NextCastTime = DateTime.UtcNow;
|
||||
m_NextSpecial = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public virtual SpecialMove GetSpecialMove()
|
||||
{
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Bushido].Value;
|
||||
|
||||
if (skill <= 50)
|
||||
return null;
|
||||
|
||||
if (m_Mobile.Combatant != null && m_Mobile.Combatant.Hits <= 10 && skill >= 25)
|
||||
return SpellRegistry.GetSpecialMove(400); //new HonerableExecution();
|
||||
if (skill >= 70 && CheckForMomentumStrike() && 0.5 > Utility.RandomDouble())
|
||||
return SpellRegistry.GetSpecialMove(405); //new MomentumStrike();
|
||||
return SpellRegistry.GetSpecialMove(404); // new LightningStrike();
|
||||
}
|
||||
|
||||
private bool CheckForMomentumStrike()
|
||||
{
|
||||
var count = 0;
|
||||
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(1);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m.CanBeHarmful(m_Mobile) && m != m_Mobile)
|
||||
count++;
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return count > 1;
|
||||
}
|
||||
|
||||
public virtual Spell GetRandomSpell()
|
||||
{
|
||||
// 25 - Confidence
|
||||
// 40 - Counter Attack
|
||||
// 60 - Evasion
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Bushido].Value;
|
||||
|
||||
if (skill < 25)
|
||||
return null;
|
||||
|
||||
var avail = 1;
|
||||
|
||||
if (skill >= 60)
|
||||
avail = 3;
|
||||
else if (skill >= 40)
|
||||
avail = 2;
|
||||
|
||||
switch (Utility.Random(avail))
|
||||
{
|
||||
case 0:
|
||||
return new Confidence(m_Mobile, null);
|
||||
case 1:
|
||||
return new CounterAttack(m_Mobile, null);
|
||||
case 2:
|
||||
return new Evasion(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
base.DoActionCombat();
|
||||
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (c != null)
|
||||
{
|
||||
var move = SpecialMove.GetCurrentMove(m_Mobile);
|
||||
|
||||
if (move == null && m_NextSpecial < DateTime.UtcNow && 0.05 > Utility.RandomDouble())
|
||||
{
|
||||
move = GetSpecialMove();
|
||||
|
||||
if (move != null)
|
||||
{
|
||||
SpecialMove.SetCurrentMove(m_Mobile, move);
|
||||
m_NextSpecial = DateTime.UtcNow + GetCastDelay();
|
||||
}
|
||||
}
|
||||
else if (m_Mobile.Spell == null && m_NextCastTime < DateTime.UtcNow && 0.05 > Utility.RandomDouble())
|
||||
{
|
||||
var spell = GetRandomSpell();
|
||||
|
||||
if (spell != null)
|
||||
{
|
||||
spell.Cast();
|
||||
m_NextCastTime = DateTime.UtcNow + GetCastDelay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public TimeSpan GetCastDelay()
|
||||
{
|
||||
var skill = (int)m_Mobile.Skills[SkillName.Bushido].Value;
|
||||
|
||||
if (skill >= 60)
|
||||
return TimeSpan.FromSeconds(15);
|
||||
if (skill > 25)
|
||||
return TimeSpan.FromSeconds(30);
|
||||
|
||||
return TimeSpan.FromSeconds(45);
|
||||
}
|
||||
}
|
||||
}
|
||||
820
Scripts/Mobiles/AI/Magical AI/SpellbinderAI.cs
Normal file
820
Scripts/Mobiles/AI/Magical AI/SpellbinderAI.cs
Normal file
@@ -0,0 +1,820 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Spells;
|
||||
using Server.Spells.Fifth;
|
||||
using Server.Spells.First;
|
||||
using Server.Spells.Fourth;
|
||||
using Server.Spells.Necromancy;
|
||||
using Server.Spells.Second;
|
||||
using Server.Spells.Seventh;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Spells.Third;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class SpellbinderAI : BaseAI
|
||||
{
|
||||
private static readonly int[] m_Offsets =
|
||||
{
|
||||
-1, -1, -1, 0, -1, 1, 0, -1, 0, 1, 1, -1, 1, 0, 1, 1, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -1, -2, -1, 2, 0, -2, 0,
|
||||
2, 1, -2, 1, 2, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2
|
||||
};
|
||||
|
||||
private const double HealChance = 0.05; // 5% chance to heal at gm necromancy, uses spirit speak healing
|
||||
private const double TeleportChance = 0.05; // 5% chance to teleport at gm magery
|
||||
private const double DispelChance = 0.75; // 75% chance to dispel at gm magery
|
||||
private DateTime m_NextCastTime;
|
||||
private DateTime m_NextHealTime = DateTime.UtcNow;
|
||||
|
||||
public SpellbinderAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool Think()
|
||||
{
|
||||
if (m_Mobile.Deleted)
|
||||
return false;
|
||||
|
||||
var targ = m_Mobile.Target;
|
||||
|
||||
if (targ != null)
|
||||
{
|
||||
ProcessTarget(targ);
|
||||
|
||||
return true;
|
||||
}
|
||||
return base.Think();
|
||||
}
|
||||
|
||||
public virtual double ScaleByNecromancy(double v)
|
||||
{
|
||||
return m_Mobile.Skills[SkillName.Necromancy].Value * v * 0.01;
|
||||
}
|
||||
|
||||
public virtual double ScaleByMagery(double v)
|
||||
{
|
||||
return m_Mobile.Skills[SkillName.Magery].Value * v * 0.01;
|
||||
}
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
m_NextCastTime = DateTime.UtcNow;
|
||||
}
|
||||
else if (m_Mobile.Mana < m_Mobile.ManaMax)
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to meditate");
|
||||
|
||||
m_Mobile.UseSkill(SkillName.Meditation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am wandering");
|
||||
|
||||
m_Mobile.Warmode = false;
|
||||
|
||||
base.DoActionWander();
|
||||
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (!m_Mobile.Summoned)
|
||||
{
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
if (!new GreaterHealSpell(m_Mobile, null).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
{
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RunTo(Mobile m)
|
||||
{
|
||||
if (m.Paralyzed || m.Frozen)
|
||||
{
|
||||
if (m_Mobile.InRange(m, 1))
|
||||
RunFrom(m);
|
||||
else if (!m_Mobile.InRange(m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2) && !MoveTo(m, true, 1))
|
||||
OnFailedMove();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!m_Mobile.InRange(m, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!MoveTo(m, true, 1))
|
||||
OnFailedMove();
|
||||
}
|
||||
else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1))
|
||||
{
|
||||
RunFrom(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RunFrom(IDamageable m)
|
||||
{
|
||||
Run((Direction)((int)m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask);
|
||||
}
|
||||
|
||||
public void OnFailedMove()
|
||||
{
|
||||
if (!m_Mobile.DisallowAllMoves && ScaleByMagery(TeleportChance) > Utility.RandomDouble())
|
||||
{
|
||||
if (m_Mobile.Target != null)
|
||||
m_Mobile.Target.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
|
||||
new TeleportSpell(m_Mobile, null).Cast();
|
||||
|
||||
m_Mobile.DebugSay("I am stuck, I'm going to try teleporting away");
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stuck");
|
||||
}
|
||||
}
|
||||
|
||||
public void Run(Direction d)
|
||||
{
|
||||
if ((m_Mobile.Spell != null && m_Mobile.Spell.IsCasting) || !m_Mobile.CanMove || m_Mobile.Paralyzed ||
|
||||
m_Mobile.Frozen || m_Mobile.DisallowAllMoves)
|
||||
return;
|
||||
|
||||
m_Mobile.Direction = d | Direction.Running;
|
||||
|
||||
if (!DoMove(m_Mobile.Direction, true))
|
||||
OnFailedMove();
|
||||
}
|
||||
|
||||
public virtual Spell GetRandomCurseSpell()
|
||||
{
|
||||
var necro = (int)((m_Mobile.Skills[SkillName.Necromancy].Value + 50.0) / (100.0 / 7.0));
|
||||
var mage = (int)((m_Mobile.Skills[SkillName.Magery].Value + 50.0) / (100.0 / 7.0));
|
||||
|
||||
if (mage < 1)
|
||||
mage = 1;
|
||||
|
||||
if (necro < 1)
|
||||
necro = 1;
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Necromancy].Value > 30 && Utility.Random(necro) > Utility.Random(mage))
|
||||
{
|
||||
switch (Utility.Random(necro - 5))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
return new CorpseSkinSpell(m_Mobile, null);
|
||||
case 2:
|
||||
case 3:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
default:
|
||||
return new MindRotSpell(m_Mobile, null);
|
||||
}
|
||||
}
|
||||
|
||||
if (Utility.RandomBool() && mage > 3)
|
||||
return new CurseSpell(m_Mobile, null);
|
||||
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
return new WeakenSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new ClumsySpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new FeeblemindSpell(m_Mobile, null);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual Spell GetRandomManaDrainSpell()
|
||||
{
|
||||
if (Utility.RandomBool())
|
||||
{
|
||||
if (m_Mobile.Skills[SkillName.Magery].Value >= 80.0)
|
||||
return new ManaVampireSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return new ManaDrainSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
public virtual Spell DoDispel(Mobile toDispel)
|
||||
{
|
||||
if (ScaleByMagery(DispelChance) > Utility.RandomDouble())
|
||||
return new DispelSpell(m_Mobile, null);
|
||||
|
||||
return ChooseSpell(toDispel);
|
||||
}
|
||||
|
||||
public virtual Spell ChooseSpell(IDamageable c)
|
||||
{
|
||||
var spell = CheckCastHealingSpell();
|
||||
|
||||
if (spell != null)
|
||||
return spell;
|
||||
|
||||
if (!(c is Mobile))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var mob = c as Mobile;
|
||||
var damage = ((m_Mobile.Skills[SkillName.SpiritSpeak].Value - mob.Skills[SkillName.MagicResist].Value) / 10) +
|
||||
(mob.Player ? 18 : 30);
|
||||
|
||||
if (damage > c.Hits)
|
||||
spell = new ManaDrainSpell(m_Mobile, null);
|
||||
|
||||
switch (Utility.Random(16))
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2: // Poison them
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to BloodOath");
|
||||
|
||||
if (!mob.Poisoned)
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
case 3: // Bless ourselves.
|
||||
{
|
||||
m_Mobile.DebugSay("Blessing myself");
|
||||
|
||||
spell = new BlessSpell(m_Mobile, null);
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
case 5:
|
||||
case 6: // Curse them.
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to curse");
|
||||
|
||||
spell = GetRandomCurseSpell();
|
||||
break;
|
||||
}
|
||||
case 7: // Paralyze them.
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to paralyze");
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Magery].Value > 50.0)
|
||||
spell = new ParalyzeSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: // Drain mana
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to drain mana");
|
||||
|
||||
spell = GetRandomManaDrainSpell();
|
||||
break;
|
||||
}
|
||||
case 9: // Blood oath them
|
||||
{
|
||||
m_Mobile.DebugSay("Attempting to blood oath");
|
||||
|
||||
if (m_Mobile.Skills[SkillName.Necromancy].Value > 30 && BloodOathSpell.GetBloodOath(mob) != m_Mobile)
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant;
|
||||
m_Mobile.Warmode = true;
|
||||
|
||||
if (c == null || c.Deleted || !c.Alive || (c is Mobile && ((Mobile)c).IsDeadBondedPet) || !m_Mobile.CanSee(c) ||
|
||||
!m_Mobile.CanBeHarmful(c, false) || c.Map != m_Mobile.Map)
|
||||
{
|
||||
// Our combatant is deleted, dead, hidden, or we cannot hurt them
|
||||
// Try to find another combatant
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("Something happened to my combatant, so I am going to fight {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = c = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("Something happened to my combatant, and nothing is around. I am on guard.");
|
||||
Action = ActionType.Guard;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.InLOS(c))
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = c = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.StunReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 &&
|
||||
m_Mobile.Skills[SkillName.Anatomy].Value >= 80.0)
|
||||
EventSink.InvokeStunRequest(new StunRequestEventArgs(m_Mobile));
|
||||
|
||||
if (!m_Mobile.InRange(c, m_Mobile.RangePerception))
|
||||
{
|
||||
// They are somewhat far away, can we find something else?
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3))
|
||||
{
|
||||
m_Mobile.Combatant = null;
|
||||
}
|
||||
|
||||
c = m_Mobile.Combatant;
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant has fled, so I am on guard");
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Mobile.Spell == null && DateTime.UtcNow > m_NextCastTime && m_Mobile.InRange(c, 12))
|
||||
{
|
||||
// We are ready to cast a spell
|
||||
Spell spell = null;
|
||||
var toDispel = FindDispelTarget(true);
|
||||
|
||||
if (m_Mobile.Poisoned) // Top cast priority is cure
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to cure myself");
|
||||
|
||||
spell = new CureSpell(m_Mobile, null);
|
||||
}
|
||||
else if (toDispel != null) // Something dispellable is attacking us
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to dispel {0}", toDispel);
|
||||
|
||||
spell = DoDispel(toDispel);
|
||||
}
|
||||
else if (c is Mobile && (((Mobile)c).Spell is HealSpell || ((Mobile)c).Spell is GreaterHealSpell) &&
|
||||
!((Mobile)c).Poisoned) // They have a heal spell out
|
||||
{
|
||||
spell = new BloodOathSpell(m_Mobile, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
spell = ChooseSpell(c);
|
||||
}
|
||||
|
||||
// Now we have a spell picked
|
||||
// Move first before casting
|
||||
|
||||
if (toDispel != null)
|
||||
{
|
||||
if (m_Mobile.InRange(toDispel, 10))
|
||||
RunFrom(toDispel);
|
||||
else if (!m_Mobile.InRange(toDispel, 12))
|
||||
RunTo(toDispel);
|
||||
}
|
||||
else if (c is Mobile)
|
||||
{
|
||||
RunTo((Mobile)c);
|
||||
}
|
||||
|
||||
if (spell != null)
|
||||
spell.Cast();
|
||||
|
||||
TimeSpan delay;
|
||||
|
||||
if (spell is DispelSpell)
|
||||
delay = TimeSpan.FromSeconds(m_Mobile.ActiveSpeed);
|
||||
else
|
||||
delay = GetDelay();
|
||||
|
||||
m_NextCastTime = DateTime.UtcNow + delay;
|
||||
}
|
||||
else if (c is Mobile && (m_Mobile.Spell == null || !m_Mobile.Spell.IsCasting))
|
||||
{
|
||||
RunTo((Mobile)c);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
new CureSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (!m_Mobile.Summoned && ((ScaleByMagery(HealChance) > Utility.RandomDouble())))
|
||||
{
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
if (!new GreaterHealSpell(m_Mobile, null).Cast())
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
{
|
||||
new HealSpell(m_Mobile, null).Cast();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if ((m_Mobile.Mana > 20 || m_Mobile.Mana == m_Mobile.ManaMax) && m_Mobile.Hits > (m_Mobile.HitsMax / 2))
|
||||
{
|
||||
// If I have a target, go back and fight them
|
||||
if (c != null && m_Mobile.GetDistanceToSqrt(c) <= m_Mobile.RangePerception * 2)
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, reengaging {0}", c.Name);
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, my guard is up");
|
||||
Action = ActionType.Guard;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionFlee();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Mobile FindDispelTarget(bool activeOnly)
|
||||
{
|
||||
if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel)
|
||||
return null;
|
||||
|
||||
if (activeOnly)
|
||||
{
|
||||
var aggressed = m_Mobile.Aggressed;
|
||||
var aggressors = m_Mobile.Aggressors;
|
||||
|
||||
Mobile active = null;
|
||||
var activePrio = 0.0;
|
||||
|
||||
var comb = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange(comb, 12) &&
|
||||
CanDispel(comb))
|
||||
{
|
||||
active = comb;
|
||||
activePrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
|
||||
for (var i = 0; i < aggressed.Count; ++i)
|
||||
{
|
||||
var info = aggressed[i];
|
||||
var m = info.Defender;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < aggressors.Count; ++i)
|
||||
{
|
||||
var info = aggressors[i];
|
||||
var m = info.Attacker;
|
||||
|
||||
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (active == null || prio < activePrio)
|
||||
{
|
||||
active = m;
|
||||
activePrio = prio;
|
||||
|
||||
if (activePrio <= 2)
|
||||
return active;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return active;
|
||||
}
|
||||
var map = m_Mobile.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Mobile active = null, inactive = null;
|
||||
double actPrio = 0.0, inactPrio = 0.0;
|
||||
|
||||
var comb = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (comb != null && !comb.Deleted && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb))
|
||||
{
|
||||
active = inactive = comb;
|
||||
actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb);
|
||||
}
|
||||
|
||||
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(12);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m != m_Mobile && CanDispel(m))
|
||||
{
|
||||
var prio = m_Mobile.GetDistanceToSqrt(m);
|
||||
|
||||
if (!activeOnly && (inactive == null || prio < inactPrio))
|
||||
{
|
||||
inactive = m;
|
||||
inactPrio = prio;
|
||||
}
|
||||
|
||||
if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio))
|
||||
{
|
||||
active = m;
|
||||
actPrio = prio;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return active != null ? active : inactive;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool CanDispel(Mobile m)
|
||||
{
|
||||
return (m is BaseCreature && ((BaseCreature)m).Summoned && m_Mobile.CanBeHarmful(m, false) &&
|
||||
!((BaseCreature)m).IsAnimatedDead);
|
||||
}
|
||||
|
||||
private Spell CheckCastHealingSpell()
|
||||
{
|
||||
// If I'm poisoned, always attempt to cure.
|
||||
if (m_Mobile.Poisoned)
|
||||
return new CureSpell(m_Mobile, null);
|
||||
|
||||
// Summoned creatures never heal themselves.
|
||||
if (m_Mobile.Summoned)
|
||||
return null;
|
||||
|
||||
if (m_Mobile.Controlled)
|
||||
{
|
||||
if (DateTime.UtcNow < m_NextHealTime)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (ScaleByMagery(HealChance) < Utility.RandomDouble())
|
||||
return null;
|
||||
|
||||
Spell spell = null;
|
||||
|
||||
if (m_Mobile.Hits < (m_Mobile.HitsMax - 50))
|
||||
{
|
||||
spell = new GreaterHealSpell(m_Mobile, null);
|
||||
|
||||
if (spell == null)
|
||||
spell = new HealSpell(m_Mobile, null);
|
||||
}
|
||||
else if (m_Mobile.Hits < (m_Mobile.HitsMax - 10))
|
||||
spell = new HealSpell(m_Mobile, null);
|
||||
|
||||
double delay;
|
||||
|
||||
if (m_Mobile.Int >= 500)
|
||||
delay = Utility.RandomMinMax(7, 10);
|
||||
else
|
||||
delay = Math.Sqrt(600 - m_Mobile.Int);
|
||||
|
||||
m_Mobile.UseSkill(SkillName.SpiritSpeak);
|
||||
|
||||
m_NextHealTime = DateTime.UtcNow + TimeSpan.FromSeconds(delay);
|
||||
|
||||
return spell;
|
||||
}
|
||||
|
||||
private TimeSpan GetDelay()
|
||||
{
|
||||
var del = ScaleByMagery(3.0);
|
||||
var min = 6.0 - (del * 0.75);
|
||||
var max = 6.0 - (del * 1.25);
|
||||
|
||||
return TimeSpan.FromSeconds(min + ((max - min) * Utility.RandomDouble()));
|
||||
}
|
||||
|
||||
private void ProcessTarget(Target targ)
|
||||
{
|
||||
var isDispel = (targ is DispelSpell.InternalTarget);
|
||||
var isParalyze = (targ is ParalyzeSpell.InternalTarget);
|
||||
var isTeleport = (targ is TeleportSpell.InternalTarget);
|
||||
var teleportAway = false;
|
||||
|
||||
Mobile toTarget;
|
||||
|
||||
if (isDispel)
|
||||
{
|
||||
toTarget = FindDispelTarget(false);
|
||||
|
||||
if (toTarget != null && m_Mobile.InRange(toTarget, 10))
|
||||
RunFrom(toTarget);
|
||||
}
|
||||
else if (isParalyze || isTeleport)
|
||||
{
|
||||
toTarget = FindDispelTarget(true);
|
||||
|
||||
if (toTarget == null)
|
||||
{
|
||||
toTarget = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (toTarget != null)
|
||||
RunTo(toTarget);
|
||||
}
|
||||
else if (m_Mobile.InRange(toTarget, 10))
|
||||
{
|
||||
RunFrom(toTarget);
|
||||
teleportAway = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
teleportAway = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
toTarget = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (toTarget != null)
|
||||
RunTo(toTarget);
|
||||
}
|
||||
|
||||
if ((targ.Flags & TargetFlags.Harmful) != 0 && toTarget != null)
|
||||
{
|
||||
if ((targ.Range == -1 || m_Mobile.InRange(toTarget, targ.Range)) && m_Mobile.CanSee(toTarget) &&
|
||||
m_Mobile.InLOS(toTarget))
|
||||
{
|
||||
targ.Invoke(m_Mobile, toTarget);
|
||||
}
|
||||
else if (isDispel)
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
else if ((targ.Flags & TargetFlags.Beneficial) != 0)
|
||||
{
|
||||
targ.Invoke(m_Mobile, m_Mobile);
|
||||
}
|
||||
else if (isTeleport && toTarget != null)
|
||||
{
|
||||
var map = m_Mobile.Map;
|
||||
|
||||
if (map == null)
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
return;
|
||||
}
|
||||
|
||||
int px, py;
|
||||
|
||||
if (teleportAway)
|
||||
{
|
||||
var rx = m_Mobile.X - toTarget.X;
|
||||
var ry = m_Mobile.Y - toTarget.Y;
|
||||
|
||||
var d = m_Mobile.GetDistanceToSqrt(toTarget);
|
||||
|
||||
px = toTarget.X + (int)(rx * (10 / d));
|
||||
py = toTarget.Y + (int)(ry * (10 / d));
|
||||
}
|
||||
else
|
||||
{
|
||||
px = toTarget.X;
|
||||
py = toTarget.Y;
|
||||
}
|
||||
|
||||
for (var i = 0; i < m_Offsets.Length; i += 2)
|
||||
{
|
||||
int x = m_Offsets[i], y = m_Offsets[i + 1];
|
||||
|
||||
var p = new Point3D(px + x, py + y, 0);
|
||||
|
||||
var lt = new LandTarget(p, map);
|
||||
|
||||
if ((targ.Range == -1 || m_Mobile.InRange(p, targ.Range)) && m_Mobile.InLOS(lt) &&
|
||||
map.CanSpawnMobile(px + x, py + y, lt.Z) && !SpellHelper.CheckMulti(p, map))
|
||||
{
|
||||
targ.Invoke(m_Mobile, lt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var teleRange = targ.Range;
|
||||
|
||||
if (teleRange < 0)
|
||||
teleRange = 12;
|
||||
|
||||
for (var i = 0; i < 10; ++i)
|
||||
{
|
||||
var randomPoint = new Point3D(
|
||||
m_Mobile.X - teleRange + Utility.Random(teleRange * 2 + 1),
|
||||
m_Mobile.Y - teleRange + Utility.Random(teleRange * 2 + 1),
|
||||
0);
|
||||
|
||||
var lt = new LandTarget(randomPoint, map);
|
||||
|
||||
if (m_Mobile.InLOS(lt) && map.CanSpawnMobile(lt.X, lt.Y, lt.Z) && !SpellHelper.CheckMulti(randomPoint, map))
|
||||
{
|
||||
targ.Invoke(m_Mobile, new LandTarget(randomPoint, map));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
else
|
||||
{
|
||||
targ.Cancel(m_Mobile, TargetCancelType.Canceled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Scripts/Mobiles/AI/Magical AI/SpellweavingAI.cs
Normal file
126
Scripts/Mobiles/AI/Magical AI/SpellweavingAI.cs
Normal file
@@ -0,0 +1,126 @@
|
||||
#region References
|
||||
using Server.Items;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Spellweaving;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class SpellweavingAI : MageAI
|
||||
{
|
||||
public override SkillName CastSkill { get { return SkillName.Spellweaving; } }
|
||||
|
||||
public override bool UsesMagery
|
||||
{
|
||||
get { return m_Mobile.Skills[SkillName.Magery].Base >= 20.0 && !m_Mobile.Controlled; }
|
||||
}
|
||||
|
||||
public SpellweavingAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override Spell GetRandomBuffSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomBuffSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var wep = m_Mobile.Weapon as BaseWeapon;
|
||||
|
||||
if (mana >= 50 && !ArcaneEmpowermentSpell.IsUnderEffects(m_Mobile) && 0.5 >= Utility.RandomDouble())
|
||||
return new ArcaneEmpowermentSpell(m_Mobile, null);
|
||||
if (mana >= 32 && wep != null && !ImmolatingWeaponSpell.IsImmolating(m_Mobile, wep))
|
||||
return new ImmolatingWeaponSpell(m_Mobile, null);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomCurseSpell()
|
||||
{
|
||||
if (UsesMagery)
|
||||
{
|
||||
return base.GetRandomCurseSpell();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetRandomDamageSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetRandomDamageSpell();
|
||||
}
|
||||
|
||||
var mana = m_Mobile.Mana;
|
||||
var select = 1;
|
||||
|
||||
if (mana >= 50)
|
||||
select = 4;
|
||||
else if (mana >= 40)
|
||||
select = 3;
|
||||
else if (mana >= 30)
|
||||
select = 2;
|
||||
|
||||
switch (Utility.Random(select))
|
||||
{
|
||||
case 0:
|
||||
return new ThunderstormSpell(m_Mobile, null);
|
||||
case 1:
|
||||
return new EssenceOfWindSpell(m_Mobile, null);
|
||||
case 2:
|
||||
return new WildfireSpell(m_Mobile, null);
|
||||
case 3:
|
||||
return new WordOfDeathSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetHealSpell()
|
||||
{
|
||||
if (UsesMagery && 0.5 > Utility.RandomDouble())
|
||||
{
|
||||
return base.GetHealSpell();
|
||||
}
|
||||
|
||||
if (m_Mobile.Mana >= 24)
|
||||
{
|
||||
return new GiftOfRenewalSpell(m_Mobile, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override Spell GetCureSpell()
|
||||
{
|
||||
if (UsesMagery)
|
||||
{
|
||||
return base.GetCureSpell();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override bool ProcessTarget()
|
||||
{
|
||||
var t = m_Mobile.Target;
|
||||
|
||||
if (t is WildfireSpell.InternalTarget)
|
||||
{
|
||||
if (m_Mobile.Combatant != null && m_Mobile.InRange(m_Mobile.Combatant.Location, 8))
|
||||
{
|
||||
t.Invoke(m_Mobile, m_Mobile.Combatant);
|
||||
}
|
||||
else
|
||||
t.Invoke(m_Mobile, m_Mobile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.ProcessTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Scripts/Mobiles/AI/MeleeAI.cs
Normal file
155
Scripts/Mobiles/AI/MeleeAI.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
#region References
|
||||
using System;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class MeleeAI : BaseAI
|
||||
{
|
||||
public MeleeAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I have no combatant");
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant;
|
||||
|
||||
if (c == null || c.Deleted || c.Map != m_Mobile.Map || !c.Alive || (c is Mobile && ((Mobile)c).IsDeadBondedPet))
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is gone, so my guard is up");
|
||||
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!m_Mobile.InRange(c, m_Mobile.RangePerception))
|
||||
{
|
||||
// They are somewhat far away, can we find something else?
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3))
|
||||
{
|
||||
m_Mobile.Combatant = null;
|
||||
}
|
||||
|
||||
c = m_Mobile.Combatant;
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant has fled, so I am on guard");
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (MoveTo(c, true, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(c);
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_Mobile.GetDistanceToSqrt(c) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
m_Mobile.DebugSay("I cannot find {0}, so my guard is up", c.Name);
|
||||
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I should be closer to {0}", c.Name);
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (m_Mobile.Hits > (m_Mobile.HitsMax / 2))
|
||||
{
|
||||
// If I have a target, go back and fight them
|
||||
if (c != null && m_Mobile.GetDistanceToSqrt(c) <= m_Mobile.RangePerception * 2)
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, reengaging {0}", c.Name);
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, my guard is up");
|
||||
Action = ActionType.Guard;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionFlee();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
92
Scripts/Mobiles/AI/OppositionGroup.cs
Normal file
92
Scripts/Mobiles/AI/OppositionGroup.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class OppositionGroup
|
||||
{
|
||||
private static readonly OppositionGroup m_TerathansAndOphidians = new OppositionGroup(
|
||||
new[]
|
||||
{
|
||||
new[] {typeof(TerathanAvenger), typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior)},
|
||||
new[]
|
||||
{
|
||||
typeof(OphidianArchmage), typeof(OphidianKnight), typeof(OphidianMage), typeof(OphidianMatriarch),
|
||||
typeof(OphidianWarrior)
|
||||
}
|
||||
});
|
||||
|
||||
private static readonly OppositionGroup m_SavagesAndOrcs = new OppositionGroup(
|
||||
new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
typeof(Orc), typeof(OrcBomber), typeof(OrcBrute), typeof(OrcCaptain), typeof(OrcChopper), typeof(OrcishLord),
|
||||
typeof(OrcishMage), typeof(OrcScout), typeof(SpawnedOrcishLord)
|
||||
},
|
||||
new[] {typeof(Savage), typeof(SavageRider), typeof(SavageRidgeback), typeof(SavageShaman)}
|
||||
});
|
||||
|
||||
private static readonly OppositionGroup m_FeyAndUndead = new OppositionGroup(
|
||||
new[]
|
||||
{
|
||||
new[]
|
||||
{
|
||||
typeof(Centaur), typeof(EtherealWarrior), typeof(Kirin), typeof(LordOaks), typeof(Pixie), typeof(Silvani),
|
||||
typeof(Unicorn), typeof(Wisp), typeof(Treefellow), typeof(MLDryad), typeof(Satyr)
|
||||
},
|
||||
new[]
|
||||
{
|
||||
typeof(AncientLich), typeof(Bogle), typeof(BoneKnight), typeof(BoneMagi), typeof(DarknightCreeper), typeof(Ghoul),
|
||||
typeof(LadyOfTheSnow), typeof(Lich), typeof(LichLord), typeof(Mummy), typeof(RevenantLion), typeof(RottingCorpse),
|
||||
typeof(Shade), typeof(ShadowKnight), typeof(SkeletalDragon), typeof(SkeletalDrake), typeof(SkeletalKnight),
|
||||
typeof(SkeletalMage), typeof(Skeleton), typeof(Spectre), typeof(Wraith), typeof(Zombie)
|
||||
}
|
||||
});
|
||||
|
||||
private readonly Type[][] m_Types;
|
||||
|
||||
public OppositionGroup(Type[][] types)
|
||||
{
|
||||
m_Types = types;
|
||||
}
|
||||
|
||||
public static OppositionGroup TerathansAndOphidians { get { return m_TerathansAndOphidians; } }
|
||||
public static OppositionGroup SavagesAndOrcs { get { return m_SavagesAndOrcs; } }
|
||||
public static OppositionGroup FeyAndUndead { get { return m_FeyAndUndead; } }
|
||||
|
||||
public bool IsEnemy(object from, object target)
|
||||
{
|
||||
var fromGroup = IndexOf(from);
|
||||
var targGroup = IndexOf(target);
|
||||
|
||||
return (fromGroup != -1 && targGroup != -1 && fromGroup != targGroup);
|
||||
}
|
||||
|
||||
public int IndexOf(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return -1;
|
||||
|
||||
var type = obj.GetType();
|
||||
|
||||
for (var i = 0; i < m_Types.Length; ++i)
|
||||
{
|
||||
var group = m_Types[i];
|
||||
|
||||
var contains = false;
|
||||
|
||||
for (var j = 0; !contains && j < group.Length; ++j)
|
||||
contains = group[j].IsAssignableFrom(type);
|
||||
|
||||
if (contains)
|
||||
return i;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
330
Scripts/Mobiles/AI/OrcScoutAI.cs
Normal file
330
Scripts/Mobiles/AI/OrcScoutAI.cs
Normal file
@@ -0,0 +1,330 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Spells;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class OrcScoutAI : BaseAI
|
||||
{
|
||||
private static readonly double teleportChance = 0.04;
|
||||
private static readonly int[] m_Offsets = {0, 0, -1, -1, 0, -1, 1, -1, -1, 0, 1, 0, -1, -1, 0, 1, 1, 1};
|
||||
|
||||
public OrcScoutAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I have no combatant");
|
||||
|
||||
PerformHide();
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Combatant != null)
|
||||
{
|
||||
Action = ActionType.Combat;
|
||||
return true;
|
||||
}
|
||||
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (c == null || c.Deleted || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is gone, so my guard is up");
|
||||
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < teleportChance)
|
||||
{
|
||||
TryToTeleport();
|
||||
}
|
||||
|
||||
if (!m_Mobile.InRange(c, m_Mobile.RangePerception))
|
||||
{
|
||||
// They are somewhat far away, can we find something else?
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
m_Mobile.FocusMob = null;
|
||||
}
|
||||
else if (!m_Mobile.InRange(c, m_Mobile.RangePerception * 3))
|
||||
{
|
||||
m_Mobile.Combatant = null;
|
||||
}
|
||||
|
||||
c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (c == null)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant has fled, so I am on guard");
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (MoveTo(c, true, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(c);
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
|
||||
return true;
|
||||
}
|
||||
else if (m_Mobile.GetDistanceToSqrt(c) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
m_Mobile.DebugSay("I cannot find {0}, so my guard is up", c.Name);
|
||||
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I should be closer to {0}", c.Name);
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
/* // When we have no ammo, we flee
|
||||
Container pack = m_Mobile.Backpack;
|
||||
|
||||
if (pack == null || pack.FindItemByType(typeof(Arrow)) == null)
|
||||
{
|
||||
Action = ActionType.Flee;
|
||||
if (Utility.RandomDouble() < teleportChance + 0.1)
|
||||
{
|
||||
TryToTeleport();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
if (Utility.RandomDouble() < teleportChance + 0.1)
|
||||
{
|
||||
TryToTeleport();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionFlee()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
// Container pack = m_Mobile.Backpack;
|
||||
// bool hasAmmo = !(pack == null || pack.FindItemByType(typeof(Arrow)) == null);
|
||||
// They can shoot even with no ammo!
|
||||
|
||||
if ( /*hasAmmo && */m_Mobile.Hits > m_Mobile.HitsMax / 2)
|
||||
{
|
||||
// If I have a target, go back and fight them
|
||||
if (c != null && m_Mobile.GetDistanceToSqrt(c) <= m_Mobile.RangePerception * 2)
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, reengaging {0}", c.Name);
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I am stronger now, my guard is up");
|
||||
Action = ActionType.Guard;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PerformHide();
|
||||
|
||||
base.DoActionFlee();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Mobile FindNearestAggressor()
|
||||
{
|
||||
Mobile nearest = null;
|
||||
|
||||
var dist = 9999.0;
|
||||
|
||||
IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m.Player && !m.Hidden && m.IsPlayer() && m.Combatant == m_Mobile)
|
||||
{
|
||||
if (dist > m.GetDistanceToSqrt(m_Mobile))
|
||||
{
|
||||
nearest = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
return nearest;
|
||||
}
|
||||
|
||||
private void TryToTeleport()
|
||||
{
|
||||
var m = FindNearestAggressor();
|
||||
|
||||
if (m == null || m.Map == null || m_Mobile.Map == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Mobile.GetDistanceToSqrt(m) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var px = m_Mobile.X;
|
||||
var py = m_Mobile.Y;
|
||||
|
||||
var dx = m_Mobile.X - m.X;
|
||||
var dy = m_Mobile.Y - m.Y;
|
||||
|
||||
// get vector's length
|
||||
|
||||
var l = Math.Sqrt((dx * dx + dy * dy));
|
||||
|
||||
if (l == 0)
|
||||
{
|
||||
var rand = Utility.Random(8) + 1;
|
||||
rand *= 2;
|
||||
dx = m_Offsets[rand];
|
||||
dy = m_Offsets[rand + 1];
|
||||
l = Math.Sqrt((dx * dx + dy * dy));
|
||||
}
|
||||
|
||||
// normalize vector
|
||||
var dpx = (dx) / l;
|
||||
var dpy = (dy) / l;
|
||||
// move
|
||||
px += (int)(dpx * (4 + Utility.Random(3)));
|
||||
py += (int)(dpy * (4 + Utility.Random(3)));
|
||||
|
||||
for (var i = 0; i < m_Offsets.Length; i += 2)
|
||||
{
|
||||
int x = m_Offsets[i], y = m_Offsets[i + 1];
|
||||
|
||||
var p = new Point3D(px + x, py + y, 0);
|
||||
|
||||
var lt = new LandTarget(p, m_Mobile.Map);
|
||||
|
||||
if (m_Mobile.InLOS(lt) && m_Mobile.Map.CanSpawnMobile(px + x, py + y, lt.Z) &&
|
||||
!SpellHelper.CheckMulti(p, m_Mobile.Map))
|
||||
{
|
||||
m_Mobile.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
|
||||
m_Mobile.PlaySound(0x1FE);
|
||||
|
||||
m_Mobile.Location = new Point3D(lt.X, lt.Y, lt.Z);
|
||||
m_Mobile.ProcessDelta();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void HideSelf()
|
||||
{
|
||||
if (Core.TickCount >= m_Mobile.NextSkillTime)
|
||||
{
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration),
|
||||
0x3728,
|
||||
10,
|
||||
10,
|
||||
2023);
|
||||
|
||||
m_Mobile.PlaySound(0x22F);
|
||||
m_Mobile.Hidden = true;
|
||||
|
||||
m_Mobile.UseSkill(SkillName.Stealth);
|
||||
}
|
||||
}
|
||||
|
||||
private void PerformHide()
|
||||
{
|
||||
if (!m_Mobile.Alive || m_Mobile.Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_Mobile.Hidden)
|
||||
{
|
||||
var chance = 0.05;
|
||||
|
||||
if (m_Mobile.Hits < 20)
|
||||
{
|
||||
chance = 0.1;
|
||||
}
|
||||
|
||||
if (m_Mobile.Poisoned)
|
||||
{
|
||||
chance = 0.01;
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < chance)
|
||||
{
|
||||
HideSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Scripts/Mobiles/AI/PredatorAI.cs
Normal file
94
Scripts/Mobiles/AI/PredatorAI.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
/*
|
||||
* PredatorAI, its an animal that can attack
|
||||
* Dont flee but dont attack if not hurt or attacked
|
||||
*
|
||||
*/
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class PredatorAI : BaseAI
|
||||
{
|
||||
public PredatorAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
if (m_Mobile.Combatant != null)
|
||||
{
|
||||
m_Mobile.DebugSay("I am hurt or being attacked, I kill him");
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("There is something near, I go away");
|
||||
Action = ActionType.Backoff;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var combatant = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is gone, so my guard is up");
|
||||
Action = ActionType.Wander;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WalkMobileRange(combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(combatant);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.GetDistanceToSqrt(combatant) > m_Mobile.RangePerception + 1)
|
||||
{
|
||||
m_Mobile.DebugSay("I cannot find {0}", combatant.Name);
|
||||
|
||||
Action = ActionType.Wander;
|
||||
return true;
|
||||
}
|
||||
|
||||
m_Mobile.DebugSay("I should be closer to {0}", combatant.Name);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionBackoff()
|
||||
{
|
||||
if (m_Mobile.IsHurt() || m_Mobile.Combatant != null)
|
||||
{
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false, true))
|
||||
{
|
||||
if (WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2))
|
||||
{
|
||||
m_Mobile.DebugSay("Well, here I am safe");
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I have lost my focus, lets relax");
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
255
Scripts/Mobiles/AI/SpeedInfo.cs
Normal file
255
Scripts/Mobiles/AI/SpeedInfo.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class SpeedInfo
|
||||
{
|
||||
public static readonly double MinDelay = 0.1;
|
||||
public static readonly double MaxDelay = 0.5;
|
||||
public static readonly double MinDelayWild = 0.4;
|
||||
public static readonly double MaxDelayWild = 0.8;
|
||||
|
||||
public static bool GetSpeedsNew(BaseCreature bc, ref double activeSpeed, ref double passiveSpeed)
|
||||
{
|
||||
var maxDex = GetMaxMovementDex(bc);
|
||||
var dex = Math.Min(maxDex, Math.Max(25, bc.Dex));
|
||||
|
||||
var min = bc.IsMonster || InActivePVPCombat(bc) ? MinDelayWild : MinDelay;
|
||||
var max = bc.IsMonster || InActivePVPCombat(bc) ? MaxDelayWild : MaxDelay;
|
||||
|
||||
if (bc.IsParagon)
|
||||
{
|
||||
min /= 2;
|
||||
max = min + .4;
|
||||
}
|
||||
|
||||
activeSpeed = max - ((max - min) * ((double)dex / maxDex));
|
||||
|
||||
if (activeSpeed < min)
|
||||
{
|
||||
activeSpeed = min;
|
||||
}
|
||||
|
||||
passiveSpeed = activeSpeed * 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int GetMaxMovementDex(BaseCreature bc)
|
||||
{
|
||||
return bc.IsMonster ? 150 : 190;
|
||||
}
|
||||
|
||||
public static bool InActivePVPCombat(BaseCreature bc)
|
||||
{
|
||||
return bc.Combatant != null && bc.ControlOrder != OrderType.Follow && bc.Combatant is PlayerMobile;
|
||||
}
|
||||
|
||||
public static double TransformMoveDelay(BaseCreature bc, double delay)
|
||||
{
|
||||
var adjusted = bc.IsMonster ? MaxDelayWild : MaxDelay;
|
||||
|
||||
if (!bc.IsDeadPet && (bc.ReduceSpeedWithDamage || bc.IsSubdued))
|
||||
{
|
||||
var offset = (double)bc.Stam / (double)bc.StamMax;
|
||||
|
||||
if (offset < 1.0)
|
||||
{
|
||||
delay = delay + ((adjusted - delay) * (1.0 - offset));
|
||||
}
|
||||
}
|
||||
|
||||
if (delay > adjusted)
|
||||
{
|
||||
delay = adjusted;
|
||||
}
|
||||
|
||||
return delay;
|
||||
}
|
||||
|
||||
public static bool UseNewSpeeds { get { return true; } }
|
||||
public double ActiveSpeed { get; set; }
|
||||
public double PassiveSpeed { get; set; }
|
||||
|
||||
public Type[] Types { get; set; }
|
||||
|
||||
public SpeedInfo(double activeSpeed, double passiveSpeed, Type[] types)
|
||||
{
|
||||
ActiveSpeed = activeSpeed;
|
||||
PassiveSpeed = passiveSpeed;
|
||||
Types = types;
|
||||
}
|
||||
|
||||
/*public static bool Contains(object obj)
|
||||
{
|
||||
if (UseNewSpeeds)
|
||||
return false;
|
||||
|
||||
if (m_Table == null)
|
||||
LoadTable();
|
||||
|
||||
var sp = (SpeedInfo)m_Table[obj.GetType()];
|
||||
|
||||
return (sp != null);
|
||||
}*/
|
||||
|
||||
public static bool GetSpeeds(BaseCreature bc, ref double activeSpeed, ref double passiveSpeed)
|
||||
{
|
||||
if (UseNewSpeeds)
|
||||
{
|
||||
GetSpeedsNew(bc, ref activeSpeed, ref passiveSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Table == null)
|
||||
LoadTable();
|
||||
|
||||
var sp = (SpeedInfo)m_Table[bc.GetType()];
|
||||
|
||||
if (sp == null)
|
||||
return false;
|
||||
|
||||
activeSpeed = sp.ActiveSpeed;
|
||||
passiveSpeed = sp.PassiveSpeed;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void LoadTable()
|
||||
{
|
||||
m_Table = new Hashtable();
|
||||
|
||||
for (var i = 0; i < m_Speeds.Length; ++i)
|
||||
{
|
||||
var info = m_Speeds[i];
|
||||
var types = info.Types;
|
||||
|
||||
for (var j = 0; j < types.Length; ++j)
|
||||
m_Table[types[j]] = info;
|
||||
}
|
||||
}
|
||||
|
||||
private static Hashtable m_Table;
|
||||
|
||||
private static readonly SpeedInfo[] m_Speeds =
|
||||
{
|
||||
// Slow
|
||||
new SpeedInfo(
|
||||
0.3,
|
||||
0.6,
|
||||
new[]
|
||||
{
|
||||
typeof(AntLion), typeof(ArcticOgreLord), typeof(BogThing), typeof(Bogle), typeof(BoneKnight),
|
||||
typeof(EarthElemental), typeof(Ettin), typeof(FrostOoze), typeof(FrostTroll), typeof(GazerLarva), typeof(Ghoul),
|
||||
typeof(Golem), typeof(HeadlessOne), typeof(Jwilson), typeof(Mummy), typeof(Ogre), typeof(OgreLord),
|
||||
typeof(PlagueBeast), typeof(Quagmire), typeof(Rat), typeof(RottingCorpse), typeof(Sewerrat), typeof(Skeleton),
|
||||
typeof(Slime), typeof(Zombie), typeof(Walrus), typeof(RestlessSoul), typeof(CrystalElemental),
|
||||
typeof(DarknightCreeper), typeof(MoundOfMaggots), typeof(Juggernaut), typeof(Yamandon), typeof(Serado),
|
||||
typeof(RuddyBoura), typeof(LowlandBoura), typeof(HighPlainsBoura), typeof(Relanord), typeof(Ortanord),
|
||||
typeof(Korpre), typeof(Anzuanord), typeof(Anlorzen), typeof(UndeadGuardian), typeof(PutridUndeadGuardian),
|
||||
typeof(CorgulTheSoulBinder), typeof(GooeyMaggots), typeof(Fezzik), typeof(Ronin)
|
||||
}),
|
||||
// Fast
|
||||
new SpeedInfo(
|
||||
0.2,
|
||||
0.4,
|
||||
new[]
|
||||
{
|
||||
typeof(LordOaks), typeof(Silvani), typeof(AirElemental), typeof(AncientWyrm), typeof(Balron), typeof(BladeSpirits),
|
||||
typeof(DreadSpider), typeof(Efreet), typeof(EtherealWarrior), typeof(Lich), typeof(Nightmare),
|
||||
typeof(OphidianArchmage), typeof(OphidianMage), typeof(OphidianWarrior), typeof(OphidianMatriarch),
|
||||
typeof(OphidianKnight), typeof(PoisonElemental), typeof(Revenant), typeof(SandVortex), typeof(SavageRider),
|
||||
typeof(SavageShaman), typeof(SnowElemental), typeof(WhiteWyrm), typeof(Wisp), typeof(DemonKnight),
|
||||
typeof(GiantBlackWidow), typeof(SummonedAirElemental), typeof(LesserHiryu), typeof(Hiryu), typeof(LadyOfTheSnow),
|
||||
typeof(RaiJu), typeof(RuneBeetle), typeof(Changeling), typeof(SentinelSpider), typeof(Anlorvaglem), typeof(Medusa),
|
||||
typeof(PrimevalLich), typeof(StygianDragon), typeof(CoralSnake), typeof(DarkWisp), typeof(DreamWraith),
|
||||
typeof(FireAnt), typeof(KepetchAmbusher), typeof(LavaElemental), typeof(MaddeningHorror), typeof(Wight),
|
||||
typeof(WolfSpider), typeof(UndeadGargoyle), typeof(SlasherOfVeils), typeof(SavagePackWolf), typeof(DemonicJailor),
|
||||
typeof(SilverSerpent),
|
||||
|
||||
#region ML named mobs - before Paragon speedboost
|
||||
typeof(LadyJennifyr), typeof(LadyMarai), typeof(MasterJonath), typeof(MasterMikael), typeof(MasterTheophilus),
|
||||
typeof(RedDeath), typeof(SirPatrick), typeof(Rend), typeof(Grobu), typeof(Gnaw), typeof(Guile), typeof(Irk),
|
||||
typeof(Spite), typeof(LadyLissith), typeof(LadySabrix), typeof(Malefic), typeof(Silk), typeof(Virulent)
|
||||
// TODO: Where to put Lurg, Putrefier, Swoop and Pyre? They seem slower.
|
||||
#endregion
|
||||
}),
|
||||
// Very Fast
|
||||
new SpeedInfo(
|
||||
0.175,
|
||||
0.350,
|
||||
new[]
|
||||
{
|
||||
typeof(Barracoon), typeof(Neira), typeof(Rikktor), typeof(EnergyVortex), typeof(EliteNinja), typeof(Pixie),
|
||||
typeof(FleshRenderer), typeof(KhaldunRevenant), typeof(FactionDragoon), typeof(FactionKnight),
|
||||
typeof(FactionPaladin), typeof(FactionHenchman), typeof(FactionMercenary), typeof(FactionNecromancer),
|
||||
typeof(FactionSorceress), typeof(FactionWizard), typeof(FactionBerserker), typeof(FactionPaladin),
|
||||
typeof(Leviathan), typeof(FireBeetle), typeof(FanDancer), typeof(FactionDeathKnight), typeof(ClockworkExodus),
|
||||
typeof(Navrey), typeof(Raptor), typeof(TrapdoorSpider)
|
||||
}),
|
||||
// Extremely Fast
|
||||
new SpeedInfo(0.08, 0.20, new[] {typeof(Miasma), typeof(Semidar), typeof(Mephitis)}),
|
||||
// Medium
|
||||
new SpeedInfo(
|
||||
0.25,
|
||||
0.5,
|
||||
new[]
|
||||
{
|
||||
typeof(ToxicElemental), typeof(AgapiteElemental), typeof(Alligator), typeof(AncientLich), typeof(Betrayer),
|
||||
typeof(Bird), typeof(BlackBear), typeof(BlackSolenInfiltratorQueen), typeof(BlackSolenInfiltratorWarrior),
|
||||
typeof(BlackSolenQueen), typeof(BlackSolenWarrior), typeof(BlackSolenWorker), typeof(BloodElemental), typeof(Boar),
|
||||
typeof(Bogling), typeof(BoneMagi), typeof(Brigand), typeof(BronzeElemental), typeof(BrownBear), typeof(Bull),
|
||||
typeof(BullFrog), typeof(Cat), typeof(Centaur), typeof(ChaosDaemon), typeof(Chicken), typeof(GolemController),
|
||||
typeof(CopperElemental), typeof(CopperElemental), typeof(Cougar), typeof(Cow), typeof(Cyclops), typeof(Daemon),
|
||||
typeof(DeepSeaSerpent), typeof(DesertOstard), typeof(DireWolf), typeof(Dog), typeof(Dolphin), typeof(Dragon),
|
||||
typeof(Drake), typeof(DullCopperElemental), typeof(Eagle), typeof(ElderGazer), typeof(EvilMage),
|
||||
typeof(EvilMageLord), typeof(Executioner), typeof(Savage), typeof(FireElemental), typeof(FireGargoyle),
|
||||
typeof(FireSteed), typeof(ForestOstard), typeof(FrenziedOstard), typeof(FrostSpider), typeof(Gargoyle),
|
||||
typeof(Gazer), typeof(IceSerpent), typeof(GiantRat), typeof(GiantSerpent), typeof(GiantSpider), typeof(GiantToad),
|
||||
typeof(Goat), typeof(GoldenElemental), typeof(Gorilla), typeof(GreatHart), typeof(GreyWolf), typeof(GrizzlyBear),
|
||||
typeof(Guardian), typeof(Harpy), typeof(Harrower), typeof(HellHound), typeof(Hind), typeof(HordeMinion),
|
||||
typeof(Horse), typeof(IceElemental), typeof(IceFiend), typeof(IceSnake), typeof(Imp), typeof(JackRabbit),
|
||||
typeof(Kirin), typeof(Kraken), typeof(PredatorHellCat), typeof(LavaLizard), typeof(LavaSerpent), typeof(LavaSnake),
|
||||
typeof(Lizardman), typeof(Llama), typeof(Mongbat), typeof(StrongMongbat), typeof(MountainGoat), typeof(Orc),
|
||||
typeof(OrcBomber), typeof(OrcBrute), typeof(OrcCaptain), typeof(OrcishLord), typeof(OrcishMage), typeof(PackHorse),
|
||||
typeof(PackLlama), typeof(Panther), typeof(Pig), typeof(PlagueSpawn), typeof(PolarBear), typeof(Rabbit),
|
||||
typeof(Ratman), typeof(RatmanArcher), typeof(RatmanMage), typeof(RedSolenInfiltratorQueen),
|
||||
typeof(RedSolenInfiltratorWarrior), typeof(RedSolenQueen), typeof(RedSolenWarrior), typeof(RedSolenWorker),
|
||||
typeof(RidableLlama), typeof(Ridgeback), typeof(Scorpion), typeof(SeaSerpent), typeof(SerpentineDragon),
|
||||
typeof(Shade), typeof(ShadowIronElemental), typeof(ShadowWisp), typeof(ShadowWyrm), typeof(Sheep),
|
||||
typeof(SilverSteed), typeof(SkeletalDragon), typeof(SkeletalMage), typeof(SkeletalMount), typeof(HellCat),
|
||||
typeof(Snake), typeof(SnowLeopard), typeof(SpectralArmour), typeof(Spectre), typeof(StoneGargoyle),
|
||||
typeof(StoneHarpy), typeof(SwampDragon), typeof(ScaledSwampDragon), typeof(SwampTentacle), typeof(TerathanAvenger),
|
||||
typeof(TerathanDrone), typeof(TerathanMatriarch), typeof(TerathanWarrior), typeof(TimberWolf), typeof(Titan),
|
||||
typeof(Troll), typeof(Unicorn), typeof(ValoriteElemental), typeof(VeriteElemental), typeof(CoMWarHorse),
|
||||
typeof(MinaxWarHorse), typeof(SLWarHorse), typeof(TBWarHorse), typeof(WaterElemental), typeof(WhippingVine),
|
||||
typeof(WhiteWolf), typeof(Wraith), typeof(Wyvern), typeof(KhaldunZealot), typeof(KhaldunSummoner),
|
||||
typeof(SavageRidgeback), typeof(LichLord), typeof(SkeletalKnight), typeof(SummonedDaemon),
|
||||
typeof(SummonedEarthElemental), typeof(SummonedWaterElemental), typeof(SummonedFireElemental), typeof(MeerWarrior),
|
||||
typeof(MeerEternal), typeof(MeerMage), typeof(MeerCaptain), typeof(JukaLord), typeof(JukaMage),
|
||||
typeof(JukaWarrior), typeof(AbysmalHorror), typeof(BoneDemon), typeof(Devourer), typeof(FleshGolem),
|
||||
typeof(Gibberling), typeof(GoreFiend), typeof(Impaler), typeof(PatchworkSkeleton), typeof(Ravager),
|
||||
typeof(ShadowKnight), typeof(SkitteringHopper), typeof(Treefellow), typeof(VampireBat), typeof(WailingBanshee),
|
||||
typeof(WandererOfTheVoid), typeof(Cursed), typeof(GrimmochDrummel), typeof(LysanderGathenwale), typeof(MorgBergen),
|
||||
typeof(ShadowFiend), typeof(SpectralArmour), typeof(TavaraSewel), typeof(ArcaneDaemon), typeof(Doppleganger),
|
||||
typeof(EnslavedGargoyle), typeof(ExodusMinion), typeof(ExodusOverseer), typeof(GargoyleDestroyer),
|
||||
typeof(GargoyleEnforcer), typeof(Moloch), typeof(BakeKitsune), typeof(DeathwatchBeetleHatchling), typeof(Kappa),
|
||||
typeof(KazeKemono), typeof(DeathwatchBeetle), typeof(TsukiWolf), typeof(YomotsuElder), typeof(YomotsuPriest),
|
||||
typeof(YomotsuWarrior), typeof(RevenantLion), typeof(Oni), typeof(Gaman), typeof(Crane), typeof(Beetle),
|
||||
typeof(ColdDrake), typeof(Vasanord), typeof(Ballem), typeof(Betballem), typeof(Anlorlem), typeof(BloodWorm),
|
||||
typeof(GreenGoblin), typeof(EnslavedGreenGoblin), typeof(GreenGoblinAlchemist), typeof(GreenGoblinScout),
|
||||
typeof(Kepetch), typeof(ClanRC), typeof(EnslavedGoblinKeeper), typeof(EnslavedGoblinMage),
|
||||
typeof(EnslavedGoblinScout), typeof(EnslavedGrayGoblin), typeof(GrayGoblin), typeof(GrayGoblinKeeper),
|
||||
typeof(GrayGoblinMage), typeof(Gremlin), typeof(SkeletalDrake), typeof(Slith), typeof(StoneSlith),
|
||||
typeof(ToxicSlith), typeof(WyvernRenowned), typeof(GrayGoblinMageRenowned), typeof(FireDaemon), typeof(AcidSlug)
|
||||
})
|
||||
};
|
||||
}
|
||||
}
|
||||
195
Scripts/Mobiles/AI/ThiefAI.cs
Normal file
195
Scripts/Mobiles/AI/ThiefAI.cs
Normal file
@@ -0,0 +1,195 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class ThiefAI : BaseAI
|
||||
{
|
||||
private Item m_toDisarm;
|
||||
|
||||
public ThiefAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I have no combatant");
|
||||
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionWander();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionCombat()
|
||||
{
|
||||
var c = m_Mobile.Combatant as Mobile;
|
||||
|
||||
if (c == null || c.Deleted || c.Map != m_Mobile.Map)
|
||||
{
|
||||
m_Mobile.DebugSay("My combatant is gone, so my guard is up");
|
||||
|
||||
Action = ActionType.Guard;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WalkMobileRange(c, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight))
|
||||
{
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(c);
|
||||
|
||||
if (m_toDisarm == null)
|
||||
{
|
||||
m_toDisarm = c.FindItemOnLayer(Layer.OneHanded);
|
||||
}
|
||||
|
||||
if (m_toDisarm == null)
|
||||
{
|
||||
m_toDisarm = c.FindItemOnLayer(Layer.TwoHanded);
|
||||
}
|
||||
|
||||
if (m_toDisarm != null && m_toDisarm.IsChildOf(m_Mobile.Backpack))
|
||||
{
|
||||
m_toDisarm = c.FindItemOnLayer(Layer.OneHanded);
|
||||
|
||||
if (m_toDisarm == null)
|
||||
{
|
||||
m_toDisarm = c.FindItemOnLayer(Layer.TwoHanded);
|
||||
}
|
||||
}
|
||||
|
||||
if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 &&
|
||||
m_Mobile.Skills[SkillName.ArmsLore].Value >= 80.0 && m_toDisarm != null)
|
||||
{
|
||||
EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(m_Mobile));
|
||||
}
|
||||
|
||||
if (m_toDisarm != null && m_toDisarm.IsChildOf(c.Backpack) && m_Mobile.NextSkillTime <= Core.TickCount &&
|
||||
(m_toDisarm.LootType != LootType.Blessed && m_toDisarm.LootType != LootType.Newbied))
|
||||
{
|
||||
m_Mobile.DebugSay("Trying to steal from combatant.");
|
||||
m_Mobile.UseSkill(SkillName.Stealing);
|
||||
|
||||
if (m_Mobile.Target != null)
|
||||
{
|
||||
m_Mobile.Target.Invoke(m_Mobile, m_toDisarm);
|
||||
}
|
||||
}
|
||||
else if (m_toDisarm == null && m_Mobile.NextSkillTime <= Core.TickCount)
|
||||
{
|
||||
var cpack = c.Backpack;
|
||||
|
||||
if (cpack != null)
|
||||
{
|
||||
var steala = cpack.FindItemByType(typeof(Bandage));
|
||||
|
||||
if (steala != null)
|
||||
{
|
||||
m_Mobile.DebugSay("Trying to steal from combatant.");
|
||||
m_Mobile.UseSkill(SkillName.Stealing);
|
||||
|
||||
if (m_Mobile.Target != null)
|
||||
{
|
||||
m_Mobile.Target.Invoke(m_Mobile, steala);
|
||||
}
|
||||
}
|
||||
|
||||
var stealb = cpack.FindItemByType(typeof(Nightshade));
|
||||
|
||||
if (stealb != null)
|
||||
{
|
||||
m_Mobile.DebugSay("Trying to steal from combatant.");
|
||||
m_Mobile.UseSkill(SkillName.Stealing);
|
||||
|
||||
if (m_Mobile.Target != null)
|
||||
{
|
||||
m_Mobile.Target.Invoke(m_Mobile, stealb);
|
||||
}
|
||||
}
|
||||
|
||||
var stealc = cpack.FindItemByType(typeof(BlackPearl));
|
||||
|
||||
if (stealc != null)
|
||||
{
|
||||
m_Mobile.DebugSay("Trying to steal from combatant.");
|
||||
m_Mobile.UseSkill(SkillName.Stealing);
|
||||
|
||||
if (m_Mobile.Target != null)
|
||||
{
|
||||
m_Mobile.Target.Invoke(m_Mobile, stealc);
|
||||
}
|
||||
}
|
||||
|
||||
var steald = cpack.FindItemByType(typeof(MandrakeRoot));
|
||||
|
||||
if (steald != null)
|
||||
{
|
||||
m_Mobile.DebugSay("Trying to steal from combatant.");
|
||||
m_Mobile.UseSkill(SkillName.Stealing);
|
||||
|
||||
if (m_Mobile.Target != null)
|
||||
{
|
||||
m_Mobile.Target.Invoke(m_Mobile, steald);
|
||||
}
|
||||
}
|
||||
else if (steala == null && stealb == null && stealc == null && steald == null)
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.DebugSay("I should be closer to {0}", c.Name);
|
||||
}
|
||||
|
||||
if (!m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee)
|
||||
{
|
||||
if (m_Mobile.Hits < m_Mobile.HitsMax * 20 / 100)
|
||||
{
|
||||
// We are low on health, should we flee?
|
||||
if (Utility.Random(100) <= Math.Max(10, 10 + c.Hits - m_Mobile.Hits))
|
||||
{
|
||||
m_Mobile.DebugSay("I am going to flee from {0}", c.Name);
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
|
||||
{
|
||||
m_Mobile.DebugSay("I have detected {0}, attacking", m_Mobile.FocusMob.Name);
|
||||
|
||||
m_Mobile.Combatant = m_Mobile.FocusMob;
|
||||
Action = ActionType.Combat;
|
||||
}
|
||||
else
|
||||
{
|
||||
base.DoActionGuard();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
158
Scripts/Mobiles/AI/VendorAI.cs
Normal file
158
Scripts/Mobiles/AI/VendorAI.cs
Normal file
@@ -0,0 +1,158 @@
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class VendorAI : BaseAI
|
||||
{
|
||||
public VendorAI(BaseCreature m)
|
||||
: base(m)
|
||||
{ }
|
||||
|
||||
public override bool DoActionWander()
|
||||
{
|
||||
m_Mobile.DebugSay("I'm fine");
|
||||
|
||||
if (m_Mobile.Combatant != null)
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name);
|
||||
|
||||
if (m_Mobile.CanCallGuards)
|
||||
m_Mobile.Say(Utility.RandomList(1005305, 501603));
|
||||
|
||||
Action = ActionType.Flee;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.FocusMob != null)
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} has talked to me", m_Mobile.FocusMob.Name);
|
||||
|
||||
Action = ActionType.Interact;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Mobile.Warmode = false;
|
||||
|
||||
base.DoActionWander();
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionInteract()
|
||||
{
|
||||
var customer = m_Mobile.FocusMob as Mobile;
|
||||
|
||||
if (m_Mobile.Combatant != null)
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} is attacking me", m_Mobile.Combatant.Name);
|
||||
|
||||
if (m_Mobile.CanCallGuards)
|
||||
m_Mobile.Say(Utility.RandomList(1005305, 501603));
|
||||
|
||||
Action = ActionType.Flee;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (customer == null || customer.Deleted || customer.Map != m_Mobile.Map)
|
||||
{
|
||||
m_Mobile.DebugSay("My customer have disapeared");
|
||||
m_Mobile.FocusMob = null;
|
||||
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (customer.InRange(m_Mobile, m_Mobile.RangeFight))
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("I am with {0}", customer.Name);
|
||||
|
||||
if (!DirectionLocked)
|
||||
m_Mobile.Direction = m_Mobile.GetDirectionTo(customer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Mobile.Debug)
|
||||
m_Mobile.DebugSay("{0} is gone", customer.Name);
|
||||
|
||||
m_Mobile.FocusMob = null;
|
||||
|
||||
Action = ActionType.Wander;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override bool DoActionGuard()
|
||||
{
|
||||
m_Mobile.FocusMob = m_Mobile.Combatant as Mobile;
|
||||
return base.DoActionGuard();
|
||||
}
|
||||
|
||||
public override bool HandlesOnSpeech(Mobile from)
|
||||
{
|
||||
if (from.InRange(m_Mobile, 4))
|
||||
return true;
|
||||
|
||||
return base.HandlesOnSpeech(from);
|
||||
}
|
||||
|
||||
// Temporary
|
||||
public override void OnSpeech(SpeechEventArgs e)
|
||||
{
|
||||
base.OnSpeech(e);
|
||||
|
||||
var from = e.Mobile;
|
||||
|
||||
if (m_Mobile is BaseVendor && from.InRange(m_Mobile, Core.AOS ? 1 : 4) && !e.Handled)
|
||||
{
|
||||
if (e.HasKeyword(0x14D)) // *vendor sell*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
((BaseVendor)m_Mobile).VendorSell(from);
|
||||
m_Mobile.FocusMob = from;
|
||||
}
|
||||
else if (e.HasKeyword(0x3C)) // *vendor buy*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
((BaseVendor)m_Mobile).VendorBuy(from);
|
||||
m_Mobile.FocusMob = from;
|
||||
}
|
||||
else if (WasNamed(e.Speech))
|
||||
{
|
||||
if (e.HasKeyword(0x177)) // *sell*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
((BaseVendor)m_Mobile).VendorSell(from);
|
||||
}
|
||||
else if (e.HasKeyword(0x171)) // *buy*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
((BaseVendor)m_Mobile).VendorBuy(from);
|
||||
}
|
||||
|
||||
m_Mobile.FocusMob = from;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override double TransformMoveDelay(double delay)
|
||||
{
|
||||
if (m_Mobile is BaseVendor)
|
||||
{
|
||||
return ((BaseVendor)m_Mobile).GetMoveDelay;
|
||||
}
|
||||
|
||||
return base.TransformMoveDelay(delay);
|
||||
}
|
||||
}
|
||||
}
|
||||
426
Scripts/Mobiles/Bosses/AbyssalInfernal.cs
Normal file
426
Scripts/Mobiles/Bosses/AbyssalInfernal.cs
Normal file
@@ -0,0 +1,426 @@
|
||||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("an abyssal infernal corpse")]
|
||||
public class AbyssalInfernal : BaseChampion
|
||||
{
|
||||
private static Dictionary<Mobile, Point3D> m_Table = new Dictionary<Mobile, Point3D>();
|
||||
|
||||
private DateTime m_NextAbility;
|
||||
|
||||
[Constructable]
|
||||
public AbyssalInfernal()
|
||||
: base(AIType.AI_Mage)
|
||||
{
|
||||
Body = 713;
|
||||
Name = "Abyssal Infernal";
|
||||
|
||||
SetStr(1200, 1300);
|
||||
SetDex(100, 125);
|
||||
SetInt(600, 700);
|
||||
|
||||
SetHits(30000);
|
||||
SetStam(203, 650);
|
||||
|
||||
SetDamage(11, 18);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 60);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 50, 60);
|
||||
SetResistance(ResistanceType.Fire, 60, 70);
|
||||
SetResistance(ResistanceType.Cold, 50, 60);
|
||||
SetResistance(ResistanceType.Poison, 30, 40);
|
||||
SetResistance(ResistanceType.Energy, 70, 80);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 110.0, 120.0);
|
||||
SetSkill(SkillName.Magery, 130.0, 140.0);
|
||||
SetSkill(SkillName.EvalInt, 120.0, 140.0);
|
||||
SetSkill(SkillName.MagicResist, 120);
|
||||
SetSkill(SkillName.Tactics, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 110.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 100.0);
|
||||
|
||||
Fame = 28000;
|
||||
Karma = -28000;
|
||||
|
||||
VirtualArmor = 40;
|
||||
}
|
||||
|
||||
public AbyssalInfernal(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType { get { return ChampionSkullType.None; } }
|
||||
public override Type[] UniqueList { get { return new Type[] { typeof(TongueOfTheBeast), typeof(DeathsHead), typeof(WallOfHungryMouths), typeof(AbyssalBlade) }; } }
|
||||
public override Type[] SharedList { get { return new Type[] { typeof(RoyalGuardInvestigatorsCloak), typeof(DetectiveBoots), typeof(JadeArmband) }; } }
|
||||
public override Type[] DecorativeList { get { return new Type[] { typeof(MagicalDoor) }; } }
|
||||
public override MonsterStatuetteType[] StatueTypes { get { return new MonsterStatuetteType[] { MonsterStatuetteType.AbyssalInfernal, MonsterStatuetteType.ArchDemon }; } }
|
||||
|
||||
public override Poison PoisonImmune { get { return Poison.Lethal; } }
|
||||
|
||||
public override ScaleType ScaleType { get { return ScaleType.All; } }
|
||||
public override int Scales { get { return 20; } }
|
||||
|
||||
public override int GetAttackSound() { return 0x5D4; }
|
||||
public override int GetDeathSound() { return 0x5D5; }
|
||||
public override int GetHurtSound() { return 0x5D6; }
|
||||
public override int GetIdleSound() { return 0x5D7; }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.SuperBoss, 4);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
if (Utility.RandomBool())
|
||||
{
|
||||
switch (Utility.Random(2))
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new HornAbyssalInferno());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new NetherCycloneScroll());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (Combatant == null)
|
||||
return;
|
||||
|
||||
if (m_NextAbility < DateTime.UtcNow)
|
||||
{
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0: { DoCondemn(); break; }
|
||||
case 1: { DoSummon(); break; }
|
||||
case 2: { DoNuke(); break; }
|
||||
}
|
||||
|
||||
m_NextAbility = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(35, 45));
|
||||
}
|
||||
}
|
||||
|
||||
private Mobile GetRandomTarget(int range, bool playersOnly)
|
||||
{
|
||||
List<Mobile> list = GetTargets(range, playersOnly);
|
||||
Mobile m = null;
|
||||
|
||||
if (list != null && list.Count > 0)
|
||||
{
|
||||
m = list[Utility.Random(list.Count)];
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
private List<Mobile> GetTargets(int range, bool playersOnly)
|
||||
{
|
||||
List<Mobile> targets = new List<Mobile>();
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(range);
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == this || !CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if (!playersOnly && m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != Team))
|
||||
targets.Add(m);
|
||||
else if (m.Player)
|
||||
targets.Add(m);
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
#region Condemn
|
||||
private static Point3D[] _Locs = new Point3D[]
|
||||
{
|
||||
new Point3D(6949, 701, 32),
|
||||
new Point3D(6941, 761, 32),
|
||||
new Point3D(7015, 688, 32),
|
||||
new Point3D(7043, 751, 32),
|
||||
new Point3D(6999, 798, 32),
|
||||
};
|
||||
|
||||
public void DoCondemn()
|
||||
{
|
||||
Map map = Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Mobile toCondemn = GetRandomTarget(8, true);
|
||||
|
||||
if (toCondemn != null && !m_Table.ContainsKey(toCondemn))
|
||||
{
|
||||
m_Table[toCondemn] = toCondemn.Location;
|
||||
|
||||
var loc = _Locs[Utility.Random(_Locs.Length)];
|
||||
toCondemn.MoveToWorld(loc, map);
|
||||
|
||||
toCondemn.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
|
||||
toCondemn.PlaySound(0x1FE);
|
||||
|
||||
toCondemn.Frozen = true;
|
||||
|
||||
int seconds = 15;
|
||||
|
||||
BuffInfo.AddBuff(toCondemn, new BuffInfo(BuffIcon.TrueFear, 1153791, 1153827, TimeSpan.FromSeconds(seconds), toCondemn));
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(seconds), () =>
|
||||
{
|
||||
toCondemn.Frozen = false;
|
||||
toCondemn.SendLocalizedMessage(1005603); // You can move again!
|
||||
|
||||
loc = m_Table.ToList().Find(x => x.Key == toCondemn).Value;
|
||||
toCondemn.MoveToWorld(loc, map);
|
||||
|
||||
m_Table.Remove(toCondemn);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void DoNuke()
|
||||
{
|
||||
if (!Alive || Map == null)
|
||||
return;
|
||||
|
||||
Say(1112362); // You will burn to a pile of ash!
|
||||
|
||||
int range = 8;
|
||||
|
||||
Effects.PlaySound(Location, Map, 0x349);
|
||||
|
||||
//Flame Columns
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Misc.Geometry.Circle2D(Location, Map, i, (pnt, map) =>
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(pnt, map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
|
||||
});
|
||||
}
|
||||
|
||||
//Flash then boom
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
|
||||
{
|
||||
if (Alive && Map != null)
|
||||
{
|
||||
Effects.PlaySound(Location, Map, 0x44B);
|
||||
|
||||
Packet flash = ScreenLightFlash.Instance;
|
||||
IPooledEnumerable e = Map.GetClientsInRange(Location, (range * 4) + 5);
|
||||
|
||||
foreach (NetState ns in e)
|
||||
{
|
||||
if (ns.Mobile != null)
|
||||
ns.Mobile.Send(flash);
|
||||
}
|
||||
|
||||
e.Free();
|
||||
|
||||
for (int i = 0; i < range; i++)
|
||||
{
|
||||
Misc.Geometry.Circle2D(Location, Map, i, (pnt, map) =>
|
||||
{
|
||||
Effects.SendLocationEffect(pnt, map, 14000, 14, 10, Utility.RandomMinMax(2497, 2499), 2);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(range);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if ((m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile)) && CanBeHarmful(m))
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1.75), new TimerStateCallback(DoDamage_Callback), m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
private void DoDamage_Callback(object o)
|
||||
{
|
||||
Mobile m = o as Mobile;
|
||||
|
||||
if (m != null && Map != null)
|
||||
{
|
||||
IMount mount = m.Mount;
|
||||
|
||||
if (mount != null)
|
||||
{
|
||||
if (m is PlayerMobile)
|
||||
((PlayerMobile)m).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
|
||||
else
|
||||
mount.Rider = null;
|
||||
}
|
||||
else if (m.Flying)
|
||||
{
|
||||
((PlayerMobile)m).SetMountBlock(BlockMountType.Dazed, TimeSpan.FromSeconds(10), true);
|
||||
}
|
||||
|
||||
DoHarmful(m);
|
||||
AOS.Damage(m, this, Utility.RandomMinMax(90, 110), 0, 0, 0, 0, 100);
|
||||
|
||||
m.Frozen = true;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(3), () =>
|
||||
{
|
||||
m.Frozen = false;
|
||||
m.SendLocalizedMessage(1005603); // You can move again!
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Spawn
|
||||
public List<BaseCreature> SummonedHelpers { get; set; }
|
||||
|
||||
private static Type[] SummonTypes = new Type[]
|
||||
{
|
||||
typeof(HellHound), typeof(Phoenix),
|
||||
typeof(FireSteed), typeof(FireElemental),
|
||||
typeof(LavaElemental), typeof(FireGargoyle),
|
||||
typeof(Efreet), typeof(Gargoyle),
|
||||
typeof(Nightmare), typeof(HellCat)
|
||||
};
|
||||
|
||||
public int TotalSummons()
|
||||
{
|
||||
if (SummonedHelpers == null || SummonedHelpers.Count == 0)
|
||||
return 0;
|
||||
|
||||
return SummonedHelpers.Where(bc => bc != null && bc.Alive).Count();
|
||||
}
|
||||
|
||||
public virtual void DoSummon()
|
||||
{
|
||||
if (Map == null || TotalSummons() > 0)
|
||||
return;
|
||||
|
||||
Type type = SummonTypes[Utility.Random(SummonTypes.Length)];
|
||||
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (Combatant == null)
|
||||
return;
|
||||
|
||||
Point3D p = Combatant.Location;
|
||||
|
||||
for (int j = 0; j < 10; j++)
|
||||
{
|
||||
int x = Utility.RandomMinMax(p.X - 3, p.X + 3);
|
||||
int y = Utility.RandomMinMax(p.Y - 3, p.Y + 3);
|
||||
int z = Map.GetAverageZ(x, y);
|
||||
|
||||
if (Map.CanSpawnMobile(x, y, z))
|
||||
{
|
||||
p = new Point3D(x, y, z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BaseCreature spawn = Activator.CreateInstance(type) as BaseCreature;
|
||||
|
||||
if (spawn != null)
|
||||
{
|
||||
spawn.MoveToWorld(p, Map);
|
||||
spawn.Team = Team;
|
||||
spawn.SummonMaster = this;
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), (o) =>
|
||||
{
|
||||
BaseCreature s = o as BaseCreature;
|
||||
|
||||
if (s != null && s.Combatant != null)
|
||||
{
|
||||
if (!(s.Combatant is PlayerMobile) || !((PlayerMobile)s.Combatant).HonorActive)
|
||||
s.Combatant = Combatant;
|
||||
}
|
||||
|
||||
}, spawn);
|
||||
|
||||
AddHelper(spawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void AddHelper(BaseCreature bc)
|
||||
{
|
||||
if (SummonedHelpers == null)
|
||||
SummonedHelpers = new List<BaseCreature>();
|
||||
|
||||
if (!SummonedHelpers.Contains(bc))
|
||||
SummonedHelpers.Add(bc);
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
|
||||
if (SummonedHelpers != null)
|
||||
{
|
||||
ColUtility.Free(SummonedHelpers);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
|
||||
writer.Write(SummonedHelpers == null ? 0 : SummonedHelpers.Count);
|
||||
|
||||
if (SummonedHelpers != null)
|
||||
SummonedHelpers.ForEach(m => writer.Write(m));
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
|
||||
int count = reader.ReadInt();
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
BaseCreature summon = reader.ReadMobile() as BaseCreature;
|
||||
|
||||
if (summon != null)
|
||||
{
|
||||
if (SummonedHelpers == null)
|
||||
SummonedHelpers = new List<BaseCreature>();
|
||||
|
||||
SummonedHelpers.Add(summon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_NextAbility = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
360
Scripts/Mobiles/Bosses/Barracoon.cs
Normal file
360
Scripts/Mobiles/Bosses/Barracoon.cs
Normal file
@@ -0,0 +1,360 @@
|
||||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
using Server.Spells.Fifth;
|
||||
using Server.Spells.Seventh;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Barracoon : BaseChampion
|
||||
{
|
||||
[Constructable]
|
||||
public Barracoon()
|
||||
: base(AIType.AI_Melee)
|
||||
{
|
||||
Name = "Barracoon";
|
||||
Title = "the piper";
|
||||
Body = 0x190;
|
||||
Hue = 0x83EC;
|
||||
|
||||
SetStr(283, 425);
|
||||
SetDex(72, 150);
|
||||
SetInt(505, 750);
|
||||
|
||||
SetHits(12000);
|
||||
SetStam(102, 300);
|
||||
SetMana(505, 750);
|
||||
|
||||
SetDamage(29, 38);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 65, 75);
|
||||
SetResistance(ResistanceType.Fire, 70, 80);
|
||||
SetResistance(ResistanceType.Cold, 65, 80);
|
||||
SetResistance(ResistanceType.Poison, 70, 75);
|
||||
SetResistance(ResistanceType.Energy, 70, 80);
|
||||
|
||||
SetSkill(SkillName.MagicResist, 100.0);
|
||||
SetSkill(SkillName.Tactics, 118.3, 120.2);
|
||||
SetSkill(SkillName.Wrestling, 118.4, 122.7);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
VirtualArmor = 70;
|
||||
|
||||
AddItem(new FancyShirt(Utility.RandomGreenHue()));
|
||||
AddItem(new LongPants(Utility.RandomYellowHue()));
|
||||
AddItem(new JesterHat(Utility.RandomPinkHue()));
|
||||
AddItem(new Cloak(Utility.RandomPinkHue()));
|
||||
AddItem(new Sandals());
|
||||
|
||||
HairItemID = 0x203B; // Short Hair
|
||||
HairHue = 0x94;
|
||||
|
||||
m_SpecialSlayerMechanics = true;
|
||||
}
|
||||
|
||||
public Barracoon(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Greed;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(FangOfRactus) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(EmbroideredOakLeafCloak),
|
||||
typeof(DjinnisRing),
|
||||
typeof(DetectiveBoots),
|
||||
typeof(GauntletsOfAnger)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(SwampTile), typeof(MonsterStatuette) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { MonsterStatuetteType.Slime };
|
||||
}
|
||||
}
|
||||
public override bool AlwaysMurderer
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override double AutoDispelChance
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
public override bool BardImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool AllureImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool Uncalmable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Deadly;
|
||||
}
|
||||
}
|
||||
public override bool ShowFameTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool ClickTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ForceStayHome { get { return true; } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 3);
|
||||
}
|
||||
|
||||
public void Polymorph(Mobile m)
|
||||
{
|
||||
if (!m.CanBeginAction(typeof(PolymorphSpell)) || !m.CanBeginAction(typeof(IncognitoSpell)) || m.IsBodyMod)
|
||||
return;
|
||||
|
||||
IMount mount = m.Mount;
|
||||
|
||||
if (mount != null)
|
||||
mount.Rider = null;
|
||||
|
||||
if (m.Flying)
|
||||
m.ToggleFlying();
|
||||
|
||||
if (m.Mounted)
|
||||
return;
|
||||
|
||||
if (m.BeginAction(typeof(PolymorphSpell)))
|
||||
{
|
||||
m.BodyMod = 42;
|
||||
m.HueMod = 0;
|
||||
if (m == this) {
|
||||
m_SlayerVulnerabilities.Add("Vermin");
|
||||
m_SlayerVulnerabilities.Add("Repond");
|
||||
}
|
||||
|
||||
new ExpirePolymorphTimer(m).Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnRatmen(Mobile target)
|
||||
{
|
||||
Map map = Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
int rats = 0;
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(10);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m is Ratman || m is RatmanArcher || m is RatmanMage)
|
||||
++rats;
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (rats < 16)
|
||||
{
|
||||
PlaySound(0x3D);
|
||||
|
||||
int newRats = Utility.RandomMinMax(3, 6);
|
||||
|
||||
for (int i = 0; i < newRats; ++i)
|
||||
{
|
||||
BaseCreature rat;
|
||||
|
||||
switch ( Utility.Random(5) )
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
case 1:
|
||||
rat = new Ratman();
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
rat = new RatmanArcher();
|
||||
break;
|
||||
case 4:
|
||||
rat = new RatmanMage();
|
||||
break;
|
||||
}
|
||||
|
||||
rat.Team = Team;
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = X + Utility.Random(3) - 1;
|
||||
int y = Y + Utility.Random(3) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
|
||||
loc = new Point3D(x, y, Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
rat.IsChampionSpawn = true;
|
||||
rat.MoveToWorld(loc, map);
|
||||
rat.Combatant = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DoSpecialAbility(Mobile target)
|
||||
{
|
||||
if (target == null || target.Deleted) //sanity
|
||||
return;
|
||||
|
||||
if (target.Player && 0.6 >= Utility.RandomDouble()) // 60% chance to polymorph attacker into a ratman
|
||||
Polymorph(target);
|
||||
|
||||
if (0.1 >= Utility.RandomDouble()) // 10% chance to more ratmen
|
||||
SpawnRatmen(target);
|
||||
|
||||
if (0.05 >= Utility.RandomDouble() && !IsBodyMod) // 5% chance to polymorph into a ratman
|
||||
Polymorph(this);
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
DoSpecialAbility(attacker);
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
DoSpecialAbility(defender);
|
||||
}
|
||||
|
||||
public override void OnDamagedBySpell(Mobile from)
|
||||
{
|
||||
base.OnDamagedBySpell(from);
|
||||
|
||||
DoSpecialAbility(from);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_SlayerVulnerabilities.Clear();
|
||||
}
|
||||
|
||||
private class ExpirePolymorphTimer : Timer
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
public ExpirePolymorphTimer(Mobile owner)
|
||||
: base(TimeSpan.FromMinutes(3.0)) //3.0
|
||||
{
|
||||
m_Owner = owner;
|
||||
|
||||
Priority = TimerPriority.OneSecond;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!m_Owner.CanBeginAction(typeof(PolymorphSpell)))
|
||||
{
|
||||
m_Owner.BodyMod = 0;
|
||||
m_Owner.HueMod = -1;
|
||||
m_Owner.EndAction(typeof(PolymorphSpell));
|
||||
if (m_Owner.SlayerVulnerabilities != null)
|
||||
{
|
||||
m_Owner.SlayerVulnerabilities.Remove("Vermin");
|
||||
m_Owner.SlayerVulnerabilities.Remove("Repond");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
302
Scripts/Mobiles/Bosses/BaseChampion.cs
Normal file
302
Scripts/Mobiles/Bosses/BaseChampion.cs
Normal file
@@ -0,0 +1,302 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
using Server.Services.Virtues;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public abstract class BaseChampion : BaseCreature
|
||||
{
|
||||
public BaseChampion(AIType aiType)
|
||||
: this(aiType, FightMode.Closest)
|
||||
{
|
||||
}
|
||||
|
||||
public BaseChampion(AIType aiType, FightMode mode)
|
||||
: base(aiType, mode, 18, 1, 0.1, 0.2)
|
||||
{
|
||||
}
|
||||
|
||||
public BaseChampion(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
public override bool CanBeParagon { get { return false; } }
|
||||
public abstract ChampionSkullType SkullType { get; }
|
||||
public abstract Type[] UniqueList { get; }
|
||||
public abstract Type[] SharedList { get; }
|
||||
public abstract Type[] DecorativeList { get; }
|
||||
public abstract MonsterStatuetteType[] StatueTypes { get; }
|
||||
public virtual bool NoGoodies
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CanGivePowerscrolls { get { return true; } }
|
||||
|
||||
public static void GivePowerScrollTo(Mobile m, Item item, BaseChampion champ)
|
||||
{
|
||||
if (m == null) //sanity
|
||||
return;
|
||||
|
||||
if (!Core.SE || m.Alive)
|
||||
m.AddToBackpack(item);
|
||||
else
|
||||
{
|
||||
if (m.Corpse != null && !m.Corpse.Deleted)
|
||||
m.Corpse.DropItem(item);
|
||||
else
|
||||
m.AddToBackpack(item);
|
||||
}
|
||||
|
||||
if (item is PowerScroll && m is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = (PlayerMobile)m;
|
||||
|
||||
for (int j = 0; j < pm.JusticeProtectors.Count; ++j)
|
||||
{
|
||||
Mobile prot = pm.JusticeProtectors[j];
|
||||
|
||||
if (prot.Map != m.Map || prot.Murderer || prot.Criminal || !JusticeVirtue.CheckMapRegion(m, prot) || !prot.InRange(champ, 100))
|
||||
continue;
|
||||
|
||||
int chance = 0;
|
||||
|
||||
switch( VirtueHelper.GetLevel(prot, VirtueName.Justice) )
|
||||
{
|
||||
case VirtueLevel.Seeker:
|
||||
chance = 60;
|
||||
break;
|
||||
case VirtueLevel.Follower:
|
||||
chance = 80;
|
||||
break;
|
||||
case VirtueLevel.Knight:
|
||||
chance = 100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chance > Utility.Random(100))
|
||||
{
|
||||
PowerScroll powerScroll = CreateRandomPowerScroll();
|
||||
|
||||
prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
|
||||
|
||||
if (!Core.SE || prot.Alive)
|
||||
prot.AddToBackpack(powerScroll);
|
||||
else
|
||||
{
|
||||
if (prot.Corpse != null && !prot.Corpse.Deleted)
|
||||
prot.Corpse.DropItem(powerScroll);
|
||||
else
|
||||
prot.AddToBackpack(powerScroll);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public virtual Item GetArtifact()
|
||||
{
|
||||
double random = Utility.RandomDouble();
|
||||
if (0.05 >= random)
|
||||
return this.CreateArtifact(this.UniqueList);
|
||||
else if (0.15 >= random)
|
||||
return this.CreateArtifact(this.SharedList);
|
||||
else if (0.30 >= random)
|
||||
return this.CreateArtifact(this.DecorativeList);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Item CreateArtifact(Type[] list)
|
||||
{
|
||||
if (list.Length == 0)
|
||||
return null;
|
||||
|
||||
int random = Utility.Random(list.Length);
|
||||
|
||||
Type type = list[random];
|
||||
|
||||
Item artifact = Loot.Construct(type);
|
||||
|
||||
if (artifact is MonsterStatuette && this.StatueTypes.Length > 0)
|
||||
{
|
||||
((MonsterStatuette)artifact).Type = this.StatueTypes[Utility.Random(this.StatueTypes.Length)];
|
||||
((MonsterStatuette)artifact).LootType = LootType.Regular;
|
||||
}
|
||||
|
||||
return artifact;
|
||||
}
|
||||
|
||||
public virtual void GivePowerScrolls()
|
||||
{
|
||||
if (this.Map != Map.Felucca)
|
||||
return;
|
||||
|
||||
List<Mobile> toGive = new List<Mobile>();
|
||||
List<DamageStore> rights = GetLootingRights();
|
||||
|
||||
for (int i = rights.Count - 1; i >= 0; --i)
|
||||
{
|
||||
DamageStore ds = rights[i];
|
||||
|
||||
if (ds.m_HasRight && InRange(ds.m_Mobile, 100) && ds.m_Mobile.Map == this.Map)
|
||||
toGive.Add(ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (toGive.Count == 0)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < toGive.Count; i++)
|
||||
{
|
||||
Mobile m = toGive[i];
|
||||
|
||||
if (!(m is PlayerMobile))
|
||||
continue;
|
||||
|
||||
bool gainedPath = false;
|
||||
|
||||
int pointsToGain = 800;
|
||||
|
||||
if (VirtueHelper.Award(m, VirtueName.Valor, pointsToGain, ref gainedPath))
|
||||
{
|
||||
if (gainedPath)
|
||||
m.SendLocalizedMessage(1054032); // You have gained a path in Valor!
|
||||
else
|
||||
m.SendLocalizedMessage(1054030); // You have gained in Valor!
|
||||
//No delay on Valor gains
|
||||
}
|
||||
}
|
||||
|
||||
// Randomize - PowerScrolls
|
||||
for (int i = 0; i < toGive.Count; ++i)
|
||||
{
|
||||
int rand = Utility.Random(toGive.Count);
|
||||
Mobile hold = toGive[i];
|
||||
toGive[i] = toGive[rand];
|
||||
toGive[rand] = hold;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ChampionSystem.PowerScrollAmount; ++i)
|
||||
{
|
||||
Mobile m = toGive[i % toGive.Count];
|
||||
|
||||
PowerScroll ps = CreateRandomPowerScroll();
|
||||
m.SendLocalizedMessage(1049524); // You have received a scroll of power!
|
||||
|
||||
GivePowerScrollTo(m, ps, this);
|
||||
}
|
||||
|
||||
if (Core.TOL)
|
||||
{
|
||||
// Randomize - Primers
|
||||
for (int i = 0; i < toGive.Count; ++i)
|
||||
{
|
||||
int rand = Utility.Random(toGive.Count);
|
||||
Mobile hold = toGive[i];
|
||||
toGive[i] = toGive[rand];
|
||||
toGive[rand] = hold;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ChampionSystem.PowerScrollAmount; ++i)
|
||||
{
|
||||
Mobile m = toGive[i % toGive.Count];
|
||||
|
||||
SkillMasteryPrimer p = CreateRandomPrimer();
|
||||
m.SendLocalizedMessage(1156209); // You have received a mastery primer!
|
||||
|
||||
GivePowerScrollTo(m, p, this);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(toGive);
|
||||
}
|
||||
|
||||
public virtual void OnChampPopped(ChampionSpawn spawn)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
if (CanGivePowerscrolls && !NoKillAwards)
|
||||
{
|
||||
this.GivePowerScrolls();
|
||||
|
||||
if (this.NoGoodies)
|
||||
return base.OnBeforeDeath();
|
||||
|
||||
GoldShower.DoForChamp(Location, Map);
|
||||
}
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
if (this.Map == Map.Felucca)
|
||||
{
|
||||
//TODO: Confirm SE change or AoS one too?
|
||||
List<DamageStore> rights = GetLootingRights();
|
||||
List<Mobile> toGive = new List<Mobile>();
|
||||
|
||||
for (int i = rights.Count - 1; i >= 0; --i)
|
||||
{
|
||||
DamageStore ds = rights[i];
|
||||
|
||||
if (ds.m_HasRight)
|
||||
toGive.Add(ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (SkullType != ChampionSkullType.None)
|
||||
{
|
||||
if (toGive.Count > 0)
|
||||
toGive[Utility.Random(toGive.Count)].AddToBackpack(new ChampionSkull(this.SkullType));
|
||||
else
|
||||
c.DropItem(new ChampionSkull(this.SkullType));
|
||||
}
|
||||
|
||||
if(Core.SA)
|
||||
RefinementComponent.Roll(c, 3, 0.10);
|
||||
}
|
||||
|
||||
base.OnDeath(c);
|
||||
}
|
||||
|
||||
private static PowerScroll CreateRandomPowerScroll()
|
||||
{
|
||||
int level;
|
||||
double random = Utility.RandomDouble();
|
||||
|
||||
if (0.05 >= random)
|
||||
level = 20;
|
||||
else if (0.4 >= random)
|
||||
level = 15;
|
||||
else
|
||||
level = 10;
|
||||
|
||||
return PowerScroll.CreateRandomNoCraft(level, level);
|
||||
}
|
||||
|
||||
private static SkillMasteryPrimer CreateRandomPrimer()
|
||||
{
|
||||
return SkillMasteryPrimer.GetRandom();
|
||||
}
|
||||
}
|
||||
}
|
||||
182
Scripts/Mobiles/Bosses/ChiefParoxysmus.cs
Normal file
182
Scripts/Mobiles/Bosses/ChiefParoxysmus.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a chief paroxysmus corpse")]
|
||||
public class ChiefParoxysmus : BasePeerless
|
||||
{
|
||||
[Constructable]
|
||||
public ChiefParoxysmus()
|
||||
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a chief paroxysmus";
|
||||
Body = 0x100;
|
||||
|
||||
SetStr(1232, 1400);
|
||||
SetDex(76, 82);
|
||||
SetInt(76, 85);
|
||||
|
||||
SetHits(50000);
|
||||
|
||||
SetDamage(27, 31);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 80);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 75, 85);
|
||||
SetResistance(ResistanceType.Fire, 40, 50);
|
||||
SetResistance(ResistanceType.Cold, 50, 60);
|
||||
SetResistance(ResistanceType.Poison, 55, 65);
|
||||
SetResistance(ResistanceType.Energy, 50, 60);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 120.0);
|
||||
SetSkill(SkillName.Tactics, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 120.0);
|
||||
SetSkill(SkillName.Poisoning, 120.0);
|
||||
|
||||
PackResources(8);
|
||||
PackTalismans(5);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerCallback(SpawnBulbous)); //BulbousPutrification
|
||||
|
||||
Fame = 25000;
|
||||
Karma = -25000;
|
||||
|
||||
SetAreaEffect(AreaEffect.PoisonBreath);
|
||||
}
|
||||
|
||||
public ChiefParoxysmus(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool GivesMLMinorArtifact
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 8);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new LardOfParoxysmus());
|
||||
|
||||
switch ( Utility.Random(3) )
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new ParoxysmusDinner());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new ParoxysmusCorrodedStein());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new StringOfPartsOfParoxysmusVictims());
|
||||
break;
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < 0.6)
|
||||
c.DropItem(new ParrotItem());
|
||||
|
||||
if (Utility.RandomBool())
|
||||
c.DropItem(new SweatOfParoxysmus());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new ParoxysmusSwampDragonStatuette());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new ScepterOfTheChief());
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x56F;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return 0x570;
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x571;
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return 0x572;
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x573;
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
base.OnDamage(amount, from, willKill);
|
||||
|
||||
// eats pet or summons
|
||||
if (from is BaseCreature)
|
||||
{
|
||||
BaseCreature creature = (BaseCreature)from;
|
||||
|
||||
if (creature.Controlled || creature.Summoned)
|
||||
{
|
||||
Heal(creature.Hits);
|
||||
creature.Kill();
|
||||
|
||||
Effects.PlaySound(Location, Map, 0x574);
|
||||
}
|
||||
}
|
||||
|
||||
// teleports player near
|
||||
if (from is PlayerMobile && !InRange(from.Location, 1))
|
||||
{
|
||||
Combatant = from;
|
||||
|
||||
from.MoveToWorld(GetSpawnPosition(1), Map);
|
||||
from.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
|
||||
from.PlaySound(0x1FE);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public virtual void SpawnBulbous()
|
||||
{
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
SpawnHelper(new BulbousPutrification(), GetSpawnPosition(4));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
364
Scripts/Mobiles/Bosses/CrimsonDragon.cs
Normal file
364
Scripts/Mobiles/Bosses/CrimsonDragon.cs
Normal file
@@ -0,0 +1,364 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a crimson dragon corpse")]
|
||||
public class CrimsonDragon : BasePeerless
|
||||
{
|
||||
public override bool GiveMLSpecial { get { return false; } }
|
||||
|
||||
private DateTime m_NextTerror;
|
||||
[Constructable]
|
||||
public CrimsonDragon()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a crimson dragon";
|
||||
Body = 197;
|
||||
|
||||
BaseSoundID = 362;
|
||||
SetStr(2034, 2140);
|
||||
SetDex(215, 256);
|
||||
SetInt(1025, 1116);
|
||||
|
||||
SetHits(25000);
|
||||
|
||||
SetDamage(8, 10);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Fire, 50);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 80, 85);
|
||||
SetResistance(ResistanceType.Fire, 100);
|
||||
SetResistance(ResistanceType.Cold, 50, 60);
|
||||
SetResistance(ResistanceType.Poison, 80, 85);
|
||||
SetResistance(ResistanceType.Energy, 80, 85);
|
||||
|
||||
SetSkill(SkillName.EvalInt, 110.2, 125.3);
|
||||
SetSkill(SkillName.Magery, 110.9, 125.5);
|
||||
SetSkill(SkillName.MagicResist, 116.3, 125.0);
|
||||
SetSkill(SkillName.Tactics, 111.7, 126.3);
|
||||
SetSkill(SkillName.Wrestling, 120.5, 128.0);
|
||||
SetSkill(SkillName.Meditation, 119.4, 130.0);
|
||||
SetSkill(SkillName.Anatomy, 118.7, 125.0);
|
||||
SetSkill(SkillName.DetectHidden, 120.0);
|
||||
|
||||
// ingredients
|
||||
PackResources(8);
|
||||
|
||||
Fame = 20000;
|
||||
Karma = -20000;
|
||||
|
||||
VirtualArmor = 70;
|
||||
|
||||
SetSpecialAbility(SpecialAbility.DragonBreath);
|
||||
}
|
||||
|
||||
public CrimsonDragon(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool AlwaysMurderer
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool BardImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ReacquireOnMovement
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Uncalmable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override int Meat
|
||||
{
|
||||
get
|
||||
{
|
||||
return 19;
|
||||
}
|
||||
}
|
||||
public override int Hides
|
||||
{
|
||||
get
|
||||
{
|
||||
return 40;
|
||||
}
|
||||
}
|
||||
public override HideType HideType
|
||||
{
|
||||
get
|
||||
{
|
||||
return HideType.Barbed;
|
||||
}
|
||||
}
|
||||
public override int Scales
|
||||
{
|
||||
get
|
||||
{
|
||||
return 12;
|
||||
}
|
||||
}
|
||||
public override ScaleType ScaleType
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ScaleType)Utility.Random(4);
|
||||
}
|
||||
}
|
||||
public override FoodType FavoriteFood
|
||||
{
|
||||
get
|
||||
{
|
||||
return FoodType.Meat;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override Poison HitPoison
|
||||
{
|
||||
get
|
||||
{
|
||||
return Utility.RandomBool() ? Poison.Deadly : Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 8);
|
||||
AddLoot(LootPack.Gems, 12);
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x2D3;
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x2D1;
|
||||
}
|
||||
|
||||
public override void OnDamagedBySpell(Mobile caster)
|
||||
{
|
||||
if (Map != null && caster != this && 0.50 > Utility.RandomDouble())
|
||||
{
|
||||
Map = caster.Map;
|
||||
Location = caster.Location;
|
||||
Combatant = caster;
|
||||
Effects.PlaySound(Location, Map, 0x1FE);
|
||||
}
|
||||
|
||||
base.OnDamagedBySpell(caster);
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
base.OnMovement(m, oldLocation);
|
||||
|
||||
if (m_NextTerror < DateTime.UtcNow && m != null && InRange(m.Location, 3) && m.IsPlayer())
|
||||
{
|
||||
m.Frozen = true;
|
||||
m.SendLocalizedMessage(1080342, Name, 33); // Terror slices into your very being, destroying any chance of resisting ~1_name~ you might have had
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(5), new TimerStateCallback(Terrorize), m);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
if (Map != null && attacker != this && 0.1 > Utility.RandomDouble())
|
||||
{
|
||||
if (attacker is BaseCreature)
|
||||
{
|
||||
BaseCreature pet = (BaseCreature)attacker;
|
||||
if (pet.ControlMaster != null && (attacker is Dragon || attacker is GreaterDragon || attacker is SkeletalDragon || attacker is WhiteWyrm || attacker is Drake))
|
||||
{
|
||||
Combatant = null;
|
||||
pet.Combatant = null;
|
||||
Combatant = null;
|
||||
pet.ControlMaster = null;
|
||||
pet.Controlled = false;
|
||||
attacker.Emote(String.Format("* {0} decided to go wild *", attacker.Name));
|
||||
}
|
||||
|
||||
if (pet.ControlMaster != null && 0.1 > Utility.RandomDouble())
|
||||
{
|
||||
Combatant = null;
|
||||
pet.Combatant = pet.ControlMaster;
|
||||
Combatant = null;
|
||||
attacker.Emote(String.Format("* {0} is being angered *", attacker.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
Hue = 16385;
|
||||
|
||||
if (!NoKillAwards)
|
||||
{
|
||||
Map map = Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
for (int x = -7; x <= 7; ++x)
|
||||
{
|
||||
for (int y = -7; y <= 3; ++y)
|
||||
{
|
||||
double dist = Math.Sqrt(x * x + y * y);
|
||||
|
||||
if (dist <= 12)
|
||||
new GoodiesTimer(map, X + x, Y + y).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
if (Utility.RandomDouble() < 0.6)
|
||||
c.DropItem(new ParrotItem());
|
||||
|
||||
if (Utility.RandomDouble() < 0.025)
|
||||
c.DropItem(new CrimsonCincture());
|
||||
}
|
||||
|
||||
private void Terrorize(object o)
|
||||
{
|
||||
if (o is Mobile)
|
||||
{
|
||||
Mobile m = (Mobile)o;
|
||||
|
||||
m.Frozen = false;
|
||||
m.SendLocalizedMessage(1005603); // You can move again!
|
||||
|
||||
m_NextTerror = DateTime.UtcNow + TimeSpan.FromMinutes(5);
|
||||
}
|
||||
}
|
||||
|
||||
private class GoodiesTimer : Timer
|
||||
{
|
||||
private readonly Map m_Map;
|
||||
private readonly int m_X;
|
||||
private readonly int m_Y;
|
||||
public GoodiesTimer(Map map, int x, int y)
|
||||
: base(TimeSpan.FromSeconds(Utility.RandomDouble() * 10.0))
|
||||
{
|
||||
m_Map = map;
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
int z = m_Map.GetAverageZ(m_X, m_Y);
|
||||
bool canFit = m_Map.CanFit(m_X, m_Y, z, 6, false, false);
|
||||
|
||||
for (int i = -3; !canFit && i <= 3; ++i)
|
||||
{
|
||||
canFit = m_Map.CanFit(m_X, m_Y, z + i, 6, false, false);
|
||||
|
||||
if (canFit)
|
||||
z += i;
|
||||
}
|
||||
|
||||
if (!canFit)
|
||||
return;
|
||||
|
||||
Gold g = new Gold(300, 500);
|
||||
|
||||
g.MoveToWorld(new Point3D(m_X, m_Y, z), m_Map);
|
||||
|
||||
if (0.5 >= Utility.RandomDouble())
|
||||
{
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0: // Fire column
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x3709, 10, 30, 5052);
|
||||
Effects.PlaySound(g, g.Map, 0x208);
|
||||
|
||||
break;
|
||||
}
|
||||
case 1: // Explosion
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x36BD, 20, 10, 5044);
|
||||
Effects.PlaySound(g, g.Map, 0x307);
|
||||
|
||||
break;
|
||||
}
|
||||
case 2: // Ball of fire
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(g.Location, g.Map, EffectItem.DefaultDuration), 0x36FE, 10, 10, 5052);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
490
Scripts/Mobiles/Bosses/DespiseBosses.cs
Normal file
490
Scripts/Mobiles/Bosses/DespiseBosses.cs
Normal file
@@ -0,0 +1,490 @@
|
||||
using Server;
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Despise
|
||||
{
|
||||
public class DespiseBoss : BaseCreature
|
||||
{
|
||||
public static readonly int ArtifactChance = 5;
|
||||
|
||||
public virtual BaseCreature SummonWisp { get { return null; } }
|
||||
public virtual double WispScalar { get { return 0.33; } }
|
||||
|
||||
private BaseCreature m_Wisp;
|
||||
private Timer m_SummonTimer;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public BaseCreature Wisp { get { return m_Wisp; } }
|
||||
|
||||
public DespiseBoss(AIType ai, FightMode fightmode) : base(ai, fightmode, 10, 1, .1, .2)
|
||||
{
|
||||
m_SummonTimer = Timer.DelayCall(TimeSpan.FromSeconds(5), new TimerCallback(SummonWisp_Callback));
|
||||
|
||||
FollowersMax = 100;
|
||||
}
|
||||
|
||||
public void SetNonMovable(Item item)
|
||||
{
|
||||
item.Movable = false;
|
||||
AddItem(item);
|
||||
}
|
||||
|
||||
public override int Damage(int amount, Mobile from, bool informMount, bool checkDisrupt)
|
||||
{
|
||||
if (from is DespiseCreature)
|
||||
return base.Damage(amount, from, informMount, checkDisrupt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void OnKilledBy( Mobile mob )
|
||||
{
|
||||
if(mob is PlayerMobile)
|
||||
{
|
||||
int chance = ArtifactChance + (int)Math.Min(10, ((PlayerMobile)mob).Luck / 180);
|
||||
|
||||
if (chance >= Utility.Random(100))
|
||||
{
|
||||
Type t = m_Artifacts[Utility.Random(m_Artifacts.Length)];
|
||||
|
||||
if (t != null)
|
||||
{
|
||||
Item arty = Loot.Construct(t);
|
||||
|
||||
if (arty != null)
|
||||
{
|
||||
Container pack = mob.Backpack;
|
||||
|
||||
if (pack == null || !pack.TryDropItem(mob, arty, false))
|
||||
{
|
||||
mob.BankBox.DropItem(arty);
|
||||
mob.SendMessage("An artifact has been placed in your bankbox!");
|
||||
}
|
||||
else
|
||||
mob.SendLocalizedMessage(1153440); // An artifact has been placed in your backpack!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterMeleeDamageTo(Mobile to, ref int damage)
|
||||
{
|
||||
base.AlterMeleeDamageTo(to, ref damage);
|
||||
|
||||
if(m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
|
||||
damage += (int)((double)damage * WispScalar);
|
||||
}
|
||||
|
||||
public override void AlterMeleeDamageFrom(Mobile from, ref int damage)
|
||||
{
|
||||
base.AlterMeleeDamageFrom(from, ref damage);
|
||||
|
||||
if(m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
|
||||
damage -= (int)((double)damage * WispScalar);
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageTo(Mobile to, ref int damage)
|
||||
{
|
||||
base.AlterSpellDamageTo(to, ref damage);
|
||||
|
||||
if (m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
|
||||
damage += (int)((double)damage * WispScalar);
|
||||
}
|
||||
|
||||
public override void AlterSpellDamageFrom(Mobile from, ref int damage)
|
||||
{
|
||||
base.AlterSpellDamageFrom(from, ref damage);
|
||||
|
||||
if (m_Wisp != null && !m_Wisp.Deleted && m_Wisp.Alive)
|
||||
damage -= (int)((double)damage * WispScalar);
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if(m_SummonTimer == null && (m_Wisp == null || !m_Wisp.Alive || m_Wisp.Deleted))
|
||||
{
|
||||
m_SummonTimer = Timer.DelayCall(TimeSpan.FromSeconds(Utility.RandomMinMax(40, 60)), new TimerCallback(SummonWisp_Callback));
|
||||
}
|
||||
}
|
||||
|
||||
public void SummonWisp_Callback()
|
||||
{
|
||||
m_Wisp = SummonWisp;
|
||||
BaseCreature.Summon(m_Wisp, true, this, this.Location, 0, TimeSpan.FromMinutes(90));
|
||||
|
||||
m_SummonTimer = null;
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
|
||||
if (m_Wisp != null && m_Wisp.Alive)
|
||||
m_Wisp.Kill();
|
||||
}
|
||||
|
||||
public static Type[] Artifacts { get { return m_Artifacts; } }
|
||||
|
||||
private static Type[] m_Artifacts = new Type[]
|
||||
{
|
||||
typeof(CompassionsEye),
|
||||
typeof(UnicornManeWovenSandals),
|
||||
typeof(UnicornManeWovenTalons),
|
||||
typeof(DespicableQuiver),
|
||||
typeof(UnforgivenVeil),
|
||||
typeof(HailstormHuman),
|
||||
typeof(HailstormGargoyle),
|
||||
};
|
||||
|
||||
public DespiseBoss(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
writer.Write(m_Wisp);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
m_Wisp = reader.ReadMobile() as BaseCreature;
|
||||
}
|
||||
}
|
||||
|
||||
public class AdrianTheGloriousLord : DespiseBoss
|
||||
{
|
||||
[Constructable]
|
||||
public AdrianTheGloriousLord() : base(AIType.AI_Mage, FightMode.Closest)
|
||||
{
|
||||
Name = "Adrian";
|
||||
Title = "the Glorious Lord";
|
||||
|
||||
Race = Race.Human;
|
||||
Body = 0x190;
|
||||
Female = false;
|
||||
|
||||
Hue = Race.RandomSkinHue();
|
||||
HairItemID = 8252;
|
||||
HairHue = 153;
|
||||
|
||||
SetStr( 900, 1200 );
|
||||
SetDex( 500, 600 );
|
||||
SetInt( 500, 600 );
|
||||
|
||||
SetHits( 60000 );
|
||||
SetStam( 415 );
|
||||
SetMana( 22000 );
|
||||
|
||||
SetDamage( 18, 28 );
|
||||
|
||||
SetDamageType( ResistanceType.Physical, 100 );
|
||||
|
||||
SetResistance( ResistanceType.Physical, 40, 60 );
|
||||
SetResistance( ResistanceType.Fire, 40, 60 );
|
||||
SetResistance( ResistanceType.Cold, 40, 60 );
|
||||
SetResistance( ResistanceType.Poison, 40, 60 );
|
||||
SetResistance( ResistanceType.Energy, 40, 60 );
|
||||
|
||||
SetSkill( SkillName.MagicResist, 120 );
|
||||
SetSkill( SkillName.Tactics, 120 );
|
||||
SetSkill( SkillName.Wrestling, 120 );
|
||||
SetSkill( SkillName.Anatomy, 120 );
|
||||
SetSkill( SkillName.Magery, 120 );
|
||||
SetSkill( SkillName.EvalInt, 120 );
|
||||
SetSkill( SkillName.Mysticism, 120 );
|
||||
SetSkill( SkillName.Focus, 160 );
|
||||
|
||||
Fame = 22000;
|
||||
Karma = 22000;
|
||||
|
||||
Item boots = new ThighBoots();
|
||||
boots.Hue = 1;
|
||||
|
||||
Item scimitar = new Item(5046);
|
||||
scimitar.Hue = 1818;
|
||||
scimitar.Layer = Layer.OneHanded;
|
||||
|
||||
SetNonMovable(boots);
|
||||
SetNonMovable(scimitar);
|
||||
SetNonMovable(new LongPants(1818));
|
||||
SetNonMovable(new FancyShirt(194));
|
||||
SetNonMovable(new Doublet(1281));
|
||||
}
|
||||
|
||||
public override bool InitialInnocent { get { return true; } }
|
||||
public override BaseCreature SummonWisp { get { return new EnsorcledWisp(); } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot( LootPack.SuperBoss, 3);
|
||||
}
|
||||
|
||||
public AdrianTheGloriousLord(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AndrosTheDreadLord : DespiseBoss
|
||||
{
|
||||
[Constructable]
|
||||
public AndrosTheDreadLord() : base(AIType.AI_Mage, FightMode.Closest)
|
||||
{
|
||||
Name = "Andros";
|
||||
Title = "the Dread Lord";
|
||||
|
||||
Race = Race.Human;
|
||||
Body = 0x190;
|
||||
Female = false;
|
||||
|
||||
Hue = Race.RandomSkinHue();
|
||||
HairItemID = 0;
|
||||
|
||||
SetStr( 900, 1200 );
|
||||
SetDex( 500, 600 );
|
||||
SetInt( 500, 600 );
|
||||
|
||||
SetHits( 60000 );
|
||||
SetStam( 415 );
|
||||
SetMana( 22000 );
|
||||
|
||||
SetDamage( 18, 28 );
|
||||
|
||||
SetDamageType( ResistanceType.Physical, 100 );
|
||||
|
||||
SetResistance( ResistanceType.Physical, 40, 60 );
|
||||
SetResistance( ResistanceType.Fire, 40, 60 );
|
||||
SetResistance( ResistanceType.Cold, 40, 60 );
|
||||
SetResistance( ResistanceType.Poison, 40, 60 );
|
||||
SetResistance( ResistanceType.Energy, 40, 60 );
|
||||
|
||||
SetSkill( SkillName.MagicResist, 120 );
|
||||
SetSkill( SkillName.Tactics, 120 );
|
||||
SetSkill( SkillName.Wrestling, 120 );
|
||||
SetSkill( SkillName.Anatomy, 120 );
|
||||
SetSkill( SkillName.Magery, 120 );
|
||||
SetSkill( SkillName.EvalInt, 120 );
|
||||
SetSkill( SkillName.Mysticism, 120 );
|
||||
SetSkill( SkillName.Focus, 160 );
|
||||
|
||||
Fame = 22000;
|
||||
Karma = -22000;
|
||||
|
||||
Item boots = new ThighBoots();
|
||||
boots.Hue = 1;
|
||||
|
||||
Item staff = new Item(3721);
|
||||
staff.Layer = Layer.TwoHanded;
|
||||
|
||||
SetNonMovable(boots);
|
||||
SetNonMovable(new LongPants(1818));
|
||||
SetNonMovable(new FancyShirt(2726));
|
||||
SetNonMovable(new Doublet(1153));
|
||||
SetNonMovable(staff);
|
||||
}
|
||||
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
public override BaseCreature SummonWisp { get { return new CorruptedWisp(); } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot( LootPack.SuperBoss, 3);
|
||||
}
|
||||
|
||||
public AndrosTheDreadLord(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class EnsorcledWisp : BaseCreature
|
||||
{
|
||||
public EnsorcledWisp() : base(AIType.AI_Melee, FightMode.None, 10, 1, .2, .4)
|
||||
{
|
||||
Name = "Ensorcled Wisp";
|
||||
Body = 165;
|
||||
Hue = 0x901;
|
||||
BaseSoundID = 466;
|
||||
|
||||
SetStr( 600, 700 );
|
||||
SetDex( 500, 600 );
|
||||
SetInt( 500, 600 );
|
||||
|
||||
SetHits( 7000, 8000 );
|
||||
|
||||
SetDamage( 12, 19 );
|
||||
|
||||
SetDamageType( ResistanceType.Physical, 40 );
|
||||
SetDamageType( ResistanceType.Fire, 30 );
|
||||
SetDamageType( ResistanceType.Energy, 30 );
|
||||
|
||||
SetResistance( ResistanceType.Physical, 50 );
|
||||
SetResistance( ResistanceType.Fire, 60, 70 );
|
||||
SetResistance( ResistanceType.Cold, 60, 70 );
|
||||
SetResistance( ResistanceType.Poison, 50, 60 );
|
||||
SetResistance( ResistanceType.Energy, 60, 70 );
|
||||
|
||||
SetSkill( SkillName.MagicResist, 110, 125 );
|
||||
SetSkill( SkillName.Tactics, 110, 125 );
|
||||
SetSkill( SkillName.Wrestling, 110, 125 );
|
||||
SetSkill( SkillName.Anatomy, 110, 125 );
|
||||
|
||||
Fame = 8000;
|
||||
Karma = 8000;
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (ControlTarget != ControlMaster || ControlOrder != OrderType.Follow)
|
||||
{
|
||||
ControlTarget = ControlMaster;
|
||||
ControlOrder = OrderType.Follow;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot( LootPack.FilthyRich, 3);
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
Summoned = false;
|
||||
PackItem(new Gold(Utility.Random(800, 1000)));
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override bool InitialInnocent { get { return true; } }
|
||||
//public override bool ForceNotoriety { get { return true; } }
|
||||
|
||||
public EnsorcledWisp(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class CorruptedWisp : BaseCreature
|
||||
{
|
||||
public CorruptedWisp() : base(AIType.AI_Melee, FightMode.None, 10, 1, .2, .4)
|
||||
{
|
||||
Name = "Corrupted Wisp";
|
||||
Body = 165;
|
||||
Hue = 1955;
|
||||
BaseSoundID = 466;
|
||||
|
||||
SetStr( 600, 700 );
|
||||
SetDex( 500, 600 );
|
||||
SetInt( 500, 600 );
|
||||
|
||||
SetHits( 7000, 8000 );
|
||||
|
||||
SetDamage( 12, 19 );
|
||||
|
||||
SetDamageType( ResistanceType.Physical, 40 );
|
||||
SetDamageType( ResistanceType.Fire, 30 );
|
||||
SetDamageType( ResistanceType.Energy, 30 );
|
||||
|
||||
SetResistance( ResistanceType.Physical, 50 );
|
||||
SetResistance( ResistanceType.Fire, 60, 70 );
|
||||
SetResistance( ResistanceType.Cold, 60, 70 );
|
||||
SetResistance( ResistanceType.Poison, 50, 60 );
|
||||
SetResistance( ResistanceType.Energy, 60, 70 );
|
||||
|
||||
SetSkill( SkillName.MagicResist, 110, 125 );
|
||||
SetSkill( SkillName.Tactics, 110, 125 );
|
||||
SetSkill( SkillName.Wrestling, 110, 125 );
|
||||
SetSkill( SkillName.Anatomy, 110, 125 );
|
||||
|
||||
Fame = 8000;
|
||||
Karma = -8000;
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (ControlTarget != ControlMaster || ControlOrder != OrderType.Follow)
|
||||
{
|
||||
ControlTarget = ControlMaster;
|
||||
ControlOrder = OrderType.Follow;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.FilthyRich, 3);
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
Summoned = false;
|
||||
PackItem(new Gold(Utility.Random(800, 1000)));
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
//public override bool ForceNotoriety { get { return true; } }
|
||||
|
||||
public CorruptedWisp(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int v = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
299
Scripts/Mobiles/Bosses/DreadHorn.cs
Normal file
299
Scripts/Mobiles/Bosses/DreadHorn.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Misc;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Third;
|
||||
using Server.Spells.Sixth;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName( "a dread horns corpse" )]
|
||||
public class DreadHorn : BasePeerless
|
||||
{
|
||||
public virtual int StrikingRange{ get{ return 12; } }
|
||||
|
||||
[Constructable]
|
||||
public DreadHorn() : base( AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4 )
|
||||
{
|
||||
Name = "a Dread Horn";
|
||||
Body = 257;
|
||||
BaseSoundID = 0xA8;
|
||||
|
||||
SetStr( 878, 993 );
|
||||
SetDex( 581, 683 );
|
||||
SetInt( 1200, 1300 );
|
||||
|
||||
SetHits( 50000 );
|
||||
SetStam( 507, 669 );
|
||||
SetMana( 1200, 1300 );
|
||||
|
||||
SetDamage( 21, 28 );
|
||||
|
||||
SetDamageType( ResistanceType.Physical, 40 );
|
||||
SetDamageType( ResistanceType.Poison, 60 );
|
||||
|
||||
SetResistance( ResistanceType.Physical, 40, 55 );
|
||||
SetResistance( ResistanceType.Fire, 50, 65 );
|
||||
SetResistance( ResistanceType.Cold, 50, 65 );
|
||||
SetResistance( ResistanceType.Poison, 65, 75 );
|
||||
SetResistance( ResistanceType.Energy, 60, 75 );
|
||||
|
||||
SetSkill( SkillName.Wrestling, 90.0 );
|
||||
SetSkill( SkillName.Tactics, 90.0 );
|
||||
SetSkill( SkillName.MagicResist, 110.0 );
|
||||
SetSkill( SkillName.Poisoning, 120.0 );
|
||||
SetSkill( SkillName.Magery, 110.0 );
|
||||
SetSkill( SkillName.EvalInt, 110.0 );
|
||||
SetSkill( SkillName.Meditation, 110.0 );
|
||||
SetSkill(SkillName.Spellweaving, 120.0);
|
||||
|
||||
// TODO 1-3 spellweaving scroll
|
||||
|
||||
Fame = 32000;
|
||||
Karma = -32000;
|
||||
|
||||
PackResources( 8 );
|
||||
PackTalismans( 5 );
|
||||
|
||||
m_Change = DateTime.UtcNow;
|
||||
m_Stomp = DateTime.UtcNow;
|
||||
m_Teleport = DateTime.UtcNow;
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(1, 3); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 8);
|
||||
AddLoot(LootPack.LowScrolls, 4);
|
||||
AddLoot(LootPack.MedScrolls, 4);
|
||||
AddLoot(LootPack.HighScrolls, 4);
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if ( Combatant != null )
|
||||
{
|
||||
if ( m_Change < DateTime.UtcNow && Utility.RandomDouble() < 0.1 )
|
||||
ChangeOpponent();
|
||||
|
||||
if ( m_Stomp < DateTime.UtcNow && Utility.RandomDouble() < 0.1 )
|
||||
HoofStomp();
|
||||
|
||||
if (m_Teleport < DateTime.UtcNow && Utility.RandomDouble() < 0.1)
|
||||
Teleport();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDeath( Container c )
|
||||
{
|
||||
base.OnDeath( c );
|
||||
|
||||
c.DropItem( new DreadHornMane() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.6 )
|
||||
c.DropItem( new TaintedMushroom() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.6 )
|
||||
c.DropItem( new ParrotItem() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.5 )
|
||||
c.DropItem( new MangledHeadOfDreadhorn() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.5 )
|
||||
c.DropItem( new HornOfTheDreadhorn() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.05 )
|
||||
c.DropItem( new PristineDreadHorn() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.05 )
|
||||
c.DropItem( new DreadFlute() );
|
||||
|
||||
if ( Utility.RandomDouble() < 0.05 )
|
||||
c.DropItem( new DreadsRevenge() );
|
||||
}
|
||||
|
||||
public override int Hides{ get{ return 10; } }
|
||||
public override HideType HideType{ get{ return HideType.Regular; } }
|
||||
|
||||
public override int Meat{ get{ return 5; } }
|
||||
public override MeatType MeatType{ get{ return MeatType.Ribs; } }
|
||||
|
||||
public override bool GivesMLMinorArtifact { get { return true; } }
|
||||
public override bool Unprovokable{ get{ return true; } }
|
||||
public override Poison PoisonImmune{ get{ return Poison.Deadly; } }
|
||||
public override Poison HitPoison{ get{ return Poison.Lethal; } }
|
||||
public override int TreasureMapLevel{ get{ return 5; } }
|
||||
|
||||
public DreadHorn( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
|
||||
writer.Write( (int) 0 ); // version
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Change = DateTime.UtcNow;
|
||||
m_Stomp = DateTime.UtcNow;
|
||||
m_Teleport = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
private DateTime m_Change;
|
||||
private DateTime m_Stomp;
|
||||
private DateTime m_Teleport;
|
||||
|
||||
private void Teleport()
|
||||
{
|
||||
var toTele = SpellHelper.AcquireIndirectTargets(this, Location, Map, StrikingRange).OfType<PlayerMobile>().ToList();
|
||||
|
||||
if (toTele.Count > 0)
|
||||
{
|
||||
var from = toTele[Utility.Random(toTele.Count)];
|
||||
|
||||
if (from != null)
|
||||
{
|
||||
Combatant = from;
|
||||
|
||||
from.MoveToWorld(GetSpawnPosition(1), Map);
|
||||
from.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
|
||||
from.PlaySound(0x1FE);
|
||||
|
||||
from.ApplyPoison(this, HitPoison);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(toTele);
|
||||
m_Teleport = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(40, 60));
|
||||
}
|
||||
|
||||
public void ChangeOpponent()
|
||||
{
|
||||
Mobile agro, best = null;
|
||||
double distance, random = Utility.RandomDouble();
|
||||
|
||||
if (random < 0.75)
|
||||
{
|
||||
// find random target relatively close
|
||||
for (int i = 0; i < Aggressors.Count && best == null; i++)
|
||||
{
|
||||
agro = Validate(Aggressors[i].Attacker);
|
||||
|
||||
if (agro == null)
|
||||
continue;
|
||||
|
||||
distance = StrikingRange - GetDistanceToSqrt(agro);
|
||||
|
||||
if (distance > 0 && distance < StrikingRange - 2 && InLOS(agro.Location))
|
||||
{
|
||||
distance /= StrikingRange;
|
||||
|
||||
if (random < distance)
|
||||
best = agro;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int damage = 0;
|
||||
|
||||
// find a player who dealt most damage
|
||||
for (int i = 0; i < DamageEntries.Count; i++)
|
||||
{
|
||||
agro = Validate(DamageEntries[i].Damager);
|
||||
|
||||
if (agro == null)
|
||||
continue;
|
||||
|
||||
distance = GetDistanceToSqrt(agro);
|
||||
|
||||
if (distance < StrikingRange && DamageEntries[i].DamageGiven > damage && InLOS(agro.Location))
|
||||
{
|
||||
best = agro;
|
||||
damage = DamageEntries[i].DamageGiven;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (best != null)
|
||||
{
|
||||
// teleport
|
||||
best.Location = BasePeerless.GetSpawnPosition(Location, Map, 1);
|
||||
best.FixedParticles(0x376A, 9, 32, 0x13AF, EffectLayer.Waist);
|
||||
best.PlaySound(0x1FE);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), () =>
|
||||
{
|
||||
best.ApplyPoison(this, HitPoison);
|
||||
best.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist);
|
||||
best.PlaySound(0x474);
|
||||
});
|
||||
|
||||
m_Change = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(5, 10));
|
||||
}
|
||||
}
|
||||
|
||||
public void HoofStomp()
|
||||
{
|
||||
if (Map == null)
|
||||
return;
|
||||
|
||||
foreach (Mobile m in SpellHelper.AcquireIndirectTargets(this, Location, Map, StrikingRange).OfType<Mobile>())
|
||||
{
|
||||
if (m.GetStatMod("DreadHornStr") == null)
|
||||
{
|
||||
double percent = m.Skills.MagicResist.Value / 100;
|
||||
int malas = (int)(-20 + (percent * 5.2));
|
||||
|
||||
m.AddStatMod(new StatMod(StatType.Str, "DreadHornStr", m.Str < Math.Abs(malas) ? m.Str / 2 : malas, TimeSpan.FromSeconds(60)));
|
||||
m.AddStatMod(new StatMod(StatType.Dex, "DreadHornDex", m.Dex < Math.Abs(malas) ? m.Dex / 2 : malas, TimeSpan.FromSeconds(60)));
|
||||
m.AddStatMod(new StatMod(StatType.Int, "DreadHornInt", m.Int < Math.Abs(malas) ? m.Int / 2 : malas, TimeSpan.FromSeconds(60)));
|
||||
}
|
||||
|
||||
m.SendLocalizedMessage(1075081); // *Dreadhorns eyes light up, his mouth almost a grin, as he slams one hoof to the ground!*
|
||||
}
|
||||
|
||||
// earthquake
|
||||
PlaySound( 0x2F3 );
|
||||
m_Stomp = DateTime.UtcNow + TimeSpan.FromSeconds( Utility.RandomMinMax( 60, 80 ) );
|
||||
}
|
||||
|
||||
public static bool IsUnderInfluence(Mobile m)
|
||||
{
|
||||
return m.GetStatMod("DreadHornStr") != null;
|
||||
}
|
||||
|
||||
public Mobile Validate( Mobile m )
|
||||
{
|
||||
Mobile agro;
|
||||
|
||||
if ( m is BaseCreature )
|
||||
agro = ( (BaseCreature) m ).ControlMaster;
|
||||
else
|
||||
agro = m;
|
||||
|
||||
if ( !CanBeHarmful( agro, false ) || !agro.Player /*|| Combatant == agro*/ )
|
||||
return null;
|
||||
|
||||
return agro;
|
||||
}
|
||||
}
|
||||
}
|
||||
564
Scripts/Mobiles/Bosses/Harrower/Harrower.cs
Normal file
564
Scripts/Mobiles/Bosses/Harrower/Harrower.cs
Normal file
@@ -0,0 +1,564 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Services.Virtues;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Harrower : BaseCreature
|
||||
{
|
||||
private int m_StatCap = Config.Get("PlayerCaps.TotalStatCap", 225);
|
||||
private static readonly SpawnEntry[] m_Entries = new SpawnEntry[]
|
||||
{
|
||||
new SpawnEntry(new Point3D(5242, 945, -40), new Point3D(1176, 2638, 0)), // Destard
|
||||
new SpawnEntry(new Point3D(5225, 798, 0), new Point3D(1176, 2638, 0)), // Destard
|
||||
new SpawnEntry(new Point3D(5556, 886, 30), new Point3D(1298, 1080, 0)), // Despise
|
||||
new SpawnEntry(new Point3D(5187, 615, 0), new Point3D(4111, 432, 5)), // Deceit
|
||||
new SpawnEntry(new Point3D(5319, 583, 0), new Point3D(4111, 432, 5)), // Deceit
|
||||
new SpawnEntry(new Point3D(5713, 1334, -1), new Point3D(2923, 3407, 8)), // Fire
|
||||
new SpawnEntry(new Point3D(5860, 1460, -2), new Point3D(2923, 3407, 8)), // Fire
|
||||
new SpawnEntry(new Point3D(5328, 1620, 0), new Point3D(5451, 3143, -60)), // Terathan Keep
|
||||
new SpawnEntry(new Point3D(5690, 538, 0), new Point3D(2042, 224, 14)), // Wrong
|
||||
new SpawnEntry(new Point3D(5609, 195, 0), new Point3D(514, 1561, 0)), // Shame
|
||||
new SpawnEntry(new Point3D(5475, 187, 0), new Point3D(514, 1561, 0)), // Shame
|
||||
new SpawnEntry(new Point3D(6085, 179, 0), new Point3D(4721, 3822, 0)), // Hythloth
|
||||
new SpawnEntry(new Point3D(6084, 66, 0), new Point3D(4721, 3822, 0)), // Hythloth
|
||||
/*new SpawnEntry(new Point3D(5499, 2003, 0), new Point3D(2499, 919, 0)), // Covetous*/
|
||||
new SpawnEntry(new Point3D(5579, 1858, 0), new Point3D(2499, 919, 0))// Covetous
|
||||
};
|
||||
private static readonly ArrayList m_Instances = new ArrayList();
|
||||
private static readonly double[] m_Offsets = new double[]
|
||||
{
|
||||
Math.Cos(000.0 / 180.0 * Math.PI), Math.Sin(000.0 / 180.0 * Math.PI),
|
||||
Math.Cos(040.0 / 180.0 * Math.PI), Math.Sin(040.0 / 180.0 * Math.PI),
|
||||
Math.Cos(080.0 / 180.0 * Math.PI), Math.Sin(080.0 / 180.0 * Math.PI),
|
||||
Math.Cos(120.0 / 180.0 * Math.PI), Math.Sin(120.0 / 180.0 * Math.PI),
|
||||
Math.Cos(160.0 / 180.0 * Math.PI), Math.Sin(160.0 / 180.0 * Math.PI),
|
||||
Math.Cos(200.0 / 180.0 * Math.PI), Math.Sin(200.0 / 180.0 * Math.PI),
|
||||
Math.Cos(240.0 / 180.0 * Math.PI), Math.Sin(240.0 / 180.0 * Math.PI),
|
||||
Math.Cos(280.0 / 180.0 * Math.PI), Math.Sin(280.0 / 180.0 * Math.PI),
|
||||
Math.Cos(320.0 / 180.0 * Math.PI), Math.Sin(320.0 / 180.0 * Math.PI),
|
||||
};
|
||||
|
||||
private bool m_TrueForm;
|
||||
private bool m_IsSpawned;
|
||||
private Item m_GateItem;
|
||||
private List<HarrowerTentacles> m_Tentacles;
|
||||
|
||||
Dictionary<Mobile, int> m_DamageEntries;
|
||||
[Constructable]
|
||||
public Harrower()
|
||||
: base(AIType.AI_NecroMage, FightMode.Closest, 18, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "the harrower";
|
||||
BodyValue = 146;
|
||||
|
||||
SetStr(900, 1000);
|
||||
SetDex(125, 135);
|
||||
SetInt(1000, 1200);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
VirtualArmor = 60;
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Energy, 50);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 55, 65);
|
||||
SetResistance(ResistanceType.Fire, 60, 80);
|
||||
SetResistance(ResistanceType.Cold, 60, 80);
|
||||
SetResistance(ResistanceType.Poison, 60, 80);
|
||||
SetResistance(ResistanceType.Energy, 60, 80);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 90.1, 100.0);
|
||||
SetSkill(SkillName.Tactics, 90.2, 110.0);
|
||||
SetSkill(SkillName.MagicResist, 120.2, 160.0);
|
||||
SetSkill(SkillName.Magery, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 120.0);
|
||||
SetSkill(SkillName.Meditation, 120.0);
|
||||
|
||||
m_Tentacles = new List<HarrowerTentacles>();
|
||||
}
|
||||
|
||||
public Harrower(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public static ArrayList Instances
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Instances;
|
||||
}
|
||||
}
|
||||
public static bool CanSpawn
|
||||
{
|
||||
get
|
||||
{
|
||||
return (m_Instances.Count == 0);
|
||||
}
|
||||
}
|
||||
public Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(AcidProofRobe) };
|
||||
}
|
||||
}
|
||||
public Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(TheRobeOfBritanniaAri) };
|
||||
}
|
||||
}
|
||||
public Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(EvilIdolSkull), typeof(SkullPole) };
|
||||
}
|
||||
}
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override int HitsMax
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_TrueForm ? 65000 : 30000;
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override int ManaMax
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5000;
|
||||
}
|
||||
}
|
||||
public override bool DisallowAllMoves
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_TrueForm;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool TeleportsTo { get { return true; } }
|
||||
|
||||
public static Harrower Spawn(Point3D platLoc, Map platMap)
|
||||
{
|
||||
if (m_Instances.Count > 0)
|
||||
return null;
|
||||
|
||||
SpawnEntry entry = m_Entries[Utility.Random(m_Entries.Length)];
|
||||
|
||||
Harrower harrower = new Harrower();
|
||||
harrower.m_IsSpawned = true;
|
||||
|
||||
m_Instances.Add(harrower);
|
||||
|
||||
harrower.MoveToWorld(entry.m_Location, Map.Felucca);
|
||||
|
||||
harrower.m_GateItem = new HarrowerGate(harrower, platLoc, platMap, entry.m_Entrance, Map.Felucca);
|
||||
|
||||
return harrower;
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.SuperBoss, 2);
|
||||
AddLoot(LootPack.Meager);
|
||||
}
|
||||
|
||||
public void Morph()
|
||||
{
|
||||
if (m_TrueForm)
|
||||
return;
|
||||
|
||||
m_TrueForm = true;
|
||||
|
||||
Name = "the true harrower";
|
||||
BodyValue = 780;
|
||||
Hue = 0x497;
|
||||
|
||||
Hits = HitsMax;
|
||||
Stam = StamMax;
|
||||
Mana = ManaMax;
|
||||
|
||||
ProcessDelta();
|
||||
|
||||
Say(1049499); // Behold my true form!
|
||||
|
||||
Map map = Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
for (int i = 0; i < m_Offsets.Length; i += 2)
|
||||
{
|
||||
double rx = m_Offsets[i];
|
||||
double ry = m_Offsets[i + 1];
|
||||
|
||||
int dist = 0;
|
||||
bool ok = false;
|
||||
int x = 0, y = 0, z = 0;
|
||||
|
||||
while (!ok && dist < 10)
|
||||
{
|
||||
int rdist = 10 + dist;
|
||||
|
||||
x = X + (int)(rx * rdist);
|
||||
y = Y + (int)(ry * rdist);
|
||||
z = map.GetAverageZ(x, y);
|
||||
|
||||
if (!(ok = map.CanFit(x, y, Z, 16, false, false)))
|
||||
ok = map.CanFit(x, y, z, 16, false, false);
|
||||
|
||||
if (dist >= 0)
|
||||
dist = -(dist + 1);
|
||||
else
|
||||
dist = -(dist - 1);
|
||||
}
|
||||
|
||||
if (!ok)
|
||||
continue;
|
||||
|
||||
HarrowerTentacles spawn = new HarrowerTentacles(this);
|
||||
|
||||
spawn.Team = Team;
|
||||
|
||||
spawn.MoveToWorld(new Point3D(x, y, z), map);
|
||||
|
||||
m_Tentacles.Add(spawn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
m_Instances.Remove(this);
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)1); // version
|
||||
|
||||
writer.Write(m_IsSpawned);
|
||||
writer.Write(m_TrueForm);
|
||||
writer.Write(m_GateItem);
|
||||
writer.WriteMobileList<HarrowerTentacles>(m_Tentacles);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
m_IsSpawned = reader.ReadBool();
|
||||
goto case 0;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
m_TrueForm = reader.ReadBool();
|
||||
m_GateItem = reader.ReadItem();
|
||||
m_Tentacles = reader.ReadStrongMobileList<HarrowerTentacles>();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_IsSpawned)
|
||||
m_Instances.Add(this);
|
||||
}
|
||||
|
||||
public void GivePowerScrolls()
|
||||
{
|
||||
List<Mobile> toGive = new List<Mobile>();
|
||||
List<DamageStore> rights = GetLootingRights();
|
||||
|
||||
for (int i = rights.Count - 1; i >= 0; --i)
|
||||
{
|
||||
DamageStore ds = rights[i];
|
||||
|
||||
if (ds.m_HasRight)
|
||||
toGive.Add(ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (toGive.Count == 0)
|
||||
return;
|
||||
|
||||
// Randomize
|
||||
for (int i = 0; i < toGive.Count; ++i)
|
||||
{
|
||||
int rand = Utility.Random(toGive.Count);
|
||||
Mobile hold = toGive[i];
|
||||
toGive[i] = toGive[rand];
|
||||
toGive[rand] = hold;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ChampionSystem.StatScrollAmount; ++i)
|
||||
{
|
||||
Mobile m = toGive[i % toGive.Count];
|
||||
|
||||
m.SendLocalizedMessage(1049524); // You have received a scroll of power!
|
||||
m.AddToBackpack(new StatCapScroll(m_StatCap + RandomStatScrollLevel()));
|
||||
|
||||
if (m is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = (PlayerMobile)m;
|
||||
|
||||
for (int j = 0; j < pm.JusticeProtectors.Count; ++j)
|
||||
{
|
||||
Mobile prot = (Mobile)pm.JusticeProtectors[j];
|
||||
|
||||
if (prot.Map != m.Map || prot.Murderer || prot.Criminal || !JusticeVirtue.CheckMapRegion(m, prot))
|
||||
continue;
|
||||
|
||||
int chance = 0;
|
||||
|
||||
switch ( VirtueHelper.GetLevel(prot, VirtueName.Justice) )
|
||||
{
|
||||
case VirtueLevel.Seeker:
|
||||
chance = 60;
|
||||
break;
|
||||
case VirtueLevel.Follower:
|
||||
chance = 80;
|
||||
break;
|
||||
case VirtueLevel.Knight:
|
||||
chance = 100;
|
||||
break;
|
||||
}
|
||||
|
||||
if (chance > Utility.Random(100))
|
||||
{
|
||||
prot.SendLocalizedMessage(1049368); // You have been rewarded for your dedication to Justice!
|
||||
prot.AddToBackpack(new StatCapScroll(m_StatCap + RandomStatScrollLevel()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int RandomStatScrollLevel()
|
||||
{
|
||||
double random = Utility.RandomDouble();
|
||||
|
||||
if (0.1 >= random)
|
||||
return 25;
|
||||
else if (0.25 >= random)
|
||||
return 20;
|
||||
else if (0.45 >= random)
|
||||
return 15;
|
||||
else if (0.70 >= random)
|
||||
return 10;
|
||||
return 5;
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
if (m_TrueForm)
|
||||
{
|
||||
List<DamageStore> rights = GetLootingRights();
|
||||
|
||||
for (int i = rights.Count - 1; i >= 0; --i)
|
||||
{
|
||||
DamageStore ds = rights[i];
|
||||
|
||||
if (ds.m_HasRight && ds.m_Mobile is PlayerMobile)
|
||||
PlayerMobile.ChampionTitleInfo.AwardHarrowerTitle((PlayerMobile)ds.m_Mobile);
|
||||
}
|
||||
|
||||
if (!NoKillAwards)
|
||||
{
|
||||
GivePowerScrolls();
|
||||
|
||||
Map map = Map;
|
||||
|
||||
GoldShower.DoForHarrower(Location, Map);
|
||||
|
||||
m_DamageEntries = new Dictionary<Mobile, int>();
|
||||
|
||||
for (int i = 0; i < m_Tentacles.Count; ++i)
|
||||
{
|
||||
Mobile m = m_Tentacles[i];
|
||||
|
||||
if (!m.Deleted)
|
||||
m.Kill();
|
||||
|
||||
RegisterDamageTo(m);
|
||||
}
|
||||
|
||||
m_Tentacles.Clear();
|
||||
|
||||
RegisterDamageTo(this);
|
||||
AwardArtifact(GetArtifact());
|
||||
|
||||
if (m_GateItem != null)
|
||||
m_GateItem.Delete();
|
||||
}
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
else
|
||||
{
|
||||
Morph();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RegisterDamageTo(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
return;
|
||||
|
||||
foreach (DamageEntry de in m.DamageEntries)
|
||||
{
|
||||
Mobile damager = de.Damager;
|
||||
|
||||
Mobile master = damager.GetDamageMaster(m);
|
||||
|
||||
if (master != null)
|
||||
damager = master;
|
||||
|
||||
RegisterDamage(damager, de.DamageGiven);
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterDamage(Mobile from, int amount)
|
||||
{
|
||||
if (from == null || !from.Player)
|
||||
return;
|
||||
|
||||
if (m_DamageEntries.ContainsKey(from))
|
||||
m_DamageEntries[from] += amount;
|
||||
else
|
||||
m_DamageEntries.Add(from, amount);
|
||||
|
||||
from.SendMessage(String.Format("Total Damage: {0}", m_DamageEntries[from]));
|
||||
}
|
||||
|
||||
public void AwardArtifact(Item artifact)
|
||||
{
|
||||
if (artifact == null)
|
||||
return;
|
||||
|
||||
int totalDamage = 0;
|
||||
|
||||
Dictionary<Mobile, int> validEntries = new Dictionary<Mobile, int>();
|
||||
|
||||
foreach (KeyValuePair<Mobile, int> kvp in m_DamageEntries)
|
||||
{
|
||||
if (IsEligible(kvp.Key, artifact))
|
||||
{
|
||||
validEntries.Add(kvp.Key, kvp.Value);
|
||||
totalDamage += kvp.Value;
|
||||
}
|
||||
}
|
||||
|
||||
int randomDamage = Utility.RandomMinMax(1, totalDamage);
|
||||
|
||||
totalDamage = 0;
|
||||
|
||||
foreach (KeyValuePair<Mobile, int> kvp in validEntries)
|
||||
{
|
||||
totalDamage += kvp.Value;
|
||||
|
||||
if (totalDamage >= randomDamage)
|
||||
{
|
||||
GiveArtifact(kvp.Key, artifact);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
artifact.Delete();
|
||||
}
|
||||
|
||||
public void GiveArtifact(Mobile to, Item artifact)
|
||||
{
|
||||
if (to == null || artifact == null)
|
||||
return;
|
||||
|
||||
to.PlaySound(0x5B4);
|
||||
|
||||
Container pack = to.Backpack;
|
||||
|
||||
if (pack == null || !pack.TryDropItem(to, artifact, false))
|
||||
artifact.Delete();
|
||||
else
|
||||
to.SendLocalizedMessage(1062317); // For your valor in combating the fallen beast, a special artifact has been bestowed on you.
|
||||
}
|
||||
|
||||
public bool IsEligible(Mobile m, Item Artifact)
|
||||
{
|
||||
return m.Player && m.Alive && m.InRange(Location, 32) && m.Backpack != null && m.Backpack.CheckHold(m, Artifact, false);
|
||||
}
|
||||
|
||||
public Item GetArtifact()
|
||||
{
|
||||
double random = Utility.RandomDouble();
|
||||
if (0.05 >= random)
|
||||
return CreateArtifact(UniqueList);
|
||||
else if (0.15 >= random)
|
||||
return CreateArtifact(SharedList);
|
||||
else if (0.30 >= random)
|
||||
return CreateArtifact(DecorativeList);
|
||||
return null;
|
||||
}
|
||||
|
||||
public Item CreateArtifact(Type[] list)
|
||||
{
|
||||
if (list.Length == 0)
|
||||
return null;
|
||||
|
||||
int random = Utility.Random(list.Length);
|
||||
|
||||
Type type = list[random];
|
||||
|
||||
return Loot.Construct(type);
|
||||
}
|
||||
|
||||
private class SpawnEntry
|
||||
{
|
||||
public readonly Point3D m_Location;
|
||||
public readonly Point3D m_Entrance;
|
||||
public SpawnEntry(Point3D loc, Point3D ent)
|
||||
{
|
||||
m_Location = loc;
|
||||
m_Entrance = ent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
261
Scripts/Mobiles/Bosses/Harrower/HarrowerTentacles.cs
Normal file
261
Scripts/Mobiles/Bosses/Harrower/HarrowerTentacles.cs
Normal file
@@ -0,0 +1,261 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a tentacles corpse")]
|
||||
public class HarrowerTentacles : BaseCreature
|
||||
{
|
||||
private Mobile m_Harrower;
|
||||
private DrainTimer m_Timer;
|
||||
[Constructable]
|
||||
public HarrowerTentacles()
|
||||
: this(null)
|
||||
{
|
||||
}
|
||||
|
||||
public HarrowerTentacles(Mobile harrower)
|
||||
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
this.m_Harrower = harrower;
|
||||
|
||||
this.Name = "tentacles of the harrower";
|
||||
this.Body = 129;
|
||||
|
||||
this.SetStr(901, 1000);
|
||||
this.SetDex(126, 140);
|
||||
this.SetInt(1001, 1200);
|
||||
|
||||
this.SetHits(541, 600);
|
||||
|
||||
this.SetDamage(13, 20);
|
||||
|
||||
this.SetDamageType(ResistanceType.Physical, 20);
|
||||
this.SetDamageType(ResistanceType.Fire, 20);
|
||||
this.SetDamageType(ResistanceType.Cold, 20);
|
||||
this.SetDamageType(ResistanceType.Poison, 20);
|
||||
this.SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
this.SetResistance(ResistanceType.Physical, 55, 65);
|
||||
this.SetResistance(ResistanceType.Fire, 35, 45);
|
||||
this.SetResistance(ResistanceType.Cold, 35, 45);
|
||||
this.SetResistance(ResistanceType.Poison, 35, 45);
|
||||
this.SetResistance(ResistanceType.Energy, 35, 45);
|
||||
|
||||
this.SetSkill(SkillName.Meditation, 100.0);
|
||||
this.SetSkill(SkillName.MagicResist, 120.1, 140.0);
|
||||
this.SetSkill(SkillName.Swords, 90.1, 100.0);
|
||||
this.SetSkill(SkillName.Tactics, 90.1, 100.0);
|
||||
this.SetSkill(SkillName.Wrestling, 90.1, 100.0);
|
||||
|
||||
this.Fame = 15000;
|
||||
this.Karma = -15000;
|
||||
|
||||
this.VirtualArmor = 60;
|
||||
|
||||
this.m_Timer = new DrainTimer(this);
|
||||
this.m_Timer.Start();
|
||||
|
||||
this.PackReg(50);
|
||||
this.PackNecroReg(15, 75);
|
||||
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0: PackItem(new VampiricEmbraceScroll()); break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public HarrowerTentacles(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public Mobile Harrower
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Harrower;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Harrower = value;
|
||||
}
|
||||
}
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override bool DisallowAllMoves
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override void CheckReflect(Mobile caster, ref bool reflect)
|
||||
{
|
||||
reflect = true;
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x101;
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return 0x5E;
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x1C2;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return -1; // unknown
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x289;
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
this.AddLoot(LootPack.FilthyRich, 2);
|
||||
this.AddLoot(LootPack.MedScrolls, 3);
|
||||
this.AddLoot(LootPack.HighScrolls, 2);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
|
||||
writer.Write(this.m_Harrower);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
this.m_Harrower = reader.ReadMobile();
|
||||
|
||||
this.m_Timer = new DrainTimer(this);
|
||||
this.m_Timer.Start();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
if (this.m_Timer != null)
|
||||
this.m_Timer.Stop();
|
||||
|
||||
this.m_Timer = null;
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
private class DrainTimer : Timer
|
||||
{
|
||||
private static readonly ArrayList m_ToDrain = new ArrayList();
|
||||
private readonly HarrowerTentacles m_Owner;
|
||||
public DrainTimer(HarrowerTentacles owner)
|
||||
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
|
||||
{
|
||||
this.m_Owner = owner;
|
||||
this.Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (this.m_Owner.Deleted)
|
||||
{
|
||||
this.Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
IPooledEnumerable eable = m_Owner.GetMobilesInRange(9);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == this.m_Owner || m == this.m_Owner.Harrower || !this.m_Owner.CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if (m is BaseCreature)
|
||||
{
|
||||
BaseCreature bc = m as BaseCreature;
|
||||
|
||||
if (bc.Controlled || bc.Summoned)
|
||||
m_ToDrain.Add(m);
|
||||
}
|
||||
else if (m.Player)
|
||||
{
|
||||
m_ToDrain.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
foreach (Mobile m in m_ToDrain)
|
||||
{
|
||||
this.m_Owner.DoHarmful(m);
|
||||
|
||||
m.FixedParticles(0x374A, 10, 15, 5013, 0x455, 0, EffectLayer.Waist);
|
||||
m.PlaySound(0x1F1);
|
||||
|
||||
int drain = Utility.RandomMinMax(14, 30);
|
||||
|
||||
//Monster Stealables
|
||||
if (m is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = m as PlayerMobile;
|
||||
drain = (int)LifeShieldLotion.HandleLifeDrain(pm, drain);
|
||||
}
|
||||
//end
|
||||
|
||||
this.m_Owner.Hits += drain;
|
||||
|
||||
if (this.m_Owner.Harrower != null)
|
||||
this.m_Owner.Harrower.Hits += drain;
|
||||
|
||||
m.Damage(drain, this.m_Owner);
|
||||
}
|
||||
|
||||
m_ToDrain.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
288
Scripts/Mobiles/Bosses/LadyMelisande.cs
Normal file
288
Scripts/Mobiles/Bosses/LadyMelisande.cs
Normal file
@@ -0,0 +1,288 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a lady melisande corpse")]
|
||||
public class LadyMelisande : BasePeerless
|
||||
{
|
||||
[Constructable]
|
||||
public LadyMelisande()
|
||||
: base(AIType.AI_NecroMage, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a lady melisande";
|
||||
Body = 0x102;
|
||||
BaseSoundID = 451;
|
||||
|
||||
SetStr(400, 1000);
|
||||
SetDex(300, 400);
|
||||
SetInt(1500, 1700);
|
||||
|
||||
SetHits(100000);
|
||||
|
||||
SetDamage(11, 18);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Energy, 50);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 40, 60);
|
||||
SetResistance(ResistanceType.Fire, 40, 50);
|
||||
SetResistance(ResistanceType.Cold, 55, 65);
|
||||
SetResistance(ResistanceType.Poison, 70, 75);
|
||||
SetResistance(ResistanceType.Energy, 70, 80);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 100, 105);
|
||||
SetSkill(SkillName.Tactics, 100, 105);
|
||||
SetSkill(SkillName.MagicResist, 120);
|
||||
SetSkill(SkillName.Magery, 120);
|
||||
SetSkill(SkillName.EvalInt, 120);
|
||||
SetSkill(SkillName.Meditation, 120);
|
||||
SetSkill(SkillName.Necromancy, 120);
|
||||
SetSkill(SkillName.SpiritSpeak, 120);
|
||||
|
||||
PackResources(8);
|
||||
PackTalismans(5);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), new TimerCallback(SpawnSatyrs));
|
||||
|
||||
Fame = 25000;
|
||||
Karma = -25000;
|
||||
|
||||
VirtualArmor = 50;
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(0, 1); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
|
||||
}
|
||||
|
||||
SetAreaEffect(AreaEffect.AuraOfNausea);
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.SuperBoss, 8);
|
||||
AddLoot(LootPack.Parrot, 1);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new DiseasedBark());
|
||||
c.DropItem(new EternallyCorruptTree());
|
||||
|
||||
int drop = Utility.Random(4, 8);
|
||||
|
||||
for (int i = 0; i < drop; i++)
|
||||
c.DropItem(new MelisandesFermentedWine());
|
||||
|
||||
if (Utility.RandomDouble() < 0.6)
|
||||
c.DropItem(new ParrotItem());
|
||||
|
||||
if (Utility.RandomDouble() < 0.2225)
|
||||
{
|
||||
switch ( Utility.Random(3) )
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new MelisandesHairDye());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new MelisandesCorrodedHatchet());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new AlbinoSquirrelImprisonedInCrystal());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
Mobile combatant = Combatant as Mobile;
|
||||
|
||||
if (combatant != null)
|
||||
{
|
||||
if (CanTakeLife(combatant))
|
||||
TakeLife(combatant);
|
||||
|
||||
if (CanSmackTalk())
|
||||
SmackTalk();
|
||||
}
|
||||
}
|
||||
|
||||
public override void SetLocation(Point3D newLocation, bool isTeleport)
|
||||
{
|
||||
if (newLocation.Z > -10)
|
||||
base.SetLocation(newLocation, isTeleport);
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
if (willKill)
|
||||
{
|
||||
SpawnHelper(new Reaper(), 6490, 948, 19);
|
||||
SpawnHelper(new InsaneDryad(), 6497, 946, 17);
|
||||
SpawnHelper(new StoneHarpy(), 6511, 946, 28);
|
||||
|
||||
Say(1075118); // Noooooo! You shall never defeat me. Even if I should fall, my tree will sustain me and I will rise again.
|
||||
}
|
||||
|
||||
base.OnDamage(amount, from, willKill);
|
||||
}
|
||||
|
||||
public override bool GivesMLMinorArtifact
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
public LadyMelisande(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
#region Smack Talk
|
||||
private DateTime m_NextSmackTalk;
|
||||
|
||||
public bool CanSmackTalk()
|
||||
{
|
||||
if (m_NextSmackTalk > DateTime.UtcNow)
|
||||
return false;
|
||||
|
||||
if (Combatant == null)
|
||||
return false;
|
||||
|
||||
return Hits > 0.5 * HitsMax;
|
||||
}
|
||||
|
||||
public void SmackTalk()
|
||||
{
|
||||
Say(Utility.RandomMinMax(1075102, 1075115)); // Muahahahaha! I'll feast on your flesh.
|
||||
|
||||
m_NextSmackTalk = DateTime.UtcNow + TimeSpan.FromSeconds(2 + Utility.RandomDouble() * 3);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Take Life
|
||||
private DateTime m_NextTakeLife;
|
||||
|
||||
public bool CanTakeLife(Mobile from)
|
||||
{
|
||||
if (m_NextTakeLife > DateTime.UtcNow)
|
||||
return false;
|
||||
|
||||
if (!CanBeHarmful(from))
|
||||
return false;
|
||||
|
||||
if (Hits > 0.1 * HitsMax || Hits < 0.025 * HitsMax)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void TakeLife(Mobile from)
|
||||
{
|
||||
Hits += from.Hits / (from.Player ? 2 : 6);
|
||||
|
||||
FixedParticles(0x376A, 9, 32, 5005, EffectLayer.Waist);
|
||||
PlaySound(0x1F2);
|
||||
|
||||
Say(1075117); // Muahahaha! Your life essence is MINE!
|
||||
Say(1075120); // An unholy aura surrounds Lady Melisande as her wounds begin to close.
|
||||
|
||||
m_NextTakeLife = DateTime.UtcNow + TimeSpan.FromSeconds(15 + Utility.RandomDouble() * 45);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
public override bool CanSpawnHelpers
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override int MaxHelpersWaves
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SpawnHelpers()
|
||||
{
|
||||
int count = 4;
|
||||
|
||||
if (Altar != null)
|
||||
{
|
||||
count = Math.Min(Altar.Fighters.Count, 4);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Mobile fighter = Altar.Fighters[i];
|
||||
|
||||
if (CanBeHarmful(fighter))
|
||||
{
|
||||
EnslavedSatyr satyr = new EnslavedSatyr();
|
||||
satyr.FightMode = FightMode.Closest;
|
||||
SpawnHelper(satyr, GetSpawnPosition(fighter.Location, fighter.Map, 2));
|
||||
|
||||
satyr.Combatant = fighter;
|
||||
|
||||
fighter.SendLocalizedMessage(1075116); // A twisted satyr scrambles onto the branch beside you and attacks!
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
SpawnHelper(new EnslavedSatyr(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnSatyrs()
|
||||
{
|
||||
SpawnHelper(new EnslavedSatyr(), 6485, 945, 19);
|
||||
SpawnHelper(new EnslavedSatyr(), 6486, 948, 22);
|
||||
SpawnHelper(new EnslavedSatyr(), 6487, 945, 17);
|
||||
SpawnHelper(new EnslavedSatyr(), 6488, 947, 23);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
332
Scripts/Mobiles/Bosses/LordOaks.cs
Normal file
332
Scripts/Mobiles/Bosses/LordOaks.cs
Normal file
@@ -0,0 +1,332 @@
|
||||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class LordOaks : BaseChampion
|
||||
{
|
||||
private Mobile m_Queen;
|
||||
private bool m_SpawnedQueen;
|
||||
[Constructable]
|
||||
public LordOaks()
|
||||
: base(AIType.AI_Paladin, FightMode.Evil)
|
||||
{
|
||||
Body = 175;
|
||||
Name = "Lord Oaks";
|
||||
|
||||
SetStr(403, 850);
|
||||
SetDex(101, 150);
|
||||
SetInt(503, 800);
|
||||
|
||||
SetHits(12000);
|
||||
SetStam(202, 400);
|
||||
|
||||
SetDamage(21, 33);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 75);
|
||||
SetDamageType(ResistanceType.Fire, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 85, 90);
|
||||
SetResistance(ResistanceType.Fire, 60, 70);
|
||||
SetResistance(ResistanceType.Cold, 60, 70);
|
||||
SetResistance(ResistanceType.Poison, 80, 90);
|
||||
SetResistance(ResistanceType.Energy, 80, 90);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 75.1, 100.0);
|
||||
SetSkill(SkillName.EvalInt, 120.1, 130.0);
|
||||
SetSkill(SkillName.Magery, 120.0);
|
||||
SetSkill(SkillName.Meditation, 120.1, 130.0);
|
||||
SetSkill(SkillName.MagicResist, 100.5, 150.0);
|
||||
SetSkill(SkillName.Tactics, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 100.0);
|
||||
SetSkill(SkillName.Chivalry, 100.0);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = 22500;
|
||||
|
||||
VirtualArmor = 100;
|
||||
}
|
||||
|
||||
public LordOaks(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Enlightenment;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(OrcChieftainHelm) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(RoyalGuardSurvivalKnife),
|
||||
typeof(DjinnisRing),
|
||||
typeof(LieutenantOfTheBritannianRoyalGuard),
|
||||
typeof(SamaritanRobe),
|
||||
typeof(DetectiveBoots),
|
||||
typeof(TheMostKnowledgePerson)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(WaterTile),
|
||||
typeof(WindSpirit),
|
||||
typeof(Pier),
|
||||
};
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { };
|
||||
}
|
||||
}
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool CanFly
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool BardImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool Uncalmable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
|
||||
public override TribeType Tribe { get { return TribeType.Fey; } }
|
||||
|
||||
public override OppositionGroup OppositionGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
return OppositionGroup.FeyAndUndead;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Deadly;
|
||||
}
|
||||
}
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 5);
|
||||
}
|
||||
|
||||
public void SpawnPixies(Mobile target)
|
||||
{
|
||||
Map map = Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
Say(1042154); // You shall never defeat me as long as I have my queen!
|
||||
|
||||
int newPixies = Utility.RandomMinMax(3, 6);
|
||||
|
||||
for (int i = 0; i < newPixies; ++i)
|
||||
{
|
||||
Pixie pixie = new Pixie();
|
||||
|
||||
pixie.Team = Team;
|
||||
pixie.FightMode = FightMode.Closest;
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = X + Utility.Random(3) - 1;
|
||||
int y = Y + Utility.Random(3) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
|
||||
loc = new Point3D(x, y, Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
pixie.MoveToWorld(loc, map);
|
||||
pixie.Combatant = target;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return 0x2F8;
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x2F8;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return Utility.Random(0x2F5, 2);
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x2F9;
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x2F7;
|
||||
}
|
||||
|
||||
public void CheckQueen()
|
||||
{
|
||||
if (Map == null)
|
||||
return;
|
||||
|
||||
if (!m_SpawnedQueen)
|
||||
{
|
||||
Say(1042153); // Come forth my queen!
|
||||
|
||||
m_Queen = new Silvani();
|
||||
|
||||
((BaseCreature)m_Queen).Team = Team;
|
||||
|
||||
m_Queen.MoveToWorld(Location, Map);
|
||||
|
||||
m_SpawnedQueen = true;
|
||||
}
|
||||
else if (m_Queen != null && m_Queen.Deleted)
|
||||
{
|
||||
m_Queen = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
|
||||
{
|
||||
CheckQueen();
|
||||
|
||||
if (m_Queen != null)
|
||||
{
|
||||
scalar *= 0.1;
|
||||
|
||||
if (0.1 >= Utility.RandomDouble())
|
||||
SpawnPixies(caster);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
if (0.25 > Utility.RandomDouble())
|
||||
{
|
||||
int toSap = Utility.RandomMinMax(20, 30);
|
||||
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0:
|
||||
defender.Damage(toSap, this);
|
||||
Hits += toSap;
|
||||
break;
|
||||
case 1:
|
||||
defender.Stam -= toSap;
|
||||
Stam += toSap;
|
||||
break;
|
||||
case 2:
|
||||
defender.Mana -= toSap;
|
||||
Mana += toSap;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*defender.Damage(Utility.Random(20, 10), this);
|
||||
defender.Stam -= Utility.Random(20, 10);
|
||||
defender.Mana -= Utility.Random(20, 10);*/
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
CheckQueen();
|
||||
|
||||
if (m_Queen != null && 0.1 >= Utility.RandomDouble())
|
||||
SpawnPixies(attacker);
|
||||
|
||||
/*attacker.Damage(Utility.Random(20, 10), this);
|
||||
attacker.Stam -= Utility.Random(20, 10);
|
||||
attacker.Mana -= Utility.Random(20, 10);*/
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
|
||||
writer.Write(m_Queen);
|
||||
writer.Write(m_SpawnedQueen);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Queen = reader.ReadMobile();
|
||||
m_SpawnedQueen = reader.ReadBool();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
809
Scripts/Mobiles/Bosses/Medusa.cs
Normal file
809
Scripts/Mobiles/Bosses/Medusa.cs
Normal file
@@ -0,0 +1,809 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a medusa corpse")]
|
||||
public class Medusa : BaseSABoss, ICarvable
|
||||
{
|
||||
private List<Mobile> m_TurnedToStone = new List<Mobile>();
|
||||
public List<Mobile> AffectedMobiles { get { return m_TurnedToStone; } }
|
||||
|
||||
public List<Mobile> m_Helpers = new List<Mobile>();
|
||||
|
||||
private int m_Scales;
|
||||
private DateTime m_GazeDelay;
|
||||
private DateTime m_StoneDelay;
|
||||
private DateTime m_NextCarve;
|
||||
|
||||
[Constructable]
|
||||
public Medusa()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.1, 0.2)
|
||||
{
|
||||
Name = "Medusa";
|
||||
Body = 728;
|
||||
|
||||
SetStr(1235, 1391);
|
||||
SetDex(128, 139);
|
||||
SetInt(537, 664);
|
||||
|
||||
SetHits(60000);
|
||||
|
||||
SetDamage(21, 28);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 60);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 55, 65);
|
||||
SetResistance(ResistanceType.Fire, 55, 65);
|
||||
SetResistance(ResistanceType.Cold, 55, 65);
|
||||
SetResistance(ResistanceType.Poison, 80, 90);
|
||||
SetResistance(ResistanceType.Energy, 60, 75);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 110.6, 116.1);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 114.4);
|
||||
SetSkill(SkillName.Magery, 100.0);
|
||||
SetSkill(SkillName.Meditation, 118.2, 127.8);
|
||||
SetSkill(SkillName.MagicResist, 120.0);
|
||||
SetSkill(SkillName.Tactics, 111.9, 134.5);
|
||||
SetSkill(SkillName.Wrestling, 119.7, 128.9);
|
||||
|
||||
Fame = 22000;
|
||||
Karma = -22000;
|
||||
|
||||
VirtualArmor = 60;
|
||||
|
||||
PackItem(new Arrow(Utility.RandomMinMax(100, 200)));
|
||||
|
||||
IronwoodCompositeBow Bow = new IronwoodCompositeBow();
|
||||
Bow.Movable = false;
|
||||
AddItem(Bow);
|
||||
|
||||
m_Scales = Utility.RandomMinMax(1, 2) + 7;
|
||||
|
||||
SetWeaponAbility(WeaponAbility.MortalStrike);
|
||||
SetSpecialAbility(SpecialAbility.VenomousBite);
|
||||
}
|
||||
|
||||
public Medusa(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] UniqueSAList
|
||||
{
|
||||
get { return new Type[] { typeof(Slither), typeof(IronwoodCompositeBow), typeof(Venom), typeof(PetrifiedSnake), typeof(StoneDragonsTooth), typeof(MedusaFloorTileAddonDeed) }; }
|
||||
}
|
||||
|
||||
public override Type[] SharedSAList
|
||||
{
|
||||
get { return new Type[] { typeof(SummonersKilt) }; }
|
||||
}
|
||||
|
||||
public override bool IgnoreYoungProtection { get { return true; } }
|
||||
public override bool AutoDispel { get { return true; } }
|
||||
public override double AutoDispelChance { get { return 1.0; } }
|
||||
public override bool BardImmune { get { return true; } }
|
||||
public override Poison PoisonImmune { get { return Poison.Lethal; } }
|
||||
public override Poison HitPoison { get { return (0.8 >= Utility.RandomDouble() ? Poison.Deadly : Poison.Lethal); } }
|
||||
|
||||
public override int GetIdleSound() { return 1557; }
|
||||
public override int GetAngerSound() { return 1554; }
|
||||
public override int GetHurtSound() { return 1556; }
|
||||
public override int GetDeathSound() { return 1555; }
|
||||
|
||||
public override void OnCarve(Mobile from, Corpse corpse, Item with)
|
||||
{
|
||||
int amount = Utility.Random(5) + 1;
|
||||
|
||||
corpse.DropItem(new MedusaDarkScales(amount));
|
||||
|
||||
if(0.20 > Utility.RandomDouble())
|
||||
corpse.DropItem(new MedusaBlood());
|
||||
|
||||
base.OnCarve(from, corpse, with);
|
||||
|
||||
corpse.Carved = true;
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile m)
|
||||
{
|
||||
base.OnGotMeleeAttack(m);
|
||||
|
||||
if (0.05 > Utility.RandomDouble())
|
||||
ReleaseStoneMonster();
|
||||
}
|
||||
|
||||
public override void OnDamagedBySpell(Mobile m)
|
||||
{
|
||||
base.OnDamagedBySpell(m);
|
||||
|
||||
if (0.05 > Utility.RandomDouble())
|
||||
ReleaseStoneMonster();
|
||||
}
|
||||
|
||||
public override void OnHarmfulSpell(Mobile from)
|
||||
{
|
||||
base.OnHarmfulSpell(from);
|
||||
|
||||
if (0.05 > Utility.RandomDouble())
|
||||
ReleaseStoneMonster();
|
||||
}
|
||||
|
||||
public void RemoveAffectedMobiles(Mobile toRemove)
|
||||
{
|
||||
if (m_TurnedToStone.Contains(toRemove))
|
||||
m_TurnedToStone.Remove(toRemove);
|
||||
}
|
||||
|
||||
public Mobile FindRandomMedusaTarget()
|
||||
{
|
||||
List<Mobile> list = new List<Mobile>();
|
||||
|
||||
IPooledEnumerable eable = this.GetMobilesInRange(12);
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if ( m == null || m == this || m_TurnedToStone.Contains(m) || !CanBeHarmful(m) || !InLOS(m) || m.AccessLevel > AccessLevel.Player)
|
||||
continue;
|
||||
|
||||
//Pets
|
||||
if (m is BaseCreature && (((BaseCreature)m).GetMaster() is PlayerMobile))
|
||||
list.Add(m);
|
||||
//players
|
||||
else if (m is PlayerMobile)
|
||||
list.Add(m);
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
if (list.Count == 0)
|
||||
return null;
|
||||
if (list.Count == 1)
|
||||
return list[0];
|
||||
|
||||
return list[Utility.Random(list.Count)];
|
||||
}
|
||||
|
||||
public static bool CheckBlockGaze(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
return false;
|
||||
|
||||
Item helm = m.FindItemOnLayer(Layer.Helm);
|
||||
Item neck = m.FindItemOnLayer(Layer.Neck);
|
||||
Item ear = m.FindItemOnLayer(Layer.Earrings);
|
||||
Item shi = m.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
bool deflect = false;
|
||||
int perc = 0;
|
||||
|
||||
if (helm != null)
|
||||
{
|
||||
if (helm is BaseArmor && ((BaseArmor)helm).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseArmor)helm).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseArmor)helm).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
else if (helm is BaseClothing && ((BaseClothing)helm).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseClothing)helm).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseClothing)helm).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deflect && shi != null && shi is BaseShield && ((BaseArmor)shi).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseArmor)shi).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseArmor)shi).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!deflect && neck != null)
|
||||
{
|
||||
if (neck is BaseArmor && ((BaseArmor)neck).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseArmor)neck).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseArmor)neck).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
else if (neck is BaseJewel && ((BaseJewel)neck).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseJewel)neck).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseJewel)neck).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
else if (neck is BaseClothing && ((BaseClothing)neck).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseClothing)neck).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseClothing)neck).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!deflect && ear != null)
|
||||
{
|
||||
if (ear is BaseJewel && ((BaseJewel)ear).GorgonLenseCharges > 0)
|
||||
{
|
||||
perc = GetScaleEffectiveness(((BaseJewel)ear).GorgonLenseType);
|
||||
|
||||
if (perc > Utility.Random(100))
|
||||
{
|
||||
((BaseJewel)ear).GorgonLenseCharges--;
|
||||
deflect = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deflect;
|
||||
}
|
||||
|
||||
private static int GetScaleEffectiveness(LenseType type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case LenseType.None: return 0;
|
||||
case LenseType.Enhanced: return 100;
|
||||
case LenseType.Regular: return 50;
|
||||
case LenseType.Limited: return 15;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public bool Carve(Mobile from, Item item)
|
||||
{
|
||||
if (m_Scales > 0)
|
||||
{
|
||||
if (DateTime.UtcNow < m_NextCarve)
|
||||
{
|
||||
from.SendLocalizedMessage(1112677); // The creature is still recovering from the previous harvest. Try again in a few seconds.
|
||||
}
|
||||
else
|
||||
{
|
||||
int amount = Math.Min(m_Scales, Utility.RandomMinMax(2, 3));
|
||||
|
||||
m_Scales -= amount;
|
||||
|
||||
Item scales = new MedusaLightScales(amount);
|
||||
|
||||
if (from.PlaceInBackpack(scales))
|
||||
{
|
||||
// You harvest magical resources from the creature and place it in your bag.
|
||||
from.SendLocalizedMessage(1112676);
|
||||
}
|
||||
else
|
||||
{
|
||||
scales.MoveToWorld(from.Location, from.Map);
|
||||
}
|
||||
|
||||
new Blood(0x122D).MoveToWorld(Location, Map);
|
||||
|
||||
m_NextCarve = DateTime.UtcNow + TimeSpan.FromMinutes(1.0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
from.SendLocalizedMessage(1112674); // There's nothing left to harvest from this creature.
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (Combatant == null)
|
||||
return;
|
||||
|
||||
if (m_StoneDelay < DateTime.UtcNow)
|
||||
SpawnStone();
|
||||
|
||||
if (m_GazeDelay < DateTime.UtcNow)
|
||||
DoGaze();
|
||||
}
|
||||
|
||||
public void DoGaze()
|
||||
{
|
||||
Mobile target = FindRandomMedusaTarget();
|
||||
Map map = Map;
|
||||
|
||||
if (map == null || target == null)
|
||||
return;
|
||||
|
||||
if ((target is BaseCreature && ((BaseCreature)target).SummonMaster != this) || CanBeHarmful(target))
|
||||
{
|
||||
if (CheckBlockGaze(target))
|
||||
{
|
||||
if (GorgonLense.TotalCharges(target) == 0)
|
||||
target.SendLocalizedMessage(1112600); // Your lenses crumble. You are no longer protected from Medusa's gaze!
|
||||
else
|
||||
target.SendLocalizedMessage(1112599); //Your Gorgon Lens deflect Medusa's petrifying gaze!
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseCreature clone = new MedusaClone(target);
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = X + Utility.Random(10) - 1;
|
||||
int y = Y + Utility.Random(10) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
|
||||
loc = new Point3D(x, y, Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
Effects.SendLocationEffect(loc, target.Map, 0x37B9, 10, 5);
|
||||
clone.Frozen = clone.Blessed = true;
|
||||
clone.SolidHueOverride = 761;
|
||||
|
||||
target.Frozen = target.Blessed = true;
|
||||
target.SolidHueOverride = 761;
|
||||
|
||||
//clone.MoveToWorld(loc, target.Map);
|
||||
BaseCreature.Summon(clone, false, this, loc, 0, TimeSpan.FromMinutes(90));
|
||||
|
||||
if (target is BaseCreature && !((BaseCreature)target).Summoned && ((BaseCreature)target).GetMaster() != null)
|
||||
((BaseCreature)target).GetMaster().SendLocalizedMessage(1113281, null, 43); // Your pet has been petrified!
|
||||
else
|
||||
target.SendLocalizedMessage(1112768); // You have been turned to stone!!!
|
||||
|
||||
new GazeTimer(target, clone, this, Utility.RandomMinMax(5, 10)).Start();
|
||||
m_GazeDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(45, 75));
|
||||
|
||||
m_Helpers.Add(clone);
|
||||
m_TurnedToStone.Add(target);
|
||||
|
||||
BuffInfo.AddBuff(target, new BuffInfo(BuffIcon.MedusaStone, 1153790, 1153825));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_GazeDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(25, 65));
|
||||
}
|
||||
|
||||
public void SpawnStone()
|
||||
{
|
||||
DefragHelpers();
|
||||
|
||||
Map map = Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
int stones = 0;
|
||||
|
||||
foreach (Mobile m in m_Helpers)
|
||||
{
|
||||
if (!(m is MedusaClone))
|
||||
++stones;
|
||||
}
|
||||
|
||||
if (stones >= 5)
|
||||
return;
|
||||
else
|
||||
{
|
||||
BaseCreature stone = GetRandomStoneMonster();
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = X + Utility.Random(10) - 1;
|
||||
int y = Y + Utility.Random(10) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
|
||||
loc = new Point3D(x, y, Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
BaseCreature.Summon(stone, false, this, loc, 0, TimeSpan.FromMinutes(90));
|
||||
//stone.MoveToWorld(loc, map);
|
||||
stone.Frozen = stone.Blessed = true;
|
||||
stone.SolidHueOverride = 761;
|
||||
stone.Combatant = null;
|
||||
|
||||
m_Helpers.Add(stone);
|
||||
}
|
||||
|
||||
m_StoneDelay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 150));
|
||||
}
|
||||
|
||||
private void DefragHelpers()
|
||||
{
|
||||
List<Mobile> toDelete = new List<Mobile>();
|
||||
|
||||
foreach (Mobile m in m_Helpers)
|
||||
{
|
||||
if(m == null)
|
||||
continue;
|
||||
|
||||
if (!m.Alive || m.Deleted)
|
||||
toDelete.Add(m);
|
||||
}
|
||||
|
||||
foreach (Mobile m in toDelete)
|
||||
{
|
||||
if (m_Helpers.Contains(m))
|
||||
m_Helpers.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseCreature GetRandomStoneMonster()
|
||||
{
|
||||
switch (Utility.Random(6))
|
||||
{
|
||||
default:
|
||||
case 0: return new OphidianWarrior();
|
||||
case 1: return new OphidianArchmage();
|
||||
case 2: return new WailingBanshee();
|
||||
case 3: return new OgreLord();
|
||||
case 4: return new Dragon();
|
||||
case 5: return new UndeadGargoyle();
|
||||
}
|
||||
}
|
||||
|
||||
public void ReleaseStoneMonster()
|
||||
{
|
||||
List<Mobile> stones = new List<Mobile>();
|
||||
|
||||
foreach (Mobile mob in m_Helpers)
|
||||
{
|
||||
if (!(mob is MedusaClone) && mob.Alive)
|
||||
stones.Add(mob);
|
||||
}
|
||||
|
||||
if(stones.Count == 0)
|
||||
return;
|
||||
|
||||
Mobile m = stones[Utility.Random(stones.Count)];
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
m.Frozen = m.Blessed = false;
|
||||
m.SolidHueOverride = -1;
|
||||
Mobile closest = null;
|
||||
int dist = 12;
|
||||
|
||||
m_Helpers.Remove(m);
|
||||
|
||||
IPooledEnumerable eable = m.GetMobilesInRange(12);
|
||||
foreach (Mobile targ in eable)
|
||||
{
|
||||
if (targ != null && targ.Player)
|
||||
{
|
||||
targ.SendLocalizedMessage(1112767, null, 43); // Medusa releases one of the petrified creatures!!
|
||||
targ.Combatant = targ;
|
||||
}
|
||||
|
||||
if (targ is PlayerMobile || (targ is BaseCreature && ((BaseCreature)targ).GetMaster() is PlayerMobile))
|
||||
{
|
||||
int d = (int)m.GetDistanceToSqrt(targ.Location);
|
||||
|
||||
if (d < dist)
|
||||
{
|
||||
dist = d;
|
||||
closest = targ;
|
||||
}
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
if (closest != null)
|
||||
m.Combatant = closest;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.SuperBoss, 8);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
if (Utility.RandomDouble() < 0.025)
|
||||
c.DropItem(new MedusaStatue());
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
foreach (Mobile m in m_Helpers)
|
||||
{
|
||||
if (m != null && !m.Deleted)
|
||||
m.Delete();
|
||||
}
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
|
||||
writer.Write((int)m_Scales);
|
||||
|
||||
writer.Write(m_Helpers.Count);
|
||||
|
||||
foreach (Mobile helper in m_Helpers)
|
||||
writer.Write(helper);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Scales = reader.ReadInt();
|
||||
|
||||
int count = reader.ReadInt();
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
Mobile m = reader.ReadMobile();
|
||||
|
||||
if (m != null && m.Alive)
|
||||
m_Helpers.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
public class GazeTimer : Timer
|
||||
{
|
||||
private Mobile target;
|
||||
private Mobile clone;
|
||||
private Medusa m_Medusa;
|
||||
private int m_Count;
|
||||
|
||||
public GazeTimer(Mobile m, Mobile mc, Medusa medusa, int duration)
|
||||
: base(TimeSpan.FromSeconds(duration), TimeSpan.FromSeconds(duration))
|
||||
{
|
||||
target = m;
|
||||
clone = mc;
|
||||
m_Medusa = medusa;
|
||||
m_Count = 0;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
++m_Count;
|
||||
|
||||
if (m_Count == 1 && target != null)
|
||||
{
|
||||
target.Frozen = false;
|
||||
target.SolidHueOverride = -1;
|
||||
target.Blessed = false;
|
||||
m_Medusa.RemoveAffectedMobiles(target);
|
||||
|
||||
if (target is BaseCreature && !((BaseCreature)target).Summoned && ((BaseCreature)target).GetMaster() != null)
|
||||
((BaseCreature)target).GetMaster().SendLocalizedMessage(1113285, null, 43); // Beware! A statue of your pet has been created!
|
||||
|
||||
BuffInfo.RemoveBuff(target, BuffIcon.MedusaStone);
|
||||
}
|
||||
else if (m_Count == 2 && clone != null)
|
||||
{
|
||||
clone.SolidHueOverride = -1;
|
||||
clone.Frozen = clone.Blessed = false;
|
||||
int dist = 12;
|
||||
Mobile closest = null;
|
||||
|
||||
IPooledEnumerable eable = clone.GetMobilesInRange(12);
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
int d = (int)clone.GetDistanceToSqrt(m.Location);
|
||||
|
||||
if (m != null && m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile))
|
||||
{
|
||||
if (m.NetState != null)
|
||||
{
|
||||
m.Send(new RemoveMobile(clone));
|
||||
m.NetState.Send(MobileIncoming.Create(m.NetState, m, clone));
|
||||
m.SendLocalizedMessage(1112767); // Medusa releases one of the petrified creatures!!
|
||||
}
|
||||
|
||||
if (d < dist)
|
||||
{
|
||||
dist = d;
|
||||
closest = m;
|
||||
}
|
||||
}
|
||||
}
|
||||
eable.Free();
|
||||
|
||||
if (closest != null)
|
||||
clone.Combatant = closest;
|
||||
}
|
||||
else
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MedusaClone : BaseCreature, IFreezable
|
||||
{
|
||||
public MedusaClone(Mobile m)
|
||||
: base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
SolidHueOverride = 33;
|
||||
Clone(m);
|
||||
}
|
||||
|
||||
public MedusaClone(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool DeleteCorpseOnDeath
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool ReacquireOnMovement
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool AlwaysMurderer
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Frozen;
|
||||
}
|
||||
}
|
||||
public void Clone(Mobile m)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
Body = m.Body;
|
||||
|
||||
Str = m.Str;
|
||||
Dex = m.Dex;
|
||||
Int = m.Int;
|
||||
|
||||
Hits = m.HitsMax;
|
||||
|
||||
Hue = m.Hue;
|
||||
Female = m.Female;
|
||||
|
||||
Name = m.Name;
|
||||
NameHue = m.NameHue;
|
||||
|
||||
Title = m.Title;
|
||||
Kills = m.Kills;
|
||||
|
||||
HairItemID = m.HairItemID;
|
||||
HairHue = m.HairHue;
|
||||
|
||||
FacialHairItemID = m.FacialHairItemID;
|
||||
FacialHairHue = m.FacialHairHue;
|
||||
|
||||
BaseSoundID = m.BaseSoundID;
|
||||
|
||||
for (int i = 0; i < m.Skills.Length; ++i)
|
||||
{
|
||||
Skills[i].Base = m.Skills[i].Base;
|
||||
Skills[i].Cap = m.Skills[i].Cap;
|
||||
}
|
||||
|
||||
for (int i = 0; i < m.Items.Count; i++)
|
||||
{
|
||||
if (m.Items[i].Layer != Layer.Backpack && m.Items[i].Layer != Layer.Mount && m.Items[i].Layer != Layer.Bank)
|
||||
AddItem(CloneItem(m.Items[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public Item CloneItem(Item item)
|
||||
{
|
||||
Item cloned = new Item(item.ItemID);
|
||||
cloned.Layer = item.Layer;
|
||||
cloned.Name = item.Name;
|
||||
cloned.Hue = item.Hue;
|
||||
cloned.Weight = item.Weight;
|
||||
cloned.Movable = false;
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (Frozen)
|
||||
DisplayPaperdollTo(from);
|
||||
else
|
||||
base.OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public void OnRequestedAnimation(Mobile from)
|
||||
{
|
||||
if (Frozen)
|
||||
{
|
||||
from.Send(new UpdateStatueAnimation(this, 1, 31, 5));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
Effects.SendLocationParticles(EffectItem.Create(Location, Map, EffectItem.DefaultDuration), 0x3728, 10, 15, 5042);
|
||||
|
||||
base.OnDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class AddCloneCommands
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("addclone", AccessLevel.Seer, new CommandEventHandler(AddClone_OnCommand));
|
||||
}
|
||||
|
||||
[Description("")]
|
||||
public static void AddClone_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
BaseCreature clone = new MedusaClone(e.Mobile);
|
||||
clone.Frozen = clone.Blessed = true;
|
||||
clone.MoveToWorld(e.Mobile.Location, e.Mobile.Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Scripts/Mobiles/Bosses/Mephitis.cs
Normal file
123
Scripts/Mobiles/Bosses/Mephitis.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Mephitis : BaseChampion
|
||||
{
|
||||
[Constructable]
|
||||
public Mephitis()
|
||||
: base(AIType.AI_Melee)
|
||||
{
|
||||
Body = 173;
|
||||
Name = "Mephitis";
|
||||
|
||||
BaseSoundID = 0x183;
|
||||
|
||||
SetStr(505, 1000);
|
||||
SetDex(102, 300);
|
||||
SetInt(402, 600);
|
||||
|
||||
SetHits(12000);
|
||||
SetStam(105, 600);
|
||||
|
||||
SetDamage(21, 33);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Poison, 50);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 75, 80);
|
||||
SetResistance(ResistanceType.Fire, 60, 70);
|
||||
SetResistance(ResistanceType.Cold, 60, 70);
|
||||
SetResistance(ResistanceType.Poison, 100);
|
||||
SetResistance(ResistanceType.Energy, 60, 70);
|
||||
|
||||
SetSkill(SkillName.MagicResist, 70.7, 140.0);
|
||||
SetSkill(SkillName.Tactics, 97.6, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 97.6, 100.0);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
VirtualArmor = 80;
|
||||
|
||||
SetSpecialAbility(SpecialAbility.Webbing);
|
||||
|
||||
ForceActiveSpeed = 0.3;
|
||||
ForcePassiveSpeed = 0.6;
|
||||
}
|
||||
|
||||
public Mephitis(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Venom;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(Calm) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(OblivionsNeedle), typeof(ANecromancerShroud) };
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(Web), typeof(MonsterStatuette) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { MonsterStatuetteType.Spider };
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override Poison HitPoison
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 4);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
347
Scripts/Mobiles/Bosses/MonstrousInterredGrizzle.cs
Normal file
347
Scripts/Mobiles/Bosses/MonstrousInterredGrizzle.cs
Normal file
@@ -0,0 +1,347 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a monstrous interred grizzle corpse")]
|
||||
public class MonstrousInterredGrizzle : BasePeerless
|
||||
{
|
||||
private static readonly int[] m_Tiles = new int[]
|
||||
{
|
||||
-2, 0,
|
||||
2, 0,
|
||||
2, -2,
|
||||
2, 2,
|
||||
-2, -2,
|
||||
-2, 2,
|
||||
0, 2,
|
||||
1, 0,
|
||||
0, -2
|
||||
};
|
||||
|
||||
private readonly DateTime m_NextDrop = DateTime.UtcNow;
|
||||
|
||||
[Constructable]
|
||||
public MonstrousInterredGrizzle()
|
||||
: base(AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a monstrous interred grizzle";
|
||||
Body = 0x103;
|
||||
BaseSoundID = 589;
|
||||
|
||||
SetStr(1198, 1207);
|
||||
SetDex(127, 135);
|
||||
SetInt(595, 646);
|
||||
|
||||
SetHits(50000);
|
||||
|
||||
SetDamage(27, 31);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 60);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 48, 52);
|
||||
SetResistance(ResistanceType.Fire, 77, 82);
|
||||
SetResistance(ResistanceType.Cold, 56, 61);
|
||||
SetResistance(ResistanceType.Poison, 32, 40);
|
||||
SetResistance(ResistanceType.Energy, 69, 71);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 112.6, 116.9);
|
||||
SetSkill(SkillName.Tactics, 118.5, 119.2);
|
||||
SetSkill(SkillName.MagicResist, 120);
|
||||
SetSkill(SkillName.Anatomy, 111.0, 111.7);
|
||||
SetSkill(SkillName.Magery, 100.0);
|
||||
SetSkill(SkillName.EvalInt, 100);
|
||||
SetSkill(SkillName.Meditation, 100);
|
||||
SetSkill(SkillName.Spellweaving, 100.0);
|
||||
|
||||
Fame = 24000;
|
||||
Karma = -24000;
|
||||
|
||||
VirtualArmor = 80;
|
||||
PackResources(8);
|
||||
PackTalismans(5);
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
|
||||
}
|
||||
|
||||
SetSpecialAbility(SpecialAbility.HowlOfCacophony);
|
||||
}
|
||||
|
||||
public MonstrousInterredGrizzle(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool GivesMLMinorArtifact
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 8);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new GrizzledBones());
|
||||
|
||||
switch (Utility.Random(4))
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new TombstoneOfTheDamned());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new GlobOfMonstreousInterredGrizzle());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new MonsterousInterredGrizzleMaggots());
|
||||
break;
|
||||
case 3:
|
||||
c.DropItem(new GrizzledSkullCollection());
|
||||
break;
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < 0.6)
|
||||
c.DropItem(new ParrotItem());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new GrizzledMareStatuette());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
{
|
||||
switch (Utility.Random(5))
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new GrizzleGauntlets());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new GrizzleGreaves());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new GrizzleHelm());
|
||||
break;
|
||||
case 3:
|
||||
c.DropItem(new GrizzleTunic());
|
||||
break;
|
||||
case 4:
|
||||
c.DropItem(new GrizzleVambraces());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x57F;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return 0x580;
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x581;
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return 0x582;
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x583;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
if (Utility.RandomDouble() < 0.06)
|
||||
SpillAcid(null, Utility.RandomMinMax(1, 3));
|
||||
|
||||
base.OnDamage(amount, from, willKill);
|
||||
}
|
||||
|
||||
public override Item NewHarmfulItem()
|
||||
{
|
||||
return new InfernalOoze(this, Utility.RandomBool());
|
||||
}
|
||||
}
|
||||
|
||||
public class InfernalOoze : Item
|
||||
{
|
||||
private bool m_Corrosive;
|
||||
private int m_Damage;
|
||||
private Mobile m_Owner;
|
||||
private Timer m_Timer;
|
||||
|
||||
private DateTime m_StartTime;
|
||||
|
||||
public InfernalOoze(Mobile owner)
|
||||
: this(owner, false)
|
||||
{
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public InfernalOoze(Mobile owner, bool corrosive, int damage = 40)
|
||||
: base(0x122A)
|
||||
{
|
||||
Movable = false;
|
||||
m_Owner = owner;
|
||||
Hue = 0x95;
|
||||
|
||||
m_Damage = damage;
|
||||
|
||||
m_Corrosive = corrosive;
|
||||
m_StartTime = DateTime.UtcNow;
|
||||
|
||||
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), OnTick);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool Corrosive
|
||||
{
|
||||
get { return m_Corrosive; }
|
||||
set { m_Corrosive = value; }
|
||||
}
|
||||
|
||||
private void OnTick()
|
||||
{
|
||||
if (ItemID == 0x122A && m_StartTime + TimeSpan.FromSeconds(30) < DateTime.UtcNow)
|
||||
{
|
||||
ItemID++;
|
||||
}
|
||||
else if (m_StartTime + TimeSpan.FromSeconds(35) < DateTime.UtcNow)
|
||||
{
|
||||
Delete();
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Owner == null)
|
||||
return;
|
||||
|
||||
if (!Deleted && Map != Map.Internal && Map != null)
|
||||
{
|
||||
foreach (var m in SpellHelper.AcquireIndirectTargets(m_Owner, Location, Map, 0).OfType<Mobile>())
|
||||
{
|
||||
OnMoveOver(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
if (Map == null)
|
||||
return base.OnMoveOver(m);
|
||||
|
||||
if ((m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile) || m.Player)
|
||||
{
|
||||
Damage(m);
|
||||
}
|
||||
|
||||
return base.OnMoveOver(m);
|
||||
}
|
||||
|
||||
public virtual void Damage(Mobile m)
|
||||
{
|
||||
if (m_Corrosive)
|
||||
{
|
||||
for (int i = 0; i < m.Items.Count; i++)
|
||||
{
|
||||
IDurability item = m.Items[i] as IDurability;
|
||||
|
||||
if (item != null && Utility.RandomDouble() < 0.25)
|
||||
{
|
||||
if (item.HitPoints > 10)
|
||||
item.HitPoints -= 10;
|
||||
else
|
||||
item.HitPoints -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int dmg = m_Damage;
|
||||
|
||||
if (m is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = m as PlayerMobile;
|
||||
dmg = (int)BalmOfProtection.HandleDamage(pm, dmg);
|
||||
AOS.Damage(m, m_Owner, dmg, 0, 0, 0, 100, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
AOS.Damage(m, m_Owner, dmg, 0, 0, 0, 100, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
base.Delete();
|
||||
|
||||
if (m_Timer != null)
|
||||
{
|
||||
m_Timer.Stop();
|
||||
m_Timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public InfernalOoze(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
42
Scripts/Mobiles/Bosses/Navery/EyeOfNavrey.cs
Normal file
42
Scripts/Mobiles/Bosses/Navery/EyeOfNavrey.cs
Normal file
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class EyeOfNavrey : Item
|
||||
{
|
||||
[Constructable]
|
||||
public EyeOfNavrey()
|
||||
: base(0x318D)
|
||||
{
|
||||
this.Weight = 1;
|
||||
this.Hue = 68;
|
||||
this.LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public EyeOfNavrey(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1095154;
|
||||
}
|
||||
}// Eye of Navrey Night-Eyes
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
185
Scripts/Mobiles/Bosses/Navery/Navrey.cs
Normal file
185
Scripts/Mobiles/Bosses/Navery/Navrey.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.Quests;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a navrey corpse")]
|
||||
public class Navrey : BaseCreature
|
||||
{
|
||||
private NavreysController m_Spawner;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public bool UsedPillars { get; set; }
|
||||
|
||||
private static readonly Type[] m_Artifact = new Type[]
|
||||
{
|
||||
typeof(NightEyes),
|
||||
typeof(Tangle1)
|
||||
};
|
||||
|
||||
[Constructable]
|
||||
public Navrey(NavreysController spawner)
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
m_Spawner = spawner;
|
||||
|
||||
Name = "Navrey Night-Eyes";
|
||||
Body = 735;
|
||||
BaseSoundID = 389;
|
||||
|
||||
SetStr(1000, 1500);
|
||||
SetDex(200, 250);
|
||||
SetInt(150, 200);
|
||||
|
||||
SetHits(30000, 35000);
|
||||
|
||||
SetDamage(25, 40);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Fire, 25);
|
||||
SetDamageType(ResistanceType.Energy, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 55, 65);
|
||||
SetResistance(ResistanceType.Fire, 45, 55);
|
||||
SetResistance(ResistanceType.Cold, 60, 70);
|
||||
SetResistance(ResistanceType.Poison, 100);
|
||||
SetResistance(ResistanceType.Energy, 65, 80);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 50.0, 80.0);
|
||||
SetSkill(SkillName.EvalInt, 90.0, 100.0);
|
||||
SetSkill(SkillName.Magery, 90.0, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 130.0);
|
||||
SetSkill(SkillName.Meditation, 80.0, 100.0);
|
||||
SetSkill(SkillName.Poisoning, 100.0);
|
||||
SetSkill(SkillName.Tactics, 90.0, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 91.6, 98.2);
|
||||
|
||||
Fame = 24000;
|
||||
Karma = -24000;
|
||||
|
||||
VirtualArmor = 90;
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(1, 3); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.MysticismScrollTypes.Length, SpellbookType.Mystic));
|
||||
}
|
||||
|
||||
SetSpecialAbility(SpecialAbility.Webbing);
|
||||
}
|
||||
|
||||
public Navrey(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override double TeleportChance { get { return 0; } }
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
public override Poison PoisonImmune { get { return Poison.Parasitic; } }
|
||||
public override Poison HitPoison { get { return Poison.Lethal; } }
|
||||
public override int Meat { get { return 1; } }
|
||||
|
||||
public static void DistributeRandomArtifact(BaseCreature bc, Type[] typelist)
|
||||
{
|
||||
int random = Utility.Random(typelist.Length);
|
||||
Item item = Loot.Construct(typelist[random]);
|
||||
DistributeArtifact(DemonKnight.FindRandomPlayer(bc), item);
|
||||
}
|
||||
|
||||
public static void DistributeArtifact(Mobile to, Item artifact)
|
||||
{
|
||||
if (artifact == null)
|
||||
return;
|
||||
|
||||
if (to != null)
|
||||
{
|
||||
Container pack = to.Backpack;
|
||||
|
||||
if (pack == null || !pack.TryDropItem(to, artifact, false))
|
||||
to.BankBox.DropItem(artifact);
|
||||
|
||||
to.SendLocalizedMessage(502088); // A special gift has been placed in your backpack.
|
||||
}
|
||||
else
|
||||
{
|
||||
artifact.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 3);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
if (m_Spawner != null)
|
||||
m_Spawner.OnNavreyKilled();
|
||||
|
||||
if (Utility.RandomBool())
|
||||
c.AddItem(new UntranslatedAncientTome());
|
||||
|
||||
if (0.1 >= Utility.RandomDouble())
|
||||
c.AddItem(ScrollOfTranscendence.CreateRandom(30, 30));
|
||||
|
||||
if (0.1 >= Utility.RandomDouble())
|
||||
c.AddItem(new TatteredAncientScroll());
|
||||
|
||||
if (Utility.RandomDouble() < 0.10)
|
||||
c.DropItem(new LuckyCoin());
|
||||
|
||||
if (Utility.RandomDouble() < 0.025)
|
||||
DistributeRandomArtifact(this, m_Artifact);
|
||||
|
||||
// distribute quest items for the 'Green with Envy' quest given by Vernix
|
||||
List<DamageStore> rights = GetLootingRights();
|
||||
for (int i = rights.Count - 1; i >= 0; --i)
|
||||
{
|
||||
DamageStore ds = rights[i];
|
||||
if (!ds.m_HasRight)
|
||||
rights.RemoveAt(i);
|
||||
}
|
||||
|
||||
// for each with looting rights... give an eye of navrey if they have the quest
|
||||
foreach (DamageStore d in rights)
|
||||
{
|
||||
PlayerMobile pm = d.m_Mobile as PlayerMobile;
|
||||
if (null != pm)
|
||||
{
|
||||
foreach (BaseQuest quest in pm.Quests)
|
||||
{
|
||||
if (quest is GreenWithEnvyQuest)
|
||||
{
|
||||
Container pack = pm.Backpack;
|
||||
Item item = new EyeOfNavrey();
|
||||
if (pack == null || !pack.TryDropItem(pm, item, false))
|
||||
pm.BankBox.DropItem(item);
|
||||
pm.SendLocalizedMessage(1095155); // As Navrey Night-Eyes dies, you find and claim one of her eyes as proof of her demise.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)1);
|
||||
|
||||
writer.Write((Item)m_Spawner);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
|
||||
if (version >= 1)
|
||||
m_Spawner = reader.ReadItem() as NavreysController;
|
||||
}
|
||||
}
|
||||
}
|
||||
387
Scripts/Mobiles/Bosses/Neira.cs
Normal file
387
Scripts/Mobiles/Bosses/Neira.cs
Normal file
@@ -0,0 +1,387 @@
|
||||
using System;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Neira : BaseChampion
|
||||
{
|
||||
private const double SpeedBoostScalar = 1.2;
|
||||
private bool m_SpeedBoost;
|
||||
[Constructable]
|
||||
public Neira()
|
||||
: base(AIType.AI_Mage)
|
||||
{
|
||||
Name = "Neira";
|
||||
Title = "the necromancer";
|
||||
Body = 401;
|
||||
Hue = 0x83EC;
|
||||
|
||||
SetStr(305, 425);
|
||||
SetDex(72, 150);
|
||||
SetInt(505, 750);
|
||||
|
||||
SetHits(4800);
|
||||
SetStam(102, 300);
|
||||
|
||||
SetDamage(25, 35);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 25, 30);
|
||||
SetResistance(ResistanceType.Fire, 35, 45);
|
||||
SetResistance(ResistanceType.Cold, 50, 60);
|
||||
SetResistance(ResistanceType.Poison, 30, 40);
|
||||
SetResistance(ResistanceType.Energy, 20, 30);
|
||||
|
||||
SetSkill(SkillName.EvalInt, 120.0);
|
||||
SetSkill(SkillName.Magery, 120.0);
|
||||
SetSkill(SkillName.Meditation, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 150.0);
|
||||
SetSkill(SkillName.Tactics, 97.6, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 97.6, 100.0);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
VirtualArmor = 30;
|
||||
Female = true;
|
||||
|
||||
Item shroud = new HoodedShroudOfShadows();
|
||||
|
||||
shroud.Movable = false;
|
||||
|
||||
AddItem(shroud);
|
||||
|
||||
Scimitar weapon = new Scimitar();
|
||||
|
||||
weapon.Skill = SkillName.Wrestling;
|
||||
weapon.Hue = 38;
|
||||
weapon.Movable = false;
|
||||
|
||||
AddItem(weapon);
|
||||
|
||||
//new SkeletalMount().Rider = this;
|
||||
AddItem(new VirtualMountItem(this));
|
||||
}
|
||||
|
||||
public Neira(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Death;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(ShroudOfDeceit) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(ANecromancerShroud),
|
||||
typeof(CaptainJohnsHat),
|
||||
typeof(DetectiveBoots)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(WallBlood), typeof(TatteredAncientMummyWrapping) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { };
|
||||
}
|
||||
}
|
||||
public override bool AlwaysMurderer
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool BardImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return !Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
public override bool Uncalmable
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.SE;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Deadly;
|
||||
}
|
||||
}
|
||||
public override bool ShowFameTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool ClickTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ForceStayHome { get { return true; } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 3);
|
||||
AddLoot(LootPack.Meager);
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
IMount mount = Mount;
|
||||
|
||||
if (mount != null)
|
||||
mount.Rider = null;
|
||||
|
||||
if (mount is Mobile)
|
||||
((Mobile)mount).Delete();
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
NecromancerSpellbook book = new NecromancerSpellbook();
|
||||
book.Content = (1ul << book.BookCount) - 1;
|
||||
c.DropItem(book);
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
CheckSpeedBoost();
|
||||
base.OnDamage(amount, from, willKill);
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
if (0.1 >= Utility.RandomDouble()) // 10% chance to drop or throw an unholy bone
|
||||
AddUnholyBone(defender, 0.25);
|
||||
|
||||
CheckSpeedBoost();
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
if (0.1 >= Utility.RandomDouble()) // 10% chance to drop or throw an unholy bone
|
||||
AddUnholyBone(attacker, 0.25);
|
||||
}
|
||||
|
||||
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
|
||||
{
|
||||
base.AlterDamageScalarFrom(caster, ref scalar);
|
||||
|
||||
if (0.1 >= Utility.RandomDouble()) // 10% chance to throw an unholy bone
|
||||
AddUnholyBone(caster, 1.0);
|
||||
}
|
||||
|
||||
public void AddUnholyBone(Mobile target, double chanceToThrow)
|
||||
{
|
||||
if (Map == null)
|
||||
return;
|
||||
|
||||
if (chanceToThrow >= Utility.RandomDouble())
|
||||
{
|
||||
Direction = GetDirectionTo(target);
|
||||
MovingEffect(target, 0xF7E, 10, 1, true, false, 0x496, 0);
|
||||
new DelayTimer(this, target).Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
new UnholyBone().MoveToWorld(Location, Map);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)1); // version
|
||||
writer.Write(m_SpeedBoost);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch( version )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
m_SpeedBoost = reader.ReadBool();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckSpeedBoost()
|
||||
{
|
||||
if (Hits < (HitsMax / 4))
|
||||
{
|
||||
if (!m_SpeedBoost)
|
||||
{
|
||||
ActiveSpeed /= SpeedBoostScalar;
|
||||
PassiveSpeed /= SpeedBoostScalar;
|
||||
m_SpeedBoost = true;
|
||||
}
|
||||
}
|
||||
else if (m_SpeedBoost)
|
||||
{
|
||||
ActiveSpeed *= SpeedBoostScalar;
|
||||
PassiveSpeed *= SpeedBoostScalar;
|
||||
m_SpeedBoost = false;
|
||||
}
|
||||
}
|
||||
|
||||
private class VirtualMount : IMount
|
||||
{
|
||||
private readonly VirtualMountItem m_Item;
|
||||
public VirtualMount(VirtualMountItem item)
|
||||
{
|
||||
m_Item = item;
|
||||
}
|
||||
|
||||
public Mobile Rider
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Item.Rider;
|
||||
}
|
||||
set
|
||||
{
|
||||
}
|
||||
}
|
||||
public virtual void OnRiderDamaged(Mobile from, ref int amount, bool willKill)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private class VirtualMountItem : Item, IMountItem
|
||||
{
|
||||
private readonly VirtualMount m_Mount;
|
||||
private Mobile m_Rider;
|
||||
public VirtualMountItem(Mobile mob)
|
||||
: base(0x3EBB)
|
||||
{
|
||||
Layer = Layer.Mount;
|
||||
|
||||
Movable = false;
|
||||
|
||||
m_Rider = mob;
|
||||
m_Mount = new VirtualMount(this);
|
||||
}
|
||||
|
||||
public VirtualMountItem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
m_Mount = new VirtualMount(this);
|
||||
}
|
||||
|
||||
public Mobile Rider
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Rider;
|
||||
}
|
||||
}
|
||||
public IMount Mount
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Mount;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
|
||||
writer.Write((Mobile)m_Rider);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Rider = reader.ReadMobile();
|
||||
|
||||
if (m_Rider == null)
|
||||
Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private class DelayTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
private readonly Mobile m_Target;
|
||||
public DelayTimer(Mobile m, Mobile target)
|
||||
: base(TimeSpan.FromSeconds(1.0))
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_Target = target;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Mobile.CanBeHarmful(m_Target))
|
||||
{
|
||||
m_Mobile.DoHarmful(m_Target);
|
||||
AOS.Damage(m_Target, m_Mobile, Utility.RandomMinMax(10, 20), 100, 0, 0, 0, 0);
|
||||
new UnholyBone().MoveToWorld(m_Target.Location, m_Target.Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
520
Scripts/Mobiles/Bosses/PrimevalLich.cs
Normal file
520
Scripts/Mobiles/Bosses/PrimevalLich.cs
Normal file
@@ -0,0 +1,520 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
using System.Collections.Generic;
|
||||
using Server.Network;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a Primeval Lich corpse")]
|
||||
public class PrimevalLich : BaseChampion
|
||||
{
|
||||
private DateTime m_NextDiscordTime;
|
||||
private DateTime m_NextAbilityTime;
|
||||
private Timer m_Timer;
|
||||
|
||||
[Constructable]
|
||||
public PrimevalLich()
|
||||
: base(AIType.AI_NecroMage)
|
||||
{
|
||||
Name = "Primeval Lich";
|
||||
Body = 830;
|
||||
|
||||
SetStr(500);
|
||||
SetDex(100);
|
||||
SetInt(1000);
|
||||
|
||||
SetHits(30000);
|
||||
SetMana(5000);
|
||||
|
||||
SetDamage(17, 21);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 20);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Cold, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30);
|
||||
SetResistance(ResistanceType.Fire, 30);
|
||||
SetResistance(ResistanceType.Cold, 30);
|
||||
SetResistance(ResistanceType.Poison, 30);
|
||||
SetResistance(ResistanceType.Energy, 20);
|
||||
|
||||
SetSkill(SkillName.EvalInt, 90, 120.0);
|
||||
SetSkill(SkillName.Magery, 90, 120.0);
|
||||
SetSkill(SkillName.Meditation, 100, 120.0);
|
||||
SetSkill(SkillName.Necromancy, 120.0);
|
||||
SetSkill(SkillName.SpiritSpeak, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 120, 140.0);
|
||||
SetSkill(SkillName.Tactics, 90, 120);
|
||||
SetSkill(SkillName.Wrestling, 100, 120);
|
||||
|
||||
Fame = 28000;
|
||||
Karma = -28000;
|
||||
|
||||
VirtualArmor = 80;
|
||||
|
||||
m_Timer = new TeleportTimer(this);
|
||||
m_Timer.Start();
|
||||
}
|
||||
|
||||
public PrimevalLich(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int GetAttackSound() { return 0x61E; }
|
||||
public override int GetDeathSound() { return 0x61F; }
|
||||
public override int GetHurtSound() { return 0x620; }
|
||||
public override int GetIdleSound() { return 0x621; }
|
||||
|
||||
public override bool CanRummageCorpses { get { return true; } }
|
||||
public override bool BleedImmune { get { return true; } }
|
||||
public override Poison PoisonImmune { get { return Poison.Lethal; } }
|
||||
public override bool ShowFameTitle { get { return false; } }
|
||||
public override bool ClickTitle { get { return false; } }
|
||||
|
||||
public override ChampionSkullType SkullType { get { return ChampionSkullType.None; } }
|
||||
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(BansheesCall), typeof(CastOffZombieSkin), typeof(ChannelersDefender), typeof(LightsRampart) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(TokenOfHolyFavor), typeof(TheMostKnowledgePerson), typeof(LieutenantOfTheBritannianRoyalGuard), typeof(ProtectoroftheBattleMage) };
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(MummifiedCorpse) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { };
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 3);
|
||||
AddLoot(LootPack.Meager);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new PrimalLichDust());
|
||||
c.DropItem(new RisingColossusScroll());
|
||||
}
|
||||
|
||||
public void ChangeCombatant()
|
||||
{
|
||||
ForceReacquire();
|
||||
BeginFlee(TimeSpan.FromSeconds(2.5));
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
if (m_NextDiscordTime <= DateTime.UtcNow)
|
||||
{
|
||||
Mobile target = Combatant as Mobile;
|
||||
|
||||
if (target != null && target.InRange(this, 8) && CanBeHarmful(target))
|
||||
Discord(target);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
if (0.05 >= Utility.RandomDouble())
|
||||
SpawnShadowDwellers(attacker);
|
||||
}
|
||||
|
||||
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
|
||||
{
|
||||
if (0.05 >= Utility.RandomDouble())
|
||||
SpawnShadowDwellers(caster);
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
if (DateTime.UtcNow > m_NextAbilityTime && 0.2 > Utility.RandomDouble())
|
||||
{
|
||||
switch (Utility.Random(2))
|
||||
{
|
||||
case 0: BlastRadius(); break;
|
||||
case 1: Lightning(); break;
|
||||
}
|
||||
|
||||
m_NextAbilityTime = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(25, 35));
|
||||
}
|
||||
}
|
||||
|
||||
#region Blast Radius
|
||||
private static readonly int BlastRange = 16;
|
||||
|
||||
private static readonly double[] BlastChance = new double[]
|
||||
{
|
||||
0.0, 0.0, 0.05, 0.95, 0.95, 0.95, 0.05, 0.95, 0.95,
|
||||
0.95, 0.05, 0.95, 0.95, 0.95, 0.05, 0.95, 0.95
|
||||
};
|
||||
|
||||
private void BlastRadius()
|
||||
{
|
||||
// TODO: Based on OSI taken videos, not accurate, but an aproximation
|
||||
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int x = -BlastRange; x <= BlastRange; x++)
|
||||
{
|
||||
for (int y = -BlastRange; y <= BlastRange; y++)
|
||||
{
|
||||
Point3D p = new Point3D(loc.X + x, loc.Y + y, loc.Z);
|
||||
int dist = (int)Math.Round(Utility.GetDistanceToSqrt(loc, p));
|
||||
|
||||
if (dist <= BlastRange && BlastChance[dist] > Utility.RandomDouble())
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(0.1 * dist), new TimerCallback(
|
||||
delegate
|
||||
{
|
||||
int hue = Utility.RandomList(90, 95);
|
||||
|
||||
Effects.SendPacket(loc, Map, new HuedEffect(EffectType.FixedXYZ, Serial.Zero, Serial.Zero, 0x3709, p, p, 20, 30, true, false, hue, 4));
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PlaySound(0x64C);
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(BlastRange);
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (this != m && GetDistanceToSqrt(m) <= BlastRange && CanBeHarmful(m))
|
||||
{
|
||||
if (m is ShadowDweller)
|
||||
continue;
|
||||
|
||||
DoHarmful(m);
|
||||
|
||||
double damage = m.Hits * 0.6;
|
||||
|
||||
if (damage < 100.0)
|
||||
damage = 100.0;
|
||||
else if (damage > 200.0)
|
||||
damage = 200.0;
|
||||
|
||||
DoHarmful(m);
|
||||
|
||||
AOS.Damage(m, this, (int)damage, 0, 0, 0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Lightning
|
||||
private void Lightning()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(BlastRange);
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m is ShadowDweller)
|
||||
continue;
|
||||
|
||||
if (m.IsPlayer() && GetDistanceToSqrt(m) <= BlastRange && CanBeHarmful(m))
|
||||
{
|
||||
DoHarmful(m);
|
||||
|
||||
Effects.SendBoltEffect(m, false, 0);
|
||||
Effects.PlaySound(m, m.Map, 0x51D);
|
||||
|
||||
double damage = m.Hits * 0.6;
|
||||
|
||||
if (damage < 100.0)
|
||||
damage = 100.0;
|
||||
else if (damage > 200.0)
|
||||
damage = 200.0;
|
||||
|
||||
AOS.Damage(m, this, (int)damage, 0, 0, 0, 0, 100);
|
||||
|
||||
count++;
|
||||
|
||||
if (count >= 6)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Teleport
|
||||
private class TeleportTimer : Timer
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
|
||||
private static int[] m_Offsets = new int[]
|
||||
{
|
||||
-1, -1,
|
||||
-1, 0,
|
||||
-1, 1,
|
||||
0, -1,
|
||||
0, 1,
|
||||
1, -1,
|
||||
1, 0,
|
||||
1, 1
|
||||
};
|
||||
|
||||
public TeleportTimer(Mobile owner)
|
||||
: base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(5.0))
|
||||
{
|
||||
m_Owner = owner;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Owner.Deleted)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
Map map = m_Owner.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
if (0.25 < Utility.RandomDouble())
|
||||
return;
|
||||
|
||||
Mobile toTeleport = null;
|
||||
|
||||
foreach (Mobile m in m_Owner.GetMobilesInRange(BlastRange))
|
||||
{
|
||||
if (m != m_Owner && m.IsPlayer() && m_Owner.CanBeHarmful(m) && m_Owner.CanSee(m))
|
||||
{
|
||||
if (m is ShadowDweller)
|
||||
continue;
|
||||
|
||||
toTeleport = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (toTeleport != null)
|
||||
{
|
||||
int offset = Utility.Random(8) * 2;
|
||||
|
||||
Point3D to = m_Owner.Location;
|
||||
|
||||
for (int i = 0; i < m_Offsets.Length; i += 2)
|
||||
{
|
||||
int x = m_Owner.X + m_Offsets[(offset + i) % m_Offsets.Length];
|
||||
int y = m_Owner.Y + m_Offsets[(offset + i + 1) % m_Offsets.Length];
|
||||
|
||||
if (map.CanSpawnMobile(x, y, m_Owner.Z))
|
||||
{
|
||||
to = new Point3D(x, y, m_Owner.Z);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (map.CanSpawnMobile(x, y, z))
|
||||
{
|
||||
to = new Point3D(x, y, z);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Mobile m = toTeleport;
|
||||
|
||||
Point3D from = m.Location;
|
||||
|
||||
m.Location = to;
|
||||
|
||||
Server.Spells.SpellHelper.Turn(m_Owner, toTeleport);
|
||||
Server.Spells.SpellHelper.Turn(toTeleport, m_Owner);
|
||||
|
||||
m.ProcessDelta();
|
||||
|
||||
Effects.SendLocationParticles(EffectItem.Create(from, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023);
|
||||
Effects.SendLocationParticles(EffectItem.Create(to, m.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023);
|
||||
|
||||
m.PlaySound(0x1FE);
|
||||
|
||||
m_Owner.Combatant = toTeleport;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Unholy Touch
|
||||
private static Dictionary<Mobile, Timer> m_UnholyTouched = new Dictionary<Mobile, Timer>();
|
||||
|
||||
public void Discord(Mobile target)
|
||||
{
|
||||
if (Utility.RandomDouble() < 0.9 && !m_UnholyTouched.ContainsKey(target))
|
||||
{
|
||||
double scalar = -((20 - (target.Skills[SkillName.MagicResist].Value / 10)) / 100);
|
||||
|
||||
ArrayList mods = new ArrayList();
|
||||
|
||||
if (target.PhysicalResistance > 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Physical, (int)((double)target.PhysicalResistance * scalar)));
|
||||
}
|
||||
|
||||
if (target.FireResistance > 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Fire, (int)((double)target.FireResistance * scalar)));
|
||||
}
|
||||
|
||||
if (target.ColdResistance > 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Cold, (int)((double)target.ColdResistance * scalar)));
|
||||
}
|
||||
|
||||
if (target.PoisonResistance > 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Poison, (int)((double)target.PoisonResistance * scalar)));
|
||||
}
|
||||
|
||||
if (target.EnergyResistance > 0)
|
||||
{
|
||||
mods.Add(new ResistanceMod(ResistanceType.Energy, (int)((double)target.EnergyResistance * scalar)));
|
||||
}
|
||||
|
||||
for (int i = 0; i < target.Skills.Length; ++i)
|
||||
{
|
||||
if (target.Skills[i].Value > 0)
|
||||
{
|
||||
mods.Add(new DefaultSkillMod((SkillName)i, true, target.Skills[i].Value * scalar));
|
||||
}
|
||||
}
|
||||
|
||||
target.PlaySound(0x458);
|
||||
|
||||
ApplyMods(target, mods);
|
||||
|
||||
m_UnholyTouched[target] = Timer.DelayCall(TimeSpan.FromSeconds(30), new TimerCallback(
|
||||
delegate
|
||||
{
|
||||
ClearMods(target, mods);
|
||||
|
||||
m_UnholyTouched.Remove(target);
|
||||
}));
|
||||
}
|
||||
|
||||
m_NextDiscordTime = DateTime.UtcNow + TimeSpan.FromSeconds(5 + Utility.RandomDouble() * 22);
|
||||
}
|
||||
|
||||
private static void ApplyMods(Mobile from, ArrayList mods)
|
||||
{
|
||||
for (int i = 0; i < mods.Count; ++i)
|
||||
{
|
||||
object mod = mods[i];
|
||||
|
||||
if (mod is ResistanceMod)
|
||||
from.AddResistanceMod((ResistanceMod)mod);
|
||||
else if (mod is StatMod)
|
||||
from.AddStatMod((StatMod)mod);
|
||||
else if (mod is SkillMod)
|
||||
from.AddSkillMod((SkillMod)mod);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ClearMods(Mobile from, ArrayList mods)
|
||||
{
|
||||
for (int i = 0; i < mods.Count; ++i)
|
||||
{
|
||||
object mod = mods[i];
|
||||
|
||||
if (mod is ResistanceMod)
|
||||
from.RemoveResistanceMod((ResistanceMod)mod);
|
||||
else if (mod is StatMod)
|
||||
from.RemoveStatMod(((StatMod)mod).Name);
|
||||
else if (mod is SkillMod)
|
||||
from.RemoveSkillMod((SkillMod)mod);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void SpawnShadowDwellers(Mobile target)
|
||||
{
|
||||
Map map = Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
int newShadowDwellers = Utility.RandomMinMax(2, 3);
|
||||
|
||||
for (int i = 0; i < newShadowDwellers; ++i)
|
||||
{
|
||||
ShadowDweller shadowdweller = new ShadowDweller();
|
||||
|
||||
shadowdweller.Team = Team;
|
||||
shadowdweller.FightMode = FightMode.Closest;
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = X + Utility.Random(3) - 1;
|
||||
int y = Y + Utility.Random(3) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, Z, 16, false, false))
|
||||
loc = new Point3D(x, y, Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
shadowdweller.MoveToWorld(loc, map);
|
||||
shadowdweller.Combatant = target;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Timer = new TeleportTimer(this);
|
||||
m_Timer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
223
Scripts/Mobiles/Bosses/Rikktor.cs
Normal file
223
Scripts/Mobiles/Bosses/Rikktor.cs
Normal file
@@ -0,0 +1,223 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Rikktor : BaseChampion
|
||||
{
|
||||
[Constructable]
|
||||
public Rikktor()
|
||||
: base(AIType.AI_Melee)
|
||||
{
|
||||
Body = 172;
|
||||
Name = "Rikktor";
|
||||
|
||||
SetStr(701, 900);
|
||||
SetDex(201, 350);
|
||||
SetInt(51, 100);
|
||||
|
||||
SetHits(15000);
|
||||
SetStam(203, 650);
|
||||
|
||||
SetDamage(28, 55);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 25);
|
||||
SetDamageType(ResistanceType.Fire, 50);
|
||||
SetDamageType(ResistanceType.Energy, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 80, 90);
|
||||
SetResistance(ResistanceType.Fire, 80, 90);
|
||||
SetResistance(ResistanceType.Cold, 30, 40);
|
||||
SetResistance(ResistanceType.Poison, 80, 90);
|
||||
SetResistance(ResistanceType.Energy, 80, 90);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 140.2, 160.0);
|
||||
SetSkill(SkillName.Tactics, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 118.4, 123.9);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
VirtualArmor = 130;
|
||||
|
||||
ForceActiveSpeed = 0.35;
|
||||
ForcePassiveSpeed = 0.7;
|
||||
}
|
||||
|
||||
public Rikktor(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Power;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(CrownOfTalKeesh) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(TheMostKnowledgePerson),
|
||||
typeof(BraveKnightOfTheBritannia),
|
||||
typeof(LieutenantOfTheBritannianRoyalGuard)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(LavaTile),
|
||||
typeof(MonsterStatuette),
|
||||
typeof(MonsterStatuette)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[]
|
||||
{
|
||||
MonsterStatuetteType.OphidianArchMage,
|
||||
MonsterStatuetteType.OphidianWarrior
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override ScaleType ScaleType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ScaleType.All;
|
||||
}
|
||||
}
|
||||
public override int Scales
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 4);
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
if (0.2 >= Utility.RandomDouble())
|
||||
this.Earthquake();
|
||||
}
|
||||
|
||||
public void Earthquake()
|
||||
{
|
||||
Map map = this.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
ArrayList targets = new ArrayList();
|
||||
|
||||
IPooledEnumerable eable = GetMobilesInRange(8);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == this || !this.CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != this.Team))
|
||||
targets.Add(m);
|
||||
else if (m.Player)
|
||||
targets.Add(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
this.PlaySound(0x2F3);
|
||||
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
|
||||
double damage = m.Hits * 0.6;
|
||||
|
||||
if (damage < 10.0)
|
||||
damage = 10.0;
|
||||
else if (damage > 75.0)
|
||||
damage = 75.0;
|
||||
|
||||
this.DoHarmful(m);
|
||||
|
||||
AOS.Damage(m, this, (int)damage, 100, 0, 0, 0, 0);
|
||||
|
||||
if (m.Alive && m.Body.IsHuman && !m.Mounted)
|
||||
m.Animate(20, 7, 1, true, false, 0); // take hit
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return Utility.Random(0x2CE, 2);
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x2D2;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return Utility.Random(0x2C7, 5);
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x2D1;
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x2CC;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
131
Scripts/Mobiles/Bosses/Semidar.cs
Normal file
131
Scripts/Mobiles/Bosses/Semidar.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Semidar : BaseChampion
|
||||
{
|
||||
[Constructable]
|
||||
public Semidar()
|
||||
: base(AIType.AI_Mage)
|
||||
{
|
||||
Name = "Semidar";
|
||||
Body = 174;
|
||||
BaseSoundID = 0x4B0;
|
||||
|
||||
SetStr(502, 600);
|
||||
SetDex(102, 200);
|
||||
SetInt(601, 750);
|
||||
|
||||
SetHits(10000);
|
||||
SetStam(103, 250);
|
||||
|
||||
SetDamage(29, 35);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 75);
|
||||
SetDamageType(ResistanceType.Fire, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 75, 90);
|
||||
SetResistance(ResistanceType.Fire, 65, 75);
|
||||
SetResistance(ResistanceType.Cold, 60, 70);
|
||||
SetResistance(ResistanceType.Poison, 65, 75);
|
||||
SetResistance(ResistanceType.Energy, 65, 75);
|
||||
|
||||
SetSkill(SkillName.EvalInt, 95.1, 100.0);
|
||||
SetSkill(SkillName.Magery, 90.1, 105.0);
|
||||
SetSkill(SkillName.Meditation, 95.1, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 120.2, 140.0);
|
||||
SetSkill(SkillName.Tactics, 90.1, 105.0);
|
||||
SetSkill(SkillName.Wrestling, 90.1, 105.0);
|
||||
|
||||
Fame = 24000;
|
||||
Karma = -24000;
|
||||
|
||||
VirtualArmor = 20;
|
||||
SetSpecialAbility(SpecialAbility.LifeDrain);
|
||||
|
||||
ForceActiveSpeed = 0.3;
|
||||
ForcePassiveSpeed = 0.6;
|
||||
}
|
||||
|
||||
public Semidar(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Pain;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(GladiatorsCollar) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(RoyalGuardSurvivalKnife), typeof(TheMostKnowledgePerson), typeof(LieutenantOfTheBritannianRoyalGuard) };
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(LavaTile), typeof(DemonSkull) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { };
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 4);
|
||||
AddLoot(LootPack.FilthyRich);
|
||||
}
|
||||
|
||||
public override void CheckReflect(Mobile caster, ref bool reflect)
|
||||
{
|
||||
if (!caster.Female && !caster.IsBodyMod)
|
||||
reflect = true; // Always reflect if caster isn't female
|
||||
}
|
||||
|
||||
/*public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
|
||||
{
|
||||
if (caster.Body.IsMale)
|
||||
scalar = 20; // Male bodies always reflect.. damage scaled 20x
|
||||
}*/
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
254
Scripts/Mobiles/Bosses/Serado.cs
Normal file
254
Scripts/Mobiles/Bosses/Serado.cs
Normal file
@@ -0,0 +1,254 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Engines.CannedEvil;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Serado : BaseChampion
|
||||
{
|
||||
[Constructable]
|
||||
public Serado()
|
||||
: base(AIType.AI_Melee)
|
||||
{
|
||||
Name = "Serado";
|
||||
Title = "the awakened";
|
||||
|
||||
Body = 249;
|
||||
Hue = 0x96C;
|
||||
|
||||
SetStr(1000);
|
||||
SetDex(150);
|
||||
SetInt(300);
|
||||
|
||||
SetHits(9000);
|
||||
SetMana(300);
|
||||
|
||||
SetDamage(29, 35);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 70);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
SetDamageType(ResistanceType.Energy, 10);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30);
|
||||
SetResistance(ResistanceType.Fire, 60);
|
||||
SetResistance(ResistanceType.Cold, 60);
|
||||
SetResistance(ResistanceType.Poison, 90);
|
||||
SetResistance(ResistanceType.Energy, 50);
|
||||
|
||||
SetSkill(SkillName.MagicResist, 120.0);
|
||||
SetSkill(SkillName.Tactics, 120.0);
|
||||
SetSkill(SkillName.Wrestling, 70.0);
|
||||
SetSkill(SkillName.Poisoning, 150.0);
|
||||
|
||||
Fame = 22500;
|
||||
Karma = -22500;
|
||||
|
||||
PackItem(Engines.Plants.Seed.RandomBonsaiSeed());
|
||||
|
||||
SetWeaponAbility(WeaponAbility.DoubleStrike);
|
||||
SetAreaEffect(AreaEffect.PoisonBreath);
|
||||
}
|
||||
|
||||
public Serado(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override ChampionSkullType SkullType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChampionSkullType.Power;
|
||||
}
|
||||
}
|
||||
public override Type[] UniqueList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(Pacify) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(BraveKnightOfTheBritannia),
|
||||
typeof(DetectiveBoots),
|
||||
typeof(EmbroideredOakLeafCloak),
|
||||
typeof(LieutenantOfTheBritannianRoyalGuard)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] DecorativeList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(Futon), typeof(SwampTile) };
|
||||
}
|
||||
}
|
||||
public override MonsterStatuetteType[] StatueTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return new MonsterStatuetteType[] { };
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
public override Poison HitPoison
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Lethal;
|
||||
}
|
||||
}
|
||||
public override double HitPoisonChance
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.8;
|
||||
}
|
||||
}
|
||||
public override int Feathers
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
public override bool ShowFameTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool ClickTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.UltraRich, 4);
|
||||
AddLoot(LootPack.FilthyRich);
|
||||
AddLoot(LootPack.Gems, 6);
|
||||
}
|
||||
|
||||
// TODO: Hit Lightning Area
|
||||
public override void OnDamagedBySpell(Mobile attacker)
|
||||
{
|
||||
base.OnDamagedBySpell(attacker);
|
||||
|
||||
ScaleResistances();
|
||||
DoCounter(attacker);
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
ScaleResistances();
|
||||
DoCounter(attacker);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private void ScaleResistances()
|
||||
{
|
||||
double hitsLost = (HitsMax - Hits) / (double)HitsMax;
|
||||
|
||||
SetResistance(ResistanceType.Physical, 30 + (int)(hitsLost * (95 - 30)));
|
||||
SetResistance(ResistanceType.Fire, 60 + (int)(hitsLost * (95 - 60)));
|
||||
SetResistance(ResistanceType.Cold, 60 + (int)(hitsLost * (95 - 60)));
|
||||
SetResistance(ResistanceType.Poison, 90 + (int)(hitsLost * (95 - 90)));
|
||||
SetResistance(ResistanceType.Energy, 50 + (int)(hitsLost * (95 - 50)));
|
||||
}
|
||||
|
||||
private void DoCounter(Mobile attacker)
|
||||
{
|
||||
if (Map == null || (attacker is BaseCreature && ((BaseCreature)attacker).BardProvoked))
|
||||
return;
|
||||
|
||||
if (0.2 > Utility.RandomDouble())
|
||||
{
|
||||
/* Counterattack with Hit Poison Area
|
||||
* 20-25 damage, unresistable
|
||||
* Lethal poison, 100% of the time
|
||||
* Particle effect: Type: "2" From: "0x4061A107" To: "0x0" ItemId: "0x36BD" ItemIdName: "explosion" FromLocation: "(296 615, 17)" ToLocation: "(296 615, 17)" Speed: "1" Duration: "10" FixedDirection: "True" Explode: "False" Hue: "0xA6" RenderMode: "0x0" Effect: "0x1F78" ExplodeEffect: "0x1" ExplodeSound: "0x0" Serial: "0x4061A107" Layer: "255" Unknown: "0x0"
|
||||
* Doesn't work on provoked monsters
|
||||
*/
|
||||
Mobile target = null;
|
||||
|
||||
if (attacker is BaseCreature)
|
||||
{
|
||||
Mobile m = ((BaseCreature)attacker).GetMaster();
|
||||
|
||||
if (m != null)
|
||||
target = m;
|
||||
}
|
||||
|
||||
if (target == null || !target.InRange(this, 25))
|
||||
target = attacker;
|
||||
|
||||
Animate(10, 4, 1, true, false, 0);
|
||||
|
||||
ArrayList targets = new ArrayList();
|
||||
IPooledEnumerable eable = target.GetMobilesInRange(8);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == this || !CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned || ((BaseCreature)m).Team != Team))
|
||||
targets.Add(m);
|
||||
else if (m.Player)
|
||||
targets.Add(m);
|
||||
}
|
||||
eable.Free();
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
Mobile m = (Mobile)targets[i];
|
||||
|
||||
DoHarmful(m);
|
||||
|
||||
AOS.Damage(m, this, Utility.RandomMinMax(20, 25), true, 0, 0, 0, 100, 0);
|
||||
|
||||
m.FixedParticles(0x36BD, 1, 10, 0x1F78, 0xA6, 0, (EffectLayer)255);
|
||||
m.ApplyPoison(this, Poison.Lethal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
60
Scripts/Mobiles/Bosses/ServantOfSemidar.cs
Normal file
60
Scripts/Mobiles/Bosses/ServantOfSemidar.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class ServantOfSemidar : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public ServantOfSemidar()
|
||||
: base(AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
this.Name = "a servant of Semidar";
|
||||
this.Body = 0x26;
|
||||
}
|
||||
|
||||
public ServantOfSemidar(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool DisallowAllMoves
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool InitialInnocent
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool CanBeDamaged()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void AddNameProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.AddNameProperties(list);
|
||||
|
||||
list.Add(1005494); // enslaved
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
217
Scripts/Mobiles/Bosses/ShimmeringEffusion.cs
Normal file
217
Scripts/Mobiles/Bosses/ShimmeringEffusion.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a shimmering effusion corpse")]
|
||||
public class ShimmeringEffusion : BasePeerless
|
||||
{
|
||||
[Constructable]
|
||||
public ShimmeringEffusion()
|
||||
: base(AIType.AI_Spellweaving, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "a shimmering effusion";
|
||||
Body = 0x105;
|
||||
|
||||
SetStr(500, 550);
|
||||
SetDex(350, 400);
|
||||
SetInt(1500, 1600);
|
||||
|
||||
SetHits(20000);
|
||||
|
||||
SetDamage(27, 31);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 20);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Cold, 20);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 60, 80);
|
||||
SetResistance(ResistanceType.Fire, 60, 80);
|
||||
SetResistance(ResistanceType.Cold, 60, 80);
|
||||
SetResistance(ResistanceType.Poison, 60, 80);
|
||||
SetResistance(ResistanceType.Energy, 60, 80);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 100.0, 105.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 105.0);
|
||||
SetSkill(SkillName.MagicResist, 150);
|
||||
SetSkill(SkillName.Magery, 150.0);
|
||||
SetSkill(SkillName.EvalInt, 150.0);
|
||||
SetSkill(SkillName.Meditation, 120.0);
|
||||
SetSkill(SkillName.Spellweaving, 120.0);
|
||||
|
||||
Fame = 30000;
|
||||
Karma = -30000;
|
||||
|
||||
PackResources(8);
|
||||
PackTalismans(5);
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.SuperBoss, 8);
|
||||
AddLoot(LootPack.Parrot, 2);
|
||||
AddLoot(LootPack.HighScrolls, 3);
|
||||
AddLoot(LootPack.MedScrolls, 3);
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new CapturedEssence());
|
||||
c.DropItem(new ShimmeringCrystals());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
{
|
||||
switch ( Utility.Random(4) )
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new ShimmeringEffusionStatuette());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new CorporealBrumeStatuette());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new MantraEffervescenceStatuette());
|
||||
break;
|
||||
case 3:
|
||||
c.DropItem(new FetidEssenceStatuette());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new FerretImprisonedInCrystal());
|
||||
|
||||
if (Utility.RandomDouble() < 0.025)
|
||||
c.DropItem(new CrystallineRing());
|
||||
}
|
||||
|
||||
public override bool AutoDispel
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
public override bool HasFireRing
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override double FireRingChance
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x1BF;
|
||||
}
|
||||
|
||||
public override int GetAttackSound()
|
||||
{
|
||||
return 0x1C0;
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 0x1C1;
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 0x1C2;
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
public override bool CanSpawnHelpers
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override int MaxHelpersWaves
|
||||
{
|
||||
get
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
}
|
||||
public override double SpawnHelpersChance
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
public override void SpawnHelpers()
|
||||
{
|
||||
int amount = 1;
|
||||
|
||||
if (Altar != null)
|
||||
amount = Altar.Fighters.Count;
|
||||
|
||||
if (amount > 5)
|
||||
amount = 5;
|
||||
|
||||
for (int i = 0; i < amount; i ++)
|
||||
{
|
||||
switch ( Utility.Random(3) )
|
||||
{
|
||||
case 0:
|
||||
SpawnHelper(new MantraEffervescence(), 2);
|
||||
break;
|
||||
case 1:
|
||||
SpawnHelper(new CorporealBrume(), 2);
|
||||
break;
|
||||
case 2:
|
||||
SpawnHelper(new FetidEssence(), 2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ShimmeringEffusion(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Scripts/Mobiles/Bosses/Silvani.cs
Normal file
165
Scripts/Mobiles/Bosses/Silvani.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Silvani : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public Silvani()
|
||||
: base(AIType.AI_Mage, FightMode.Evil, 18, 1, 0.1, 0.2)
|
||||
{
|
||||
this.Name = "Silvani";
|
||||
this.Body = 176;
|
||||
this.BaseSoundID = 0x467;
|
||||
|
||||
this.SetStr(253, 400);
|
||||
this.SetDex(157, 850);
|
||||
this.SetInt(503, 800);
|
||||
|
||||
this.SetHits(600);
|
||||
|
||||
this.SetDamage(27, 38);
|
||||
|
||||
this.SetDamageType(ResistanceType.Physical, 75);
|
||||
this.SetDamageType(ResistanceType.Cold, 25);
|
||||
|
||||
this.SetResistance(ResistanceType.Physical, 45, 55);
|
||||
this.SetResistance(ResistanceType.Fire, 30, 40);
|
||||
this.SetResistance(ResistanceType.Cold, 30, 40);
|
||||
this.SetResistance(ResistanceType.Poison, 40, 50);
|
||||
this.SetResistance(ResistanceType.Energy, 40, 50);
|
||||
|
||||
this.SetSkill(SkillName.EvalInt, 100.0);
|
||||
this.SetSkill(SkillName.Magery, 97.6, 107.5);
|
||||
this.SetSkill(SkillName.Meditation, 100.0);
|
||||
this.SetSkill(SkillName.MagicResist, 100.5, 150.0);
|
||||
this.SetSkill(SkillName.Tactics, 97.6, 100.0);
|
||||
this.SetSkill(SkillName.Wrestling, 97.6, 100.0);
|
||||
|
||||
this.Fame = 20000;
|
||||
this.Karma = 20000;
|
||||
|
||||
this.VirtualArmor = 50;
|
||||
}
|
||||
|
||||
public Silvani(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override TribeType Tribe { get { return TribeType.Fey; } }
|
||||
|
||||
public override OppositionGroup OppositionGroup
|
||||
{
|
||||
get
|
||||
{
|
||||
return OppositionGroup.FeyAndUndead;
|
||||
}
|
||||
}
|
||||
public override bool CanFly
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override Poison PoisonImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return Poison.Regular;
|
||||
}
|
||||
}
|
||||
public override int TreasureMapLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
}
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
this.AddLoot(LootPack.UltraRich, 2);
|
||||
}
|
||||
|
||||
public void SpawnPixies(Mobile target)
|
||||
{
|
||||
Map map = this.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
int newPixies = Utility.RandomMinMax(3, 6);
|
||||
|
||||
for (int i = 0; i < newPixies; ++i)
|
||||
{
|
||||
Pixie pixie = new Pixie();
|
||||
|
||||
pixie.Team = this.Team;
|
||||
pixie.FightMode = FightMode.Closest;
|
||||
|
||||
bool validLocation = false;
|
||||
Point3D loc = this.Location;
|
||||
|
||||
for (int j = 0; !validLocation && j < 10; ++j)
|
||||
{
|
||||
int x = this.X + Utility.Random(3) - 1;
|
||||
int y = this.Y + Utility.Random(3) - 1;
|
||||
int z = map.GetAverageZ(x, y);
|
||||
|
||||
if (validLocation = map.CanFit(x, y, this.Z, 16, false, false))
|
||||
loc = new Point3D(x, y, this.Z);
|
||||
else if (validLocation = map.CanFit(x, y, z, 16, false, false))
|
||||
loc = new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
pixie.MoveToWorld(loc, map);
|
||||
pixie.Combatant = target;
|
||||
}
|
||||
}
|
||||
|
||||
public override void AlterDamageScalarFrom(Mobile caster, ref double scalar)
|
||||
{
|
||||
if (0.1 >= Utility.RandomDouble())
|
||||
this.SpawnPixies(caster);
|
||||
}
|
||||
|
||||
public override void OnGaveMeleeAttack(Mobile defender)
|
||||
{
|
||||
base.OnGaveMeleeAttack(defender);
|
||||
|
||||
defender.Damage(Utility.Random(20, 10), this);
|
||||
defender.Stam -= Utility.Random(20, 10);
|
||||
defender.Mana -= Utility.Random(20, 10);
|
||||
}
|
||||
|
||||
public override void OnGotMeleeAttack(Mobile attacker)
|
||||
{
|
||||
base.OnGotMeleeAttack(attacker);
|
||||
|
||||
if (0.1 >= Utility.RandomDouble())
|
||||
this.SpawnPixies(attacker);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
205
Scripts/Mobiles/Bosses/SlasherOfVeils.cs
Normal file
205
Scripts/Mobiles/Bosses/SlasherOfVeils.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a slasher of veils corpse")]
|
||||
public class SlasherOfVeils : BaseSABoss
|
||||
{
|
||||
private static readonly int[] m_North = new int[]
|
||||
{
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 2,
|
||||
1, 2
|
||||
};
|
||||
private static readonly int[] m_East = new int[]
|
||||
{
|
||||
-1, 0,
|
||||
2, 0
|
||||
};
|
||||
|
||||
[Constructable]
|
||||
public SlasherOfVeils()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "The Slasher of Veils";
|
||||
Body = 741;
|
||||
|
||||
SetStr(901, 1010);
|
||||
SetDex(127, 153);
|
||||
SetInt(1078, 1263);
|
||||
|
||||
SetHits(50000, 65000);
|
||||
SetMana(10000);
|
||||
|
||||
SetDamage(10, 15);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 20);
|
||||
SetDamageType(ResistanceType.Fire, 20);
|
||||
SetDamageType(ResistanceType.Cold, 20);
|
||||
SetDamageType(ResistanceType.Poison, 20);
|
||||
SetDamageType(ResistanceType.Energy, 20);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 65, 80);
|
||||
SetResistance(ResistanceType.Fire, 70, 80);
|
||||
SetResistance(ResistanceType.Cold, 70, 80);
|
||||
SetResistance(ResistanceType.Poison, 70, 80);
|
||||
SetResistance(ResistanceType.Energy, 70, 80);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 110.8, 129.7);
|
||||
SetSkill(SkillName.EvalInt, 113.4, 130);
|
||||
SetSkill(SkillName.Magery, 111.7, 130);
|
||||
SetSkill(SkillName.Spellweaving, 111.1, 125);
|
||||
SetSkill(SkillName.Meditation, 113.5, 129.9);
|
||||
SetSkill(SkillName.MagicResist, 110, 129.8);
|
||||
SetSkill(SkillName.Tactics, 110.5, 126.3);
|
||||
SetSkill(SkillName.Wrestling, 110.1, 130);
|
||||
SetSkill(SkillName.DetectHidden, 127.1);
|
||||
|
||||
Fame = 35000;
|
||||
Karma = -35000;
|
||||
|
||||
SetSpecialAbility(SpecialAbility.AngryFire);
|
||||
SetSpecialAbility(SpecialAbility.ManaDrain);
|
||||
SetWeaponAbility(WeaponAbility.ParalyzingBlow);
|
||||
SetSpecialAbility(SpecialAbility.TrueFear);
|
||||
}
|
||||
|
||||
public SlasherOfVeils(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] UniqueSAList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(ClawsOfTheBerserker), typeof(Lavaliere), typeof(Mangler), typeof(HumanSignOfChaos), typeof(GargishSignOfChaos), typeof(StandardOfChaosG), typeof(StandardOfChaos) };
|
||||
}
|
||||
}
|
||||
public override Type[] SharedSAList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(AxesOfFury), typeof(BladeOfBattle), typeof(DemonBridleRing), typeof(PetrifiedSnake), typeof(PillarOfStrength), typeof(SwordOfShatteredHopes), typeof(SummonersKilt) };
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Unprovokable
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool BardImmune
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 1589;
|
||||
}
|
||||
|
||||
public override int GetAngerSound()
|
||||
{
|
||||
return 1586;
|
||||
}
|
||||
|
||||
public override int GetHurtSound()
|
||||
{
|
||||
return 1588;
|
||||
}
|
||||
|
||||
public override int GetDeathSound()
|
||||
{
|
||||
return 1587;
|
||||
}
|
||||
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 4);
|
||||
AddLoot(LootPack.Gems, 8);
|
||||
}
|
||||
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
//if (Combatant == null)
|
||||
// return;
|
||||
|
||||
//if (Hits > 0.6 * HitsMax && Utility.RandomDouble() < 0.05)
|
||||
// FireRing();
|
||||
}
|
||||
|
||||
public override void FireRing()
|
||||
{
|
||||
for (int i = 0; i < m_North.Length; i += 2)
|
||||
{
|
||||
Point3D p = Location;
|
||||
|
||||
p.X += m_North[i];
|
||||
p.Y += m_North[i + 1];
|
||||
|
||||
IPoint3D po = p as IPoint3D;
|
||||
|
||||
SpellHelper.GetSurfaceTop(ref po);
|
||||
|
||||
Effects.SendLocationEffect(po, Map, 0x3E27, 50);
|
||||
}
|
||||
|
||||
for (int i = 0; i < m_East.Length; i += 2)
|
||||
{
|
||||
Point3D p = Location;
|
||||
|
||||
p.X += m_East[i];
|
||||
p.Y += m_East[i + 1];
|
||||
|
||||
IPoint3D po = p as IPoint3D;
|
||||
|
||||
SpellHelper.GetSurfaceTop(ref po);
|
||||
|
||||
Effects.SendLocationEffect(po, Map, 0x3E31, 50);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDamagedBySpell(Mobile caster)
|
||||
{
|
||||
if (0.5 > Utility.RandomDouble() && caster.InRange(Location, 10) && Map != null && caster.Alive && caster != this && caster.Map == Map)
|
||||
{
|
||||
MoveToWorld(caster.Location, Map);
|
||||
|
||||
Timer.DelayCall(() =>
|
||||
{
|
||||
Combatant = caster;
|
||||
});
|
||||
|
||||
Effects.PlaySound(Location, Map, 0x1FE);
|
||||
}
|
||||
|
||||
base.OnDamagedBySpell(caster);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
463
Scripts/Mobiles/Bosses/StygianDragon.cs
Normal file
463
Scripts/Mobiles/Bosses/StygianDragon.cs
Normal file
@@ -0,0 +1,463 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a stygian dragon corpse")]
|
||||
public class StygianDragon : BaseSABoss
|
||||
{
|
||||
private DateTime m_Delay;
|
||||
|
||||
[Constructable]
|
||||
public StygianDragon()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.3, 0.5)
|
||||
{
|
||||
Name = "Stygian Dragon";
|
||||
Body = 826;
|
||||
BaseSoundID = 362;
|
||||
|
||||
SetStr(702);
|
||||
SetDex(250);
|
||||
SetInt(180);
|
||||
|
||||
SetHits(30000);
|
||||
SetStam(431);
|
||||
SetMana(180);
|
||||
|
||||
SetDamage(33, 55);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 25);
|
||||
SetDamageType(ResistanceType.Fire, 50);
|
||||
SetDamageType(ResistanceType.Energy, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 80, 90);
|
||||
SetResistance(ResistanceType.Fire, 80, 90);
|
||||
SetResistance(ResistanceType.Cold, 60, 70);
|
||||
SetResistance(ResistanceType.Poison, 80, 90);
|
||||
SetResistance(ResistanceType.Energy, 80, 90);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 150.0, 155.0);
|
||||
SetSkill(SkillName.Tactics, 120.7, 125.0);
|
||||
SetSkill(SkillName.Wrestling, 115.0, 117.7);
|
||||
|
||||
Fame = 15000;
|
||||
Karma = -15000;
|
||||
|
||||
VirtualArmor = 60;
|
||||
|
||||
Tamable = false;
|
||||
|
||||
SetWeaponAbility(WeaponAbility.Bladeweave);
|
||||
SetWeaponAbility(WeaponAbility.TalonStrike);
|
||||
SetSpecialAbility(SpecialAbility.DragonBreath);
|
||||
}
|
||||
|
||||
public StygianDragon(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] UniqueSAList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(BurningAmber), typeof(DraconisWrath), typeof(DragonHideShield), typeof(FallenMysticsSpellbook),
|
||||
typeof(LifeSyphon), typeof(GargishSignOfOrder), typeof(HumanSignOfOrder), typeof(VampiricEssence)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override Type[] SharedSAList
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(AxesOfFury), typeof(SummonersKilt), typeof(GiantSteps),
|
||||
typeof(TokenOfHolyFavor)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
public override bool Unprovokable { get { return false; } }
|
||||
public override bool BardImmune { get { return false; } }
|
||||
public override bool AutoDispel { get { return !Controlled; } }
|
||||
public override int Meat { get { return 19; } }
|
||||
public override int Hides { get { return 30; } }
|
||||
public override HideType HideType { get { return HideType.Barbed; } }
|
||||
public override int Scales { get { return 7; } }
|
||||
public override ScaleType ScaleType { get { return (Body == 12 ? ScaleType.Yellow : ScaleType.Red); } }
|
||||
public override int DragonBlood { get { return 48; } }
|
||||
public override bool CanFlee { get { return false; } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 4);
|
||||
AddLoot(LootPack.Gems, 8);
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
base.OnThink();
|
||||
|
||||
if (Combatant == null || !(Combatant is Mobile))
|
||||
return;
|
||||
|
||||
if (DateTime.UtcNow > m_Delay)
|
||||
{
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0: CrimsonMeteor(this, (Mobile)Combatant, 70, 125); break;
|
||||
case 1: DoStygianFireball(); break;
|
||||
case 2: DoFireColumn(); break;
|
||||
}
|
||||
|
||||
m_Delay = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 60));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new StygianDragonHead());
|
||||
|
||||
if ( Paragon.ChestChance > Utility.RandomDouble() )
|
||||
c.DropItem( new ParagonChest( Name, 5 ) );
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)1);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
#region Crimson Meteor
|
||||
public static void CrimsonMeteor(Mobile owner, Mobile combatant, int minDamage, int maxDamage)
|
||||
{
|
||||
if (!combatant.Alive || combatant.Map == null || combatant.Map == Map.Internal)
|
||||
return;
|
||||
|
||||
new CrimsonMeteorTimer(owner, combatant.Location, minDamage, maxDamage).Start();
|
||||
}
|
||||
|
||||
public class CrimsonMeteorTimer : Timer
|
||||
{
|
||||
private Mobile m_From;
|
||||
private Map m_Map;
|
||||
private int m_Count;
|
||||
private int m_MaxCount;
|
||||
private bool m_DoneDamage;
|
||||
private Point3D m_LastTarget;
|
||||
private Rectangle2D m_ShowerArea;
|
||||
private List<Mobile> m_ToDamage;
|
||||
|
||||
private int m_MinDamage, m_MaxDamage;
|
||||
|
||||
public CrimsonMeteorTimer(Mobile from, Point3D loc, int min, int max)
|
||||
: base(TimeSpan.FromMilliseconds(250.0), TimeSpan.FromMilliseconds(250.0))
|
||||
{
|
||||
m_From = from;
|
||||
m_Map = from.Map;
|
||||
m_Count = 0;
|
||||
m_MaxCount = 25; // in ticks
|
||||
m_LastTarget = loc;
|
||||
m_DoneDamage = false;
|
||||
m_ShowerArea = new Rectangle2D(loc.X - 2, loc.Y - 2, 4, 4);
|
||||
|
||||
m_MinDamage = min;
|
||||
m_MaxDamage = max;
|
||||
|
||||
m_ToDamage = new List<Mobile>();
|
||||
|
||||
IPooledEnumerable eable = m_Map.GetMobilesInBounds(m_ShowerArea);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m != from && m_From.CanBeHarmful(m))
|
||||
m_ToDamage.Add(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_From == null || m_From.Deleted || m_Map == null || m_Map == Map.Internal)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (0.33 > Utility.RandomDouble())
|
||||
{
|
||||
var field = new FireField(m_From, 25, Utility.RandomBool());
|
||||
field.MoveToWorld(m_LastTarget, m_Map);
|
||||
}
|
||||
|
||||
Point3D start = new Point3D();
|
||||
Point3D finish = new Point3D();
|
||||
|
||||
finish.X = m_ShowerArea.X + Utility.Random(m_ShowerArea.Width);
|
||||
finish.Y = m_ShowerArea.Y + Utility.Random(m_ShowerArea.Height);
|
||||
finish.Z = m_From.Z;
|
||||
|
||||
SpellHelper.AdjustField(ref finish, m_Map, 16, false);
|
||||
|
||||
//objects move from upper right/right to left as per OSI
|
||||
start.X = finish.X + Utility.RandomMinMax(-4, 4);
|
||||
start.Y = finish.Y - 15;
|
||||
start.Z = finish.Z + 50;
|
||||
|
||||
Effects.SendMovingParticles(
|
||||
new Entity(Serial.Zero, start, m_Map),
|
||||
new Entity(Serial.Zero, finish, m_Map),
|
||||
0x36D4, 15, 0, false, false, 0, 0, 9502, 1, 0, (EffectLayer)255, 0x100);
|
||||
|
||||
Effects.PlaySound(finish, m_Map, 0x11D);
|
||||
|
||||
m_LastTarget = finish;
|
||||
m_Count++;
|
||||
|
||||
if (m_Count >= m_MaxCount / 2 && !m_DoneDamage)
|
||||
{
|
||||
if (m_ToDamage != null && m_ToDamage.Count > 0)
|
||||
{
|
||||
int damage;
|
||||
|
||||
foreach (Mobile mob in m_ToDamage)
|
||||
{
|
||||
damage = Utility.RandomMinMax(m_MinDamage, m_MaxDamage);
|
||||
|
||||
m_From.DoHarmful(mob);
|
||||
AOS.Damage(mob, m_From, damage, 0, 100, 0, 0, 0);
|
||||
|
||||
mob.FixedParticles(0x36BD, 1, 15, 9502, 0, 3, (EffectLayer)255);
|
||||
}
|
||||
}
|
||||
|
||||
m_DoneDamage = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Count >= m_MaxCount)
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fire Column
|
||||
public void DoFireColumn()
|
||||
{
|
||||
var map = Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
Direction columnDir = Utility.GetDirection(this, Combatant);
|
||||
|
||||
Packet flash = ScreenLightFlash.Instance;
|
||||
IPooledEnumerable e = Map.GetClientsInRange(Location, Core.GlobalUpdateRange);
|
||||
|
||||
foreach (NetState ns in e)
|
||||
{
|
||||
if (ns.Mobile != null)
|
||||
ns.Mobile.Send(flash);
|
||||
}
|
||||
|
||||
e.Free();
|
||||
|
||||
int x = X;
|
||||
int y = Y;
|
||||
bool south = columnDir == Direction.East || columnDir == Direction.West;
|
||||
|
||||
Movement.Movement.Offset(columnDir, ref x, ref y);
|
||||
Point3D p = new Point3D(x, y, Z);
|
||||
SpellHelper.AdjustField(ref p, map, 16, false);
|
||||
|
||||
var fire = new FireField(this, Utility.RandomMinMax(25, 32), south);
|
||||
fire.MoveToWorld(p, map);
|
||||
|
||||
for (int i = 0; i < 7; i++)
|
||||
{
|
||||
Movement.Movement.Offset(columnDir, ref x, ref y);
|
||||
|
||||
p = new Point3D(x, y, Z);
|
||||
SpellHelper.AdjustField(ref p, map, 16, false);
|
||||
|
||||
fire = new FireField(this, Utility.RandomMinMax(25, 32), south);
|
||||
fire.MoveToWorld(p, map);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Fire Field
|
||||
public class FireField : Item
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
private Timer m_Timer;
|
||||
private DateTime m_Destroy;
|
||||
|
||||
[Constructable]
|
||||
public FireField(Mobile owner, int duration, bool south)
|
||||
: base(GetItemID(south))
|
||||
{
|
||||
Movable = false;
|
||||
m_Destroy = DateTime.UtcNow + TimeSpan.FromSeconds(duration);
|
||||
|
||||
m_Owner = owner;
|
||||
m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), new TimerCallback(OnTick));
|
||||
}
|
||||
|
||||
private static int GetItemID(bool south)
|
||||
{
|
||||
if (south)
|
||||
return 0x398C;
|
||||
else
|
||||
return 0x3996;
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
if (m_Timer != null)
|
||||
m_Timer.Stop();
|
||||
}
|
||||
|
||||
private void OnTick()
|
||||
{
|
||||
if (DateTime.UtcNow > m_Destroy)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
else
|
||||
{
|
||||
IPooledEnumerable eable = GetMobilesInRange(0);
|
||||
List<Mobile> list = new List<Mobile>();
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (m_Owner == null || CanTargetMob(m))
|
||||
{
|
||||
list.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
foreach (var mob in list)
|
||||
{
|
||||
DealDamage(mob);
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnMoveOver(Mobile m)
|
||||
{
|
||||
DealDamage(m);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void DealDamage(Mobile m)
|
||||
{
|
||||
if (m != m_Owner && (m_Owner == null || CanTargetMob(m)))
|
||||
AOS.Damage(m, m_Owner, Utility.RandomMinMax(2, 4), 0, 100, 0, 0, 0);
|
||||
}
|
||||
|
||||
public bool CanTargetMob(Mobile m)
|
||||
{
|
||||
return m != m_Owner && m_Owner.CanBeHarmful(m, false) && (m is PlayerMobile || (m is BaseCreature && ((BaseCreature)m).GetMaster() is PlayerMobile));
|
||||
}
|
||||
|
||||
public FireField(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
// Unsaved.
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Stygian Fireball
|
||||
public void DoStygianFireball()
|
||||
{
|
||||
if (!(Combatant is Mobile) || !InRange(Combatant.Location, 10))
|
||||
return;
|
||||
|
||||
new StygianFireballTimer(this, (Mobile)Combatant);
|
||||
PlaySound(0x1F3);
|
||||
}
|
||||
|
||||
private class StygianFireballTimer : Timer
|
||||
{
|
||||
private StygianDragon m_Dragon;
|
||||
private Mobile m_Combatant;
|
||||
private int m_Ticks;
|
||||
|
||||
public StygianFireballTimer(StygianDragon dragon, Mobile combatant)
|
||||
: base(TimeSpan.FromMilliseconds(200), TimeSpan.FromMilliseconds(200))
|
||||
{
|
||||
m_Dragon = dragon;
|
||||
m_Combatant = combatant;
|
||||
m_Ticks = 0;
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Dragon.MovingParticles(m_Combatant, 0x46E6, 7, 0, false, true, 1265, 0, 9502, 4019, 0x026, 0);
|
||||
|
||||
if (m_Ticks >= 10)
|
||||
{
|
||||
int damage = Utility.RandomMinMax(120, 150);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(.20), new TimerStateCallback(DoDamage_Callback), new object[] { m_Combatant, m_Dragon, damage });
|
||||
|
||||
Stop();
|
||||
}
|
||||
|
||||
m_Ticks++;
|
||||
}
|
||||
|
||||
public void DoDamage_Callback(object state)
|
||||
{
|
||||
object[] obj = (object[])state;
|
||||
|
||||
Mobile c = (Mobile)obj[0];
|
||||
Mobile d = (Mobile)obj[1];
|
||||
int dam = (int)obj[2];
|
||||
|
||||
d.DoHarmful(c);
|
||||
AOS.Damage(c, d, dam, false, 0, 0, 0, 0, 0, 100, 0, false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
440
Scripts/Mobiles/Bosses/Travesty.cs
Normal file
440
Scripts/Mobiles/Bosses/Travesty.cs
Normal file
@@ -0,0 +1,440 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a travesty's corpse")]
|
||||
public class Travesty : BasePeerless
|
||||
{
|
||||
public override WeaponAbility GetWeaponAbility()
|
||||
{
|
||||
if (Weapon == null)
|
||||
return null;
|
||||
|
||||
BaseWeapon weapon = Weapon as BaseWeapon;
|
||||
|
||||
return Utility.RandomBool() ? weapon.PrimaryAbility : weapon.SecondaryAbility;
|
||||
}
|
||||
|
||||
private DateTime m_NextBodyChange;
|
||||
private DateTime m_NextMirrorImage;
|
||||
private bool m_SpawnedHelpers;
|
||||
private Timer m_Timer;
|
||||
|
||||
private bool _CanDiscord;
|
||||
private bool _CanPeace;
|
||||
private bool _CanProvoke;
|
||||
|
||||
public override bool CanDiscord { get { return _CanDiscord; } }
|
||||
public override bool CanPeace { get { return _CanPeace; } }
|
||||
public override bool CanProvoke { get { return _CanProvoke; } }
|
||||
|
||||
[Constructable]
|
||||
public Travesty()
|
||||
: base(AIType.AI_Mage, FightMode.Closest, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
Name = "Travesty";
|
||||
Body = 0x108;
|
||||
|
||||
BaseSoundID = 0x46E;
|
||||
|
||||
SetStr(900, 950);
|
||||
SetDex(900, 950);
|
||||
SetInt(900, 950);
|
||||
|
||||
SetHits(35000);
|
||||
|
||||
SetDamage(11, 18);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 50, 70);
|
||||
SetResistance(ResistanceType.Fire, 50, 70);
|
||||
SetResistance(ResistanceType.Cold, 50, 70);
|
||||
SetResistance(ResistanceType.Poison, 50, 70);
|
||||
SetResistance(ResistanceType.Energy, 50, 70);
|
||||
|
||||
SetSkill(SkillName.Wrestling, 300.0, 320.0);
|
||||
SetSkill(SkillName.Tactics, 100.0, 120.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0, 120.0);
|
||||
SetSkill(SkillName.Anatomy, 100.0, 120.0);
|
||||
SetSkill(SkillName.Healing, 100.0, 120.0);
|
||||
SetSkill(SkillName.Poisoning, 100.0, 120.0);
|
||||
SetSkill(SkillName.DetectHidden, 100.0);
|
||||
SetSkill(SkillName.Hiding, 100.0);
|
||||
SetSkill(SkillName.Parry, 100.0, 110.0);
|
||||
SetSkill(SkillName.Magery, 100.0, 120.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0, 120.0);
|
||||
SetSkill(SkillName.Meditation, 100.0, 120.0);
|
||||
SetSkill(SkillName.Necromancy, 100.0, 120.0);
|
||||
SetSkill(SkillName.SpiritSpeak, 100.0, 120.0);
|
||||
SetSkill(SkillName.Focus, 100.0, 120.0);
|
||||
SetSkill(SkillName.Spellweaving, 100.0, 120.0);
|
||||
SetSkill(SkillName.Discordance, 100.0, 120.0);
|
||||
SetSkill(SkillName.Bushido, 100.0, 120.0);
|
||||
SetSkill(SkillName.Ninjitsu, 100.0, 120.0);
|
||||
SetSkill(SkillName.Chivalry, 100.0, 120.0);
|
||||
|
||||
SetSkill(SkillName.Musicianship, 100.0, 120.0);
|
||||
SetSkill(SkillName.Discordance, 100.0, 120.0);
|
||||
SetSkill(SkillName.Provocation, 100.0, 120.0);
|
||||
SetSkill(SkillName.Peacemaking, 100.0, 120.0);
|
||||
|
||||
Fame = 30000;
|
||||
Karma = -30000;
|
||||
|
||||
VirtualArmor = 50;
|
||||
PackTalismans(5);
|
||||
PackResources(8);
|
||||
|
||||
for (int i = 0; i < Utility.RandomMinMax(1, 6); i++)
|
||||
{
|
||||
PackItem(Loot.RandomScroll(0, Loot.ArcanistScrollTypes.Length, SpellbookType.Arcanist));
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShowFameTitle { get { return false; } }
|
||||
|
||||
public Travesty(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnDeath(Container c)
|
||||
{
|
||||
base.OnDeath(c);
|
||||
|
||||
c.DropItem(new EyeOfTheTravesty());
|
||||
c.DropItem(new OrdersFromMinax());
|
||||
|
||||
switch (Utility.Random(3))
|
||||
{
|
||||
case 0:
|
||||
c.DropItem(new TravestysSushiPreparations());
|
||||
break;
|
||||
case 1:
|
||||
c.DropItem(new TravestysFineTeakwoodTray());
|
||||
break;
|
||||
case 2:
|
||||
c.DropItem(new TravestysCollectionOfShells());
|
||||
break;
|
||||
}
|
||||
|
||||
if (Utility.RandomDouble() < 0.6)
|
||||
c.DropItem(new ParrotItem());
|
||||
|
||||
if (Utility.RandomDouble() < 0.1)
|
||||
c.DropItem(new TragicRemainsOfTravesty());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new ImprisonedDog());
|
||||
|
||||
if (Utility.RandomDouble() < 0.05)
|
||||
c.DropItem(new MarkOfTravesty());
|
||||
|
||||
if (Utility.RandomDouble() < 0.025)
|
||||
{
|
||||
c.DropItem(new MalekisHonor());
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
if (0.1 > Utility.RandomDouble() && m_NextMirrorImage < DateTime.UtcNow)
|
||||
{
|
||||
new Server.Spells.Ninjitsu.MirrorImage(this, null).Cast();
|
||||
|
||||
m_NextMirrorImage = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(20, 45));
|
||||
}
|
||||
|
||||
if (0.25 > Utility.RandomDouble() && DateTime.UtcNow > m_NextBodyChange)
|
||||
{
|
||||
ChangeBody();
|
||||
}
|
||||
|
||||
base.OnDamage(amount, from, willKill);
|
||||
}
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
AddLoot(LootPack.AosSuperBoss, 8);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
public void ChangeBody()
|
||||
{
|
||||
List<Mobile> list = new List<Mobile>();
|
||||
|
||||
IPooledEnumerable eable = Map.GetMobilesInRange(Location, 5);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m.Player && m.AccessLevel == AccessLevel.Player && m.Alive)
|
||||
list.Add(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (list.Count == 0 || IsBodyMod)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mobile attacker = list[Utility.Random(list.Count)];
|
||||
|
||||
BodyMod = attacker.Body;
|
||||
HueMod = attacker.Hue;
|
||||
NameMod = attacker.Name;
|
||||
Female = attacker.Female;
|
||||
Title = "(Travesty)";
|
||||
HairItemID = attacker.HairItemID;
|
||||
HairHue = attacker.HairHue;
|
||||
FacialHairItemID = attacker.FacialHairItemID;
|
||||
FacialHairHue = attacker.FacialHairHue;
|
||||
|
||||
foreach (Item item in attacker.Items)
|
||||
{
|
||||
if (item.Layer < Layer.Mount &&
|
||||
item.Layer != Layer.Backpack &&
|
||||
item.Layer != Layer.Mount &&
|
||||
item.Layer != Layer.Bank &&
|
||||
item.Layer != Layer.Hair &&
|
||||
item.Layer != Layer.Face &&
|
||||
item.Layer != Layer.FacialHair)
|
||||
{
|
||||
if (FindItemOnLayer(item.Layer) == null)
|
||||
{
|
||||
if (item is BaseRanged)
|
||||
{
|
||||
Item i = FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
if (i != null)
|
||||
i.Delete();
|
||||
|
||||
i = FindItemOnLayer(Layer.OneHanded);
|
||||
|
||||
if (i != null)
|
||||
i.Delete();
|
||||
|
||||
AddItem(Loot.Construct(item.GetType()));
|
||||
}
|
||||
else
|
||||
{
|
||||
AddItem(new ClonedItem(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker.Skills[SkillName.Swords].Value >= 50.0 || attacker.Skills[SkillName.Fencing].Value >= 50.0 || attacker.Skills[SkillName.Macing].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Melee);
|
||||
|
||||
if (attacker.Skills[SkillName.Archery].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Archer);
|
||||
|
||||
if (attacker.Skills[SkillName.Spellweaving].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Spellweaving);
|
||||
|
||||
if (attacker.Skills[SkillName.Mysticism].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Mystic);
|
||||
|
||||
if (attacker.Skills[SkillName.Magery].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Mage);
|
||||
|
||||
if (attacker.Skills[SkillName.Necromancy].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Necro);
|
||||
|
||||
if (attacker.Skills[SkillName.Ninjitsu].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Ninja);
|
||||
|
||||
if (attacker.Skills[SkillName.Bushido].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_Samurai);
|
||||
|
||||
if (attacker.Skills[SkillName.Necromancy].Value >= 50.0 && attacker.Skills[SkillName.Magery].Value >= 50.0)
|
||||
ChangeAIType(AIType.AI_NecroMage);
|
||||
|
||||
PlaySound(0x511);
|
||||
FixedParticles(0x376A, 1, 14, 5045, EffectLayer.Waist);
|
||||
|
||||
m_NextBodyChange = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
|
||||
|
||||
if (attacker.Skills[SkillName.Healing].Base > 20)
|
||||
{
|
||||
SetSpecialAbility(SpecialAbility.Heal);
|
||||
}
|
||||
|
||||
if (attacker.Skills[SkillName.Discordance].Base > 50)
|
||||
{
|
||||
_CanDiscord = true;
|
||||
}
|
||||
|
||||
if (attacker.Skills[SkillName.Peacemaking].Base > 50)
|
||||
{
|
||||
_CanPeace = true;
|
||||
}
|
||||
|
||||
if (attacker.Skills[SkillName.Provocation].Base > 50)
|
||||
{
|
||||
_CanProvoke = true;
|
||||
}
|
||||
|
||||
if (m_Timer != null)
|
||||
m_Timer.Stop();
|
||||
|
||||
m_Timer = Timer.DelayCall(TimeSpan.FromMinutes(1.0), new TimerCallback(RestoreBody));
|
||||
}
|
||||
|
||||
public void DeleteItems()
|
||||
{
|
||||
ColUtility.SafeDelete(Items, item => item is ClonedItem || item is BaseRanged);
|
||||
|
||||
if (Backpack != null)
|
||||
{
|
||||
ColUtility.SafeDelete(Backpack.Items, item => item is ClonedItem || item is BaseRanged);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void RestoreBody()
|
||||
{
|
||||
BodyMod = 0;
|
||||
HueMod = -1;
|
||||
NameMod = null;
|
||||
Female = false;
|
||||
Title = null;
|
||||
|
||||
_CanDiscord = false;
|
||||
_CanPeace = false;
|
||||
_CanProvoke = false;
|
||||
|
||||
if (HasAbility(SpecialAbility.Heal))
|
||||
{
|
||||
RemoveSpecialAbility(SpecialAbility.Heal);
|
||||
}
|
||||
|
||||
DeleteItems();
|
||||
|
||||
ChangeAIType(AIType.AI_Mage);
|
||||
|
||||
if (m_Timer != null)
|
||||
{
|
||||
m_Timer.Stop();
|
||||
m_Timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
RestoreBody();
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
if (m_Timer != null)
|
||||
m_Timer.Stop();
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
#region Spawn Helpers
|
||||
public override bool CanSpawnHelpers { get { return true; } }
|
||||
public override int MaxHelpersWaves { get { return 1; } }
|
||||
|
||||
public override bool CanSpawnWave()
|
||||
{
|
||||
if (Hits > 2000)
|
||||
m_SpawnedHelpers = false;
|
||||
|
||||
return !m_SpawnedHelpers && Hits < 2000;
|
||||
}
|
||||
|
||||
public override void SpawnHelpers()
|
||||
{
|
||||
m_SpawnedHelpers = true;
|
||||
|
||||
SpawnNinjaGroup(new Point3D(80, 1964, 0));
|
||||
SpawnNinjaGroup(new Point3D(80, 1949, 0));
|
||||
SpawnNinjaGroup(new Point3D(92, 1948, 0));
|
||||
SpawnNinjaGroup(new Point3D(92, 1962, 0));
|
||||
|
||||
if (Map != null && Map != Map.Internal && Region.IsPartOf("TheCitadel"))
|
||||
{
|
||||
var loc = _WarpLocs[Utility.Random(_WarpLocs.Length)];
|
||||
MoveToWorld(loc, Map);
|
||||
}
|
||||
}
|
||||
|
||||
public void SpawnNinjaGroup(Point3D _location)
|
||||
{
|
||||
SpawnHelper(new DragonsFlameMage(), _location);
|
||||
SpawnHelper(new SerpentsFangAssassin(), _location);
|
||||
SpawnHelper(new TigersClawThief(), _location);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Point3D[] _WarpLocs =
|
||||
{
|
||||
new Point3D(71, 1939, 0),
|
||||
new Point3D(71, 1955, 0),
|
||||
new Point3D(69, 1972, 0),
|
||||
new Point3D(86, 1971, 0),
|
||||
new Point3D(103, 1972, 0),
|
||||
new Point3D(86, 1939, 0),
|
||||
new Point3D(102, 1938, 0),
|
||||
};
|
||||
|
||||
private class ClonedItem : Item
|
||||
{
|
||||
public ClonedItem(Item oItem)
|
||||
: base(oItem.ItemID)
|
||||
{
|
||||
Name = oItem.Name;
|
||||
Weight = oItem.Weight;
|
||||
Hue = oItem.Hue;
|
||||
Layer = oItem.Layer;
|
||||
}
|
||||
|
||||
public override DeathMoveResult OnParentDeath(Mobile parent)
|
||||
{
|
||||
return DeathMoveResult.RemainEquiped;
|
||||
}
|
||||
|
||||
public override DeathMoveResult OnInventoryDeath(Mobile parent)
|
||||
{
|
||||
Delete();
|
||||
return base.OnInventoryDeath(parent);
|
||||
}
|
||||
|
||||
public ClonedItem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Scripts/Mobiles/Event/BaneDragon.cs
Normal file
165
Scripts/Mobiles/Event/BaneDragon.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class BaneDragon : BaseMount
|
||||
{
|
||||
public static readonly int MaxPower = 10;
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int PowerLevel { get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int PowerDecay
|
||||
{
|
||||
get { return _PowerDecay; }
|
||||
set
|
||||
{
|
||||
_PowerDecay = value;
|
||||
|
||||
if (_PowerDecay >= 10)
|
||||
{
|
||||
_PowerDecay = 0;
|
||||
PowerLevel = Math.Max(1, PowerLevel - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime _NextSpecial;
|
||||
private int _PowerDecay;
|
||||
|
||||
[Constructable]
|
||||
public BaneDragon()
|
||||
: base("Bane Dragon", 0x31A, 0x3EBD, AIType.AI_Mage, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
BaseSoundID = 0x16A;
|
||||
Hue = 1175;
|
||||
|
||||
SetStr(500, 555);
|
||||
SetDex(85, 125);
|
||||
SetInt(100, 165);
|
||||
|
||||
SetHits(550, 650);
|
||||
|
||||
SetDamage(20, 26);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 50);
|
||||
SetDamageType(ResistanceType.Cold, 25);
|
||||
SetDamageType(ResistanceType.Poison, 25);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 60, 70);
|
||||
SetResistance(ResistanceType.Fire, 40, 50);
|
||||
SetResistance(ResistanceType.Cold, 30, 45);
|
||||
SetResistance(ResistanceType.Poison, 50, 60);
|
||||
SetResistance(ResistanceType.Energy, 20, 40);
|
||||
|
||||
SetSkill(SkillName.Anatomy, 10.0);
|
||||
SetSkill(SkillName.MagicResist, 85.0);
|
||||
SetSkill(SkillName.Tactics, 110.0);
|
||||
SetSkill(SkillName.Wrestling, 90.0);
|
||||
SetSkill(SkillName.Magery, 45.0);
|
||||
SetSkill(SkillName.EvalInt, 35.0);
|
||||
SetSkill(SkillName.Meditation, 35.0);
|
||||
|
||||
Fame = 18000;
|
||||
Karma = -18000;
|
||||
|
||||
Tamable = true;
|
||||
ControlSlots = 3;
|
||||
MinTameSkill = 107.1;
|
||||
|
||||
PowerLevel = 10;
|
||||
_NextSpecial = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public override Poison HitPoison { get { return Poison.Lethal; } }
|
||||
public override bool AlwaysMurderer { get { return true; } }
|
||||
public override FoodType FavoriteFood { get { return FoodType.BlackrockStew; } }
|
||||
|
||||
public override bool CheckFeed(Mobile from, Item dropped)
|
||||
{
|
||||
if (dropped is BowlOfBlackrockStew)
|
||||
{
|
||||
if (PowerLevel >= MaxPower)
|
||||
{
|
||||
from.SendLocalizedMessage(1115755); // The creature looks at you strangely and shakes its head no.
|
||||
}
|
||||
else
|
||||
{
|
||||
PowerLevel++;
|
||||
|
||||
if (PowerLevel >= MaxPower)
|
||||
{
|
||||
from.SendLocalizedMessage(1115753); // Your bane dragon is returned to maximum power by this stew.
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1115754); // Your bane dragon seems a bit peckish today and is not at full power.
|
||||
}
|
||||
|
||||
return base.CheckFeed(from, dropped);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnHarmfulSpell(Mobile from)
|
||||
{
|
||||
if (_NextSpecial < DateTime.UtcNow)
|
||||
{
|
||||
DoSpecial(from);
|
||||
|
||||
_NextSpecial = DateTime.UtcNow + TimeSpan.FromSeconds((double)Utility.RandomMinMax(15, 30) * (double)(11.0 - PowerLevel));
|
||||
}
|
||||
}
|
||||
|
||||
public void DoSpecial(Mobile from)
|
||||
{
|
||||
if (Controlled)
|
||||
{
|
||||
PowerDecay++;
|
||||
}
|
||||
|
||||
MovingParticles(from, 0x36D4, 7, 0, false, true, 1163, 0, 9502, 4019, 0x160, 0);
|
||||
PlaySound(0x15E);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(1), m =>
|
||||
{
|
||||
AOS.Damage(m, this, Utility.RandomMinMax(8 * PowerLevel, 10 * PowerLevel), 0, 50, 0, 50, 0);
|
||||
m.ApplyPoison(this, GetHitPoison());
|
||||
}, from);
|
||||
}
|
||||
|
||||
public BaneDragon(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)1); // version
|
||||
writer.Write(PowerLevel);
|
||||
writer.Write(PowerDecay);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
PowerLevel = reader.ReadInt();
|
||||
PowerDecay = reader.ReadInt();
|
||||
break;
|
||||
case 0: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
164
Scripts/Mobiles/Event/PumpkinHead.cs
Normal file
164
Scripts/Mobiles/Event/PumpkinHead.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Items.Holiday;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a killer pumpkin corpse")]
|
||||
public class PumpkinHead : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public PumpkinHead()
|
||||
: base(Utility.RandomBool() ? AIType.AI_Melee : AIType.AI_Mage, FightMode.Closest, 10, 1, 0.05, 0.1)
|
||||
{
|
||||
Name = "a killer pumpkin";
|
||||
Body = 1246 + Utility.Random(2);
|
||||
|
||||
BaseSoundID = 268;
|
||||
|
||||
SetStr(350);
|
||||
SetDex(125);
|
||||
SetInt(250);
|
||||
|
||||
SetHits(500);
|
||||
SetMana(1000);
|
||||
|
||||
SetDamage(10, 15);
|
||||
|
||||
SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
SetResistance(ResistanceType.Physical, 55);
|
||||
SetResistance(ResistanceType.Fire, 50);
|
||||
SetResistance(ResistanceType.Cold, 50);
|
||||
SetResistance(ResistanceType.Poison, 65);
|
||||
SetResistance(ResistanceType.Energy, 80);
|
||||
|
||||
SetSkill(SkillName.DetectHidden, 100.0);
|
||||
SetSkill(SkillName.Meditation, 120.0);
|
||||
SetSkill(SkillName.Necromancy, 100.0);
|
||||
SetSkill(SkillName.SpiritSpeak, 120.0);
|
||||
SetSkill(SkillName.Magery, 160.0);
|
||||
SetSkill(SkillName.EvalInt, 100.0);
|
||||
SetSkill(SkillName.MagicResist, 100.0);
|
||||
SetSkill(SkillName.Tactics, 100.0);
|
||||
SetSkill(SkillName.Wrestling, 80.0);
|
||||
|
||||
Fame = 5000;
|
||||
Karma = -5000;
|
||||
|
||||
VirtualArmor = 49;
|
||||
}
|
||||
|
||||
public PumpkinHead(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool AutoDispel { get { return true; } }
|
||||
public override bool BardImmune { get { return true; } }
|
||||
public override bool Unprovokable { get { return true; } }
|
||||
public override bool AreaPeaceImmune { get { return true; } }
|
||||
|
||||
public override void GenerateLoot()
|
||||
{
|
||||
if (Utility.RandomDouble() < .05)
|
||||
{
|
||||
if (Core.TOL)
|
||||
{
|
||||
switch (Utility.Random(5))
|
||||
{
|
||||
case 0:
|
||||
PackItem(new ObsidianSkull());
|
||||
break;
|
||||
case 1:
|
||||
PackItem(new CrystalSkull());
|
||||
break;
|
||||
case 2:
|
||||
PackItem(new JadeSkull());
|
||||
break;
|
||||
case 3:
|
||||
PackItem(new CarvablePumpkinTall());
|
||||
break;
|
||||
case 4:
|
||||
PackItem(new CarvableGordPumpkinTall());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (Utility.Random(5))
|
||||
{
|
||||
case 0:
|
||||
PackItem(new PaintedEvilClownMask());
|
||||
break;
|
||||
case 1:
|
||||
PackItem(new PaintedDaemonMask());
|
||||
break;
|
||||
case 2:
|
||||
PackItem(new PaintedPlagueMask());
|
||||
break;
|
||||
case 3:
|
||||
PackItem(new PaintedEvilJesterMask());
|
||||
break;
|
||||
case 4:
|
||||
PackItem(new PaintedPorcelainMask());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PackItem(new WrappedCandy());
|
||||
AddLoot(LootPack.UltraRich, 2);
|
||||
}
|
||||
|
||||
public virtual void Lifted_Callback(Mobile from)
|
||||
{
|
||||
if (from != null && !from.Deleted && from is PlayerMobile)
|
||||
{
|
||||
Combatant = from;
|
||||
|
||||
Warmode = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override Item NewHarmfulItem()
|
||||
{
|
||||
Item bad = new AcidSlime(TimeSpan.FromSeconds(10), 25, 30);
|
||||
|
||||
bad.Name = "gooey nasty pumpkin hummus";
|
||||
|
||||
bad.Hue = 144;
|
||||
|
||||
return bad;
|
||||
}
|
||||
|
||||
public override void OnDamage(int amount, Mobile from, bool willKill)
|
||||
{
|
||||
if (Utility.RandomBool())
|
||||
{
|
||||
if (from != null && from.Map != null && Map != Map.Internal && Map == from.Map && from.InRange(this, 12))
|
||||
{
|
||||
SpillAcid((willKill) ? this : from, (willKill) ? 3 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnDamage(amount, from, willKill);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Scripts/Mobiles/Event/Wanderer.cs
Normal file
68
Scripts/Mobiles/Event/Wanderer.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Wanderer : Mobile
|
||||
{
|
||||
private readonly Timer m_Timer;
|
||||
[Constructable]
|
||||
public Wanderer()
|
||||
{
|
||||
this.Name = "Me";
|
||||
this.Body = 0x1;
|
||||
this.AccessLevel = AccessLevel.Counselor;
|
||||
|
||||
this.m_Timer = new InternalTimer(this);
|
||||
this.m_Timer.Start();
|
||||
}
|
||||
|
||||
public Wanderer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
this.m_Timer = new InternalTimer(this);
|
||||
this.m_Timer.Start();
|
||||
}
|
||||
|
||||
public override void OnDelete()
|
||||
{
|
||||
this.m_Timer.Stop();
|
||||
|
||||
base.OnDelete();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Wanderer m_Owner;
|
||||
private int m_Count = 0;
|
||||
public InternalTimer(Wanderer owner)
|
||||
: base(TimeSpan.FromSeconds(0.1), TimeSpan.FromSeconds(0.1))
|
||||
{
|
||||
this.m_Owner = owner;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if ((this.m_Count++ & 0x3) == 0)
|
||||
{
|
||||
this.m_Owner.Direction = (Direction)(Utility.Random(8) | 0x80);
|
||||
}
|
||||
|
||||
this.m_Owner.Move(this.m_Owner.Direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Scripts/Mobiles/Factions/BaseWarHorse.cs
Normal file
70
Scripts/Mobiles/Factions/BaseWarHorse.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a war horse corpse")]
|
||||
public abstract class BaseWarHorse : BaseMount
|
||||
{
|
||||
public BaseWarHorse(int bodyID, int itemID, AIType aiType, FightMode fightMode, int rangePerception, int rangeFight, double activeSpeed, double passiveSpeed)
|
||||
: base("a war horse", bodyID, itemID, aiType, fightMode, rangePerception, rangeFight, activeSpeed, passiveSpeed)
|
||||
{
|
||||
this.BaseSoundID = 0xA8;
|
||||
|
||||
this.InitStats(Utility.Random(300, 100), 125, 60);
|
||||
|
||||
this.SetStr(400);
|
||||
this.SetDex(125);
|
||||
this.SetInt(51, 55);
|
||||
|
||||
this.SetHits(240);
|
||||
this.SetMana(0);
|
||||
|
||||
this.SetDamage(5, 8);
|
||||
|
||||
this.SetDamageType(ResistanceType.Physical, 100);
|
||||
|
||||
this.SetResistance(ResistanceType.Physical, 40, 50);
|
||||
this.SetResistance(ResistanceType.Fire, 30, 40);
|
||||
this.SetResistance(ResistanceType.Cold, 30, 40);
|
||||
this.SetResistance(ResistanceType.Poison, 30, 40);
|
||||
this.SetResistance(ResistanceType.Energy, 30, 40);
|
||||
|
||||
this.SetSkill(SkillName.MagicResist, 25.1, 30.0);
|
||||
this.SetSkill(SkillName.Tactics, 29.3, 44.0);
|
||||
this.SetSkill(SkillName.Wrestling, 29.3, 44.0);
|
||||
|
||||
this.Fame = 300;
|
||||
this.Karma = 300;
|
||||
|
||||
this.Tamable = true;
|
||||
this.ControlSlots = 1;
|
||||
this.MinTameSkill = 29.1;
|
||||
}
|
||||
|
||||
public BaseWarHorse(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override FoodType FavoriteFood
|
||||
{
|
||||
get
|
||||
{
|
||||
return FoodType.FruitsAndVegies | FoodType.GrainsAndHay;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/Mobiles/Factions/CoMWarHorse.cs
Normal file
32
Scripts/Mobiles/Factions/CoMWarHorse.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class CoMWarHorse : BaseWarHorse
|
||||
{
|
||||
[Constructable]
|
||||
public CoMWarHorse()
|
||||
: base(0x77, 0x3EB1, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
}
|
||||
|
||||
public CoMWarHorse(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/Mobiles/Factions/MinaxWarHorse.cs
Normal file
32
Scripts/Mobiles/Factions/MinaxWarHorse.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class MinaxWarHorse : BaseWarHorse
|
||||
{
|
||||
[Constructable]
|
||||
public MinaxWarHorse()
|
||||
: base(0x78, 0x3EAF, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
}
|
||||
|
||||
public MinaxWarHorse(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/Mobiles/Factions/SLWarHorse.cs
Normal file
32
Scripts/Mobiles/Factions/SLWarHorse.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class SLWarHorse : BaseWarHorse
|
||||
{
|
||||
[Constructable]
|
||||
public SLWarHorse()
|
||||
: base(0x79, 0x3EB0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
}
|
||||
|
||||
public SLWarHorse(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
32
Scripts/Mobiles/Factions/TBWarHorse.cs
Normal file
32
Scripts/Mobiles/Factions/TBWarHorse.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class TBWarHorse : BaseWarHorse
|
||||
{
|
||||
[Constructable]
|
||||
public TBWarHorse()
|
||||
: base(0x76, 0x3EB2, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
}
|
||||
|
||||
public TBWarHorse(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Scripts/Mobiles/MobileInterfaces.cs
Normal file
37
Scripts/Mobiles/MobileInterfaces.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public interface IFreezable
|
||||
{
|
||||
void OnRequestedAnimation(Mobile from);
|
||||
}
|
||||
|
||||
public interface IRepairableMobile : IEntity
|
||||
{
|
||||
Type RepairResource { get; }
|
||||
int Hits { get; set; }
|
||||
int HitsMax { get; }
|
||||
}
|
||||
|
||||
public interface IElementalCreature
|
||||
{
|
||||
ElementType ElementType { get; }
|
||||
}
|
||||
|
||||
public interface IAuraCreature
|
||||
{
|
||||
void AuraEffect(Mobile victim);
|
||||
}
|
||||
|
||||
public enum ElementType
|
||||
{
|
||||
Physical,
|
||||
Fire,
|
||||
Cold,
|
||||
Poison,
|
||||
Energy,
|
||||
Chaos,
|
||||
Direct
|
||||
}
|
||||
}
|
||||
80
Scripts/Mobiles/NPCs/Abbein.cs
Normal file
80
Scripts/Mobiles/NPCs/Abbein.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Abbein : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Abbein()
|
||||
: base("the wise")
|
||||
{
|
||||
this.Name = "Elder Abbein";
|
||||
}
|
||||
|
||||
public Abbein(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x824D;
|
||||
this.HairItemID = 0x2FD1;
|
||||
this.HairHue = 0x321;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots(0x74B));
|
||||
this.AddItem(new FemaleElvenRobe(0x8A8));
|
||||
this.AddItem(new RoyalCirclet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
571
Scripts/Mobiles/NPCs/Acob.cs
Normal file
571
Scripts/Mobiles/NPCs/Acob.cs
Normal file
@@ -0,0 +1,571 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class OverpopulationQuest : BaseQuest
|
||||
{
|
||||
public OverpopulationQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new SlayObjective(typeof(Hind), "hinds", 10));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(SmallTrinketBag), 1072268));
|
||||
}
|
||||
|
||||
/* Overpopulation */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072252;
|
||||
}
|
||||
}
|
||||
/* I just can't bear it any longer. Sure, it's my job to thin the deer out so
|
||||
they don't overeat the area and starve themselves come winter time. Sure, I
|
||||
know we killed off the predators that would do this naturally so now we have
|
||||
to make up for it. But they're so graceful and innocent. I just can't do it.
|
||||
Will you? */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072267;
|
||||
}
|
||||
}
|
||||
/* Well, okay. But if you decide you are up for it after all, c'mon back and see me. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072270;
|
||||
}
|
||||
}
|
||||
/* You're not quite done yet. Get back to work! */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072271;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class WildBoarCullQuest : BaseQuest
|
||||
{
|
||||
public WildBoarCullQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new SlayObjective(typeof(Boar), "boars", 10));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(SmallTrinketBag), 1072268));
|
||||
}
|
||||
|
||||
/* Wild Boar Cull */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072245;
|
||||
}
|
||||
}
|
||||
/* A pity really. With the balance of nature awry, we have no choice but to accept
|
||||
the responsibility of making it all right. It's all a part of the circle of life,
|
||||
after all. So, yes, the boars are running rampant. There are far too many in the
|
||||
region. Will you shoulder your obligations as a higher life form? */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072260;
|
||||
}
|
||||
}
|
||||
/* Well, okay. But if you decide you are up for it after all, c'mon back and see me. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072270;
|
||||
}
|
||||
}
|
||||
/* You're not quite done yet. Get back to work! */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072271;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class NewLeadershipQuest : BaseQuest
|
||||
{
|
||||
public NewLeadershipQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new SlayObjective(typeof(SerpentsFangHighExecutioner), "serpent's fang high executioner", 1, "TheCitadel"));
|
||||
this.AddObjective(new SlayObjective(typeof(TigersClawThief), "tiger's claw thief", 1, "TheCitadel"));
|
||||
this.AddObjective(new SlayObjective(typeof(DragonsFlameGrandMage), "dragon's flame mage", 1, "TheCitadel"));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(RewardBox), 1072584));
|
||||
}
|
||||
|
||||
/* New Leadership */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072905;
|
||||
}
|
||||
}
|
||||
/* I have a task for you ... adventurer. Will you risk all to win great renown? The
|
||||
Black Order is organized into three sects, each with their own speciality. The Dragon's
|
||||
Flame serves the will of the Grand Mage, the Tiger's Claw answers to the Master Thief,
|
||||
and the Serpent's Fang kills at the direction of the High Executioner. Slay all three
|
||||
and you will strike the order a devastating blow! */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072963;
|
||||
}
|
||||
}
|
||||
/* I do not fault your decision. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072973;
|
||||
}
|
||||
}
|
||||
/* Once you gain entrance into The Citadel, you will need to move cautiously to find
|
||||
the sect leaders. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072974;
|
||||
}
|
||||
}
|
||||
public override bool CanOffer()
|
||||
{
|
||||
return MondainsLegacy.Citadel;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExAssassinsQuest : BaseQuest
|
||||
{
|
||||
public ExAssassinsQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new InternalObjective());
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* Ex-Assassins */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072917;
|
||||
}
|
||||
}
|
||||
/* The Serpent's Fang sect members have gone too far! Express to them my displeasure by slaying
|
||||
ten of them. But remember, I do not condone war on women, so I will only accept the deaths of
|
||||
men, human and elf. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072969;
|
||||
}
|
||||
}
|
||||
/* As you wish. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072979;
|
||||
}
|
||||
}
|
||||
/* The Black Order's fortress home is well hidden. Legend has it that a humble fishing village
|
||||
disguises the magical portal. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072980;
|
||||
}
|
||||
}
|
||||
public override bool CanOffer()
|
||||
{
|
||||
return MondainsLegacy.Citadel;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private class InternalObjective : SlayObjective
|
||||
{
|
||||
public InternalObjective()
|
||||
: base(typeof(SerpentsFangAssassin), "male serpent's fang assassins", 10, "TheCitadel")
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsObjective(Mobile mob)
|
||||
{
|
||||
if (mob.Female)
|
||||
return false;
|
||||
|
||||
return base.IsObjective(mob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ExtinguishingTheFlameQuest : BaseQuest
|
||||
{
|
||||
public ExtinguishingTheFlameQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new InternalObjective());
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* Extinguishing the Flame */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072911;
|
||||
}
|
||||
}
|
||||
/* The Dragon's Flame sect members have gone too far! Express to them my displeasure by slaying ten
|
||||
of them. But remember, I do not condone war on women, so I will only accept the deaths of men,
|
||||
human or elf. Either race will do, I care not for the shape of their ears. Yes, this action will
|
||||
properly make clear my disapproval and has a pleasing harmony. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072966;
|
||||
}
|
||||
}
|
||||
/* As you wish. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072979;
|
||||
}
|
||||
}
|
||||
/* The Black Order's fortress home is well hidden. Legend has it that a humble fishing village
|
||||
disguises the magical portal. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072980;
|
||||
}
|
||||
}
|
||||
public override bool CanOffer()
|
||||
{
|
||||
return MondainsLegacy.Citadel;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private class InternalObjective : SlayObjective
|
||||
{
|
||||
public InternalObjective()
|
||||
: base(typeof(DragonsFlameMage), "male dragon's flame mages", 10, "TheCitadel")
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsObjective(Mobile mob)
|
||||
{
|
||||
if (mob.Female)
|
||||
return false;
|
||||
|
||||
return base.IsObjective(mob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DeathToTheNinjaQuest : BaseQuest
|
||||
{
|
||||
public DeathToTheNinjaQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new SlayObjective(typeof(EliteNinja), "elite ninjas", 10, "TheCitadel"));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* Death to the Ninja! */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072913;
|
||||
}
|
||||
}
|
||||
/* I wish to make a statement of censure against the elite ninjas of the Black Order. Deliver, in
|
||||
the strongest manner, my disdain. But do not make war on women, even those that take arms against
|
||||
you. It is not ... fitting. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072967;
|
||||
}
|
||||
}
|
||||
/* As you wish. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072979;
|
||||
}
|
||||
}
|
||||
/* The Black Order's fortress home is well hidden. Legend has it that a humble fishing village
|
||||
disguises the magical portal. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072980;
|
||||
}
|
||||
}
|
||||
public override bool CanOffer()
|
||||
{
|
||||
return MondainsLegacy.Citadel;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class CrimeAndPunishmentQuest : BaseQuest
|
||||
{
|
||||
public CrimeAndPunishmentQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new InternalObjective());
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* Crime and Punishment */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072914;
|
||||
}
|
||||
}
|
||||
/* The Tiger's Claw sect members have gone too far! Express to them my displeasure by slaying
|
||||
ten of them. But remember, I do not condone war on women, so I will only accept the deaths of
|
||||
men, human and elf. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072968;
|
||||
}
|
||||
}
|
||||
/* As you wish. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072979;
|
||||
}
|
||||
}
|
||||
/* The Black Order's fortress home is well hidden. Legend has it that a humble fishing village
|
||||
disguises the magical portal. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072980;
|
||||
}
|
||||
}
|
||||
public override bool CanOffer()
|
||||
{
|
||||
return MondainsLegacy.Citadel;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
|
||||
private class InternalObjective : SlayObjective
|
||||
{
|
||||
public InternalObjective()
|
||||
: base(typeof(TigersClawThief), "male tiger's claw thieves", 10, "TheCitadel")
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsObjective(Mobile mob)
|
||||
{
|
||||
if (mob.Female)
|
||||
return false;
|
||||
|
||||
return base.IsObjective(mob);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Acob : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Acob()
|
||||
: base("Elder Acob", "the wise")
|
||||
{
|
||||
this.SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
this.SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Acob(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(OverpopulationQuest),
|
||||
typeof(WildBoarCullQuest),
|
||||
typeof(NewLeadershipQuest),
|
||||
typeof(ExAssassinsQuest),
|
||||
typeof(ExtinguishingTheFlameQuest),
|
||||
typeof(DeathToTheNinjaQuest),
|
||||
typeof(CrimeAndPunishmentQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8389;
|
||||
this.HairItemID = 0x2FCF;
|
||||
this.HairHue = 0x389;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new ElvenBoots(0x73D));
|
||||
this.AddItem(new HidePants());
|
||||
this.AddItem(new ElvenShirt(0x71));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
73
Scripts/Mobiles/NPCs/Actor.cs
Normal file
73
Scripts/Mobiles/NPCs/Actor.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Actor : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public Actor()
|
||||
: base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
this.InitStats(31, 41, 51);
|
||||
|
||||
this.SpeechHue = Utility.RandomDyedHue();
|
||||
|
||||
this.Hue = Utility.RandomSkinHue();
|
||||
|
||||
if (this.Female = Utility.RandomBool())
|
||||
{
|
||||
this.Body = 0x191;
|
||||
this.Name = NameList.RandomName("female");
|
||||
this.AddItem(new FancyDress(Utility.RandomDyedHue()));
|
||||
this.Title = "the actress";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Body = 0x190;
|
||||
this.Name = NameList.RandomName("male");
|
||||
this.AddItem(new LongPants(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new FancyShirt(Utility.RandomDyedHue()));
|
||||
this.Title = "the actor";
|
||||
}
|
||||
|
||||
this.AddItem(new Boots(Utility.RandomNeutralHue()));
|
||||
|
||||
Utility.AssignRandomHair(this);
|
||||
|
||||
Container pack = new Backpack();
|
||||
|
||||
pack.DropItem(new Gold(250, 300));
|
||||
|
||||
pack.Movable = false;
|
||||
|
||||
this.AddItem(pack);
|
||||
}
|
||||
|
||||
public Actor(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool ClickTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
204
Scripts/Mobiles/NPCs/Aelorn.cs
Normal file
204
Scripts/Mobiles/NPCs/Aelorn.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class CleansingOldHavenQuest : BaseQuest
|
||||
{
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleansing Old Haven */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077719;
|
||||
}
|
||||
}
|
||||
|
||||
/* Head East out of town to Old Haven. Consecrate your weapon, cast Divine Fury, and battle monsters there until
|
||||
you have raised your Chivalry skill to 50.<br><center>------</center><br>Hail, friend. The life of a Paladin is
|
||||
a life of much sacrifice, humility, bravery, and righteousness. If you wish to pursue such a life, I have an
|
||||
assignment for you. Adventure east to Old Haven, consecrate your weapon, and lay to rest the undead that inhabit
|
||||
there.<br><br>Each ability a Paladin wishes to invoke will require a certain amount of "tithing points" to use.
|
||||
A Paladin can earn these tithing points by donating gold at a shrine or holy place. You may tithe at this shrine.
|
||||
<br><br>Return to me once you feel that you are worthy of the rank of Apprentice Paladin. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077722;
|
||||
}
|
||||
}
|
||||
|
||||
/* Farewell to you my friend. Return to me if you wish to live the life of a Paladin. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077723;
|
||||
}
|
||||
}
|
||||
|
||||
/* There are still more undead to lay to rest. You still have more to learn. Return to me once you have done so. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077724;
|
||||
}
|
||||
}
|
||||
|
||||
/* Well done, friend. While I know you understand Chivalry is its own reward, I would like to reward you with
|
||||
something that will protect you in battle. It was passed down to me when I was a lad. Now, I am passing it on you.
|
||||
It is called the Bulwark Leggings. Thank you for your service. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077726;
|
||||
}
|
||||
}
|
||||
|
||||
public CleansingOldHavenQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ApprenticeObjective(SkillName.Chivalry, 50, "Old Haven Training", 1077720, 1077721));
|
||||
|
||||
// 1077720 Your Chivalry potential is greatly enhanced while questing in this area.
|
||||
// 1077721 You are not in the quest area for Apprentice Paladin. Your Chivalry potential is not enhanced here.
|
||||
|
||||
this.AddReward(new BaseReward(typeof(BulwarkLeggings), 1077727));
|
||||
}
|
||||
|
||||
public override bool CanOffer()
|
||||
{
|
||||
#region Scroll of Alacrity
|
||||
PlayerMobile pm = this.Owner as PlayerMobile;
|
||||
if (pm.AcceleratedStart > DateTime.UtcNow)
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
return this.Owner.Skills.Chivalry.Base < 50;
|
||||
}
|
||||
|
||||
public override void OnCompleted()
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077725, null, 0x23); // You have achieved the rank of Apprentice Paladin. Return to Aelorn in New Haven to report your progress.
|
||||
this.Owner.PlaySound(this.CompleteSound);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Aelorn : MondainQuester
|
||||
{
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(CleansingOldHavenQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsActiveVendor
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
this.SBInfos.Add(new SBKeeperOfChivalry());
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public Aelorn()
|
||||
: base("Aelorn", "The Chivalry Instructor")
|
||||
{
|
||||
this.SetSkill(SkillName.Anatomy, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.MagicResist, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Tactics, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Swords, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Meditation, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Focus, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Chivalry, 120.0, 120.0);
|
||||
}
|
||||
|
||||
public Aelorn(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1078133); // Hail, friend. Want to live the life of a paladin?
|
||||
}
|
||||
|
||||
public override void OnOfferFailed()
|
||||
{
|
||||
this.Say(1077772); // I cannot teach you, for you know all I can teach!
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new VikingSword());
|
||||
this.AddItem(new PlateChest());
|
||||
this.AddItem(new PlateLegs());
|
||||
this.AddItem(new PlateGloves());
|
||||
this.AddItem(new PlateArms());
|
||||
this.AddItem(new PlateGorget());
|
||||
this.AddItem(new OrderShield());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Scripts/Mobiles/NPCs/Aeluva.cs
Normal file
62
Scripts/Mobiles/NPCs/Aeluva.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class Aeluva : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Aeluva()
|
||||
: base("Aeluva", "the arcanist")
|
||||
{
|
||||
this.SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
this.SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Aeluva(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(PatienceQuest) };
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8835;
|
||||
this.HairItemID = 0x2FD0;
|
||||
this.HairHue = 0x387;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots());
|
||||
this.AddItem(new ElvenShirt());
|
||||
this.AddItem(new Skirt());
|
||||
this.AddItem(new Circlet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Scripts/Mobiles/NPCs/Aernya.cs
Normal file
62
Scripts/Mobiles/NPCs/Aernya.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class Aernya : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Aernya()
|
||||
: base("Aernya", "the mistress of admissions")
|
||||
{
|
||||
this.SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Aernya(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[] { typeof(MistakenIdentityQuest) };
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x8404;
|
||||
this.HairItemID = 0x2047;
|
||||
this.HairHue = 0x465;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Sandals(0x743));
|
||||
this.AddItem(new FancyShirt(0x3B3));
|
||||
this.AddItem(new Cloak(0x3));
|
||||
this.AddItem(new Skirt());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
138
Scripts/Mobiles/NPCs/Agralem.cs
Normal file
138
Scripts/Mobiles/NPCs/Agralem.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class IntoTheVoidQuest : BaseQuest
|
||||
{
|
||||
public IntoTheVoidQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new SlayObjective(typeof(BaseVoidCreature), "Void Daemons", 10));
|
||||
|
||||
AddReward(new BaseReward(typeof(AbyssReaver), 1112694)); // Abyss Reaver
|
||||
}
|
||||
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1112687;
|
||||
}
|
||||
}
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1112690;
|
||||
}
|
||||
}
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1112691;
|
||||
}
|
||||
}
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1112692;
|
||||
}
|
||||
}
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1112693;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Agralem : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Agralem()
|
||||
: base("Agralem", "the Bladeweaver")
|
||||
{
|
||||
SetSkill(SkillName.Anatomy, 65.0, 90.0);
|
||||
SetSkill(SkillName.MagicResist, 65.0, 90.0);
|
||||
SetSkill(SkillName.Tactics, 65.0, 90.0);
|
||||
SetSkill(SkillName.Throwing, 65.0, 90.0);
|
||||
}
|
||||
|
||||
public Agralem(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
Say(1112688); // Daemons from the void! They must be vanquished!
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(IntoTheVoidQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
InitStats(100, 100, 25);
|
||||
|
||||
CantWalk = true;
|
||||
Race = Race.Gargoyle;
|
||||
|
||||
Hue = 34536;
|
||||
HairItemID = 0x425D;
|
||||
HairHue = 0x31D;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
AddItem(new Cyclone());
|
||||
AddItem(new GargishLeatherKilt(2305));
|
||||
AddItem(new GargishLeatherChest(2305));
|
||||
AddItem(new GargishLeatherArms(2305));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
339
Scripts/Mobiles/NPCs/Ahie.cs
Normal file
339
Scripts/Mobiles/NPCs/Ahie.cs
Normal file
@@ -0,0 +1,339 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class TheKingOfClothingQuest : BaseQuest
|
||||
{
|
||||
public TheKingOfClothingQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(Kilt), "kilts", 10, 0x1537));
|
||||
|
||||
AddReward(new BaseReward(typeof(TailorsCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* The King of Clothing */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073902;
|
||||
}
|
||||
}
|
||||
/* I have heard noble tales of a fine and proud human garment. An article of clothing
|
||||
fit for both man and god alike. It is called a "kilt" I believe? Could you fetch for
|
||||
me some of these kilts so I that I might revel in their majesty and glory? */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074092;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me kilts. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073948;
|
||||
}
|
||||
}
|
||||
/* I say truly - that is a magnificent garment! You have more than earned a reward. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073974;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class ThePuffyShirtQuest : BaseQuest
|
||||
{
|
||||
public ThePuffyShirtQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(FancyShirt), "fancy shirts", 10, 0x1EFD));
|
||||
|
||||
AddReward(new BaseReward(typeof(TailorsCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* The Puffy Shirt */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073903;
|
||||
}
|
||||
}
|
||||
/* We elves believe that beauty is expressed in all things, including the garments we
|
||||
wear. I wish to understand more about human aesthetics, so please kind traveler - could
|
||||
you bring to me magnificent examples of human fancy shirts? For my thanks, I could teach
|
||||
you more about the beauty of elven vestements. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074093;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me fancy shirts. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073949;
|
||||
}
|
||||
}
|
||||
/* I appreciate your service. Now, see what elven hands can create. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073973;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FromTheGaultierCollectionQuest : BaseQuest
|
||||
{
|
||||
public FromTheGaultierCollectionQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(StuddedBustierArms), "studded bustiers", 10, 0x1C0C));
|
||||
|
||||
AddReward(new BaseReward(typeof(TailorsCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* From the Gaultier Collection */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073905;
|
||||
}
|
||||
}
|
||||
/* It is my understanding, the females of humankind actually wear on certain occasions a
|
||||
studded bustier? This is not simply a fanciful tale? Remarkable! It sounds hideously
|
||||
uncomfortable as well as ludicrously impracticle. But perhaps, I simply do not understand
|
||||
the nuances of human clothing. Perhaps, I need to see such a studded bustier for myself? */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074095;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me studded bustiers. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073951;
|
||||
}
|
||||
}
|
||||
/* Truly, it is worse than I feared. Still, I appreciate your efforts on my behalf. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073976;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class HuteCoutureQuest : BaseQuest
|
||||
{
|
||||
public HuteCoutureQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(FlowerGarland), "flower garlands", 10, 0x2306));
|
||||
|
||||
AddReward(new BaseReward(typeof(TailorsCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* H'ute Couture */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073901;
|
||||
}
|
||||
}
|
||||
/* Most human apparel is interesting to elven eyes. But there is one garment - the flower garland -
|
||||
which sounds very elven indeed. Could I see how a human crafts such an object of beauty? In exchange,
|
||||
I could share with you the wonders of elven garments. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074091;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me flower garlands. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073947;
|
||||
}
|
||||
}
|
||||
/* I appreciate your service. Now, see what elven hands can create. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073973;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Ahie : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Ahie()
|
||||
: base("Ahie", "the cloth weaver")
|
||||
{
|
||||
SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Ahie(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(TheKingOfClothingQuest),
|
||||
typeof(ThePuffyShirtQuest),
|
||||
typeof(FromTheGaultierCollectionQuest),
|
||||
typeof(HuteCoutureQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
InitStats(100, 100, 25);
|
||||
|
||||
Female = true;
|
||||
Race = Race.Elf;
|
||||
|
||||
Hue = 0x853F;
|
||||
HairItemID = 0x2FCD;
|
||||
HairHue = 0x90;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
AddItem(new ThighBoots(0x901));
|
||||
AddItem(new FancyShirt(0x72B));
|
||||
AddItem(new Cloak(0x1C));
|
||||
AddItem(new Skirt(0x62));
|
||||
AddItem(new Circlet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
94
Scripts/Mobiles/NPCs/AlbertaGiacco.cs
Normal file
94
Scripts/Mobiles/NPCs/AlbertaGiacco.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests.Collector
|
||||
{
|
||||
public class AlbertaGiacco : BaseQuester
|
||||
{
|
||||
[Constructable]
|
||||
public AlbertaGiacco()
|
||||
: base("the respected painter")
|
||||
{
|
||||
}
|
||||
|
||||
public AlbertaGiacco(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Hue = 0x83F2;
|
||||
|
||||
this.Female = true;
|
||||
this.Body = 0x191;
|
||||
this.Name = "Alberta Giacco";
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new FancyShirt());
|
||||
this.AddItem(new Skirt(0x59B));
|
||||
this.AddItem(new Boots());
|
||||
this.AddItem(new FeatheredHat(0x59B));
|
||||
this.AddItem(new FullApron(0x59B));
|
||||
|
||||
this.HairItemID = 0x203D; // Pony Tail
|
||||
this.HairHue = 0x457;
|
||||
}
|
||||
|
||||
public override bool CanTalkTo(PlayerMobile to)
|
||||
{
|
||||
QuestSystem qs = to.Quest as CollectorQuest;
|
||||
|
||||
if (qs == null)
|
||||
return false;
|
||||
|
||||
return (qs.IsObjectiveInProgress(typeof(FindAlbertaObjective)) ||
|
||||
qs.IsObjectiveInProgress(typeof(SitOnTheStoolObjective)) ||
|
||||
qs.IsObjectiveInProgress(typeof(ReturnPaintingObjective)));
|
||||
}
|
||||
|
||||
public override void OnTalk(PlayerMobile player, bool contextMenu)
|
||||
{
|
||||
QuestSystem qs = player.Quest;
|
||||
|
||||
if (qs is CollectorQuest)
|
||||
{
|
||||
this.Direction = this.GetDirectionTo(player);
|
||||
|
||||
QuestObjective obj = qs.FindObjective(typeof(FindAlbertaObjective));
|
||||
|
||||
if (obj != null && !obj.Completed)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
else if (qs.IsObjectiveInProgress(typeof(SitOnTheStoolObjective)))
|
||||
{
|
||||
qs.AddConversation(new AlbertaStoolConversation());
|
||||
}
|
||||
else if (qs.IsObjectiveInProgress(typeof(ReturnPaintingObjective)))
|
||||
{
|
||||
qs.AddConversation(new AlbertaAfterPaintingConversation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Scripts/Mobiles/NPCs/Alchemist.cs
Normal file
91
Scripts/Mobiles/NPCs/Alchemist.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.BulkOrders;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Alchemist : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Alchemist()
|
||||
: base("the alchemist")
|
||||
{
|
||||
this.SetSkill(SkillName.Alchemy, 85.0, 100.0);
|
||||
this.SetSkill(SkillName.TasteID, 65.0, 88.0);
|
||||
}
|
||||
|
||||
#region Bulk Orders
|
||||
public override BODType BODType { get { return BODType.Alchemy; } }
|
||||
|
||||
public override bool IsValidBulkOrder(Item item)
|
||||
{
|
||||
return (item is SmallAlchemyBOD || item is LargeAlchemyBOD);
|
||||
}
|
||||
|
||||
public override bool SupportsBulkOrders(Mobile from)
|
||||
{
|
||||
return BulkOrderSystem.NewSystemEnabled && from is PlayerMobile && from.Skills[SkillName.Alchemy].Base > 0;
|
||||
}
|
||||
|
||||
public override void OnSuccessfulBulkOrderReceive(Mobile from)
|
||||
{
|
||||
if (from is PlayerMobile)
|
||||
((PlayerMobile)from).NextAlchemyBulkOrder = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public Alchemist(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override NpcGuild NpcGuild
|
||||
{
|
||||
get
|
||||
{
|
||||
return NpcGuild.MagesGuild;
|
||||
}
|
||||
}
|
||||
public override VendorShoeType ShoeType
|
||||
{
|
||||
get
|
||||
{
|
||||
return Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
this.m_SBInfos.Add(new SBAlchemist(this));
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
this.AddItem(new Server.Items.Robe(Utility.RandomPinkHue()));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
198
Scripts/Mobiles/NPCs/AldenArmstrong.cs
Normal file
198
Scripts/Mobiles/NPCs/AldenArmstrong.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class TheArtOfWarQuest : BaseQuest
|
||||
{
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* The Art of War */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077667;
|
||||
}
|
||||
}
|
||||
|
||||
/* Head East out of town to Old Haven. Battle monsters there until you have raised your Tactics skill
|
||||
to 50.<br><center>------</center><br>Knowing how to hold a weapon is only half of the battle. The other
|
||||
half is knowing how to use it against an opponent. It's one thing to kill a few bunnies now and then
|
||||
for fun, but a true warrior knows that the right moves to use against a lich will pretty much get your
|
||||
arse fried by a dragon.<br><br>I'll help teach you how to fight so that when you do come up against that
|
||||
dragon, maybe you won't have to walk out of there "OooOOooOOOooOO'ing" and looking for a healer.<br><br>
|
||||
There are some undead that need cleaning out in Old Haven towards the east. Why don't you head on over
|
||||
there and practice killing things?<br><br>When you feel like you've got the basics down, come back to me
|
||||
and I'll see if I can scrounge up an item to help you in your adventures later on. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077670;
|
||||
}
|
||||
}
|
||||
|
||||
/* That's too bad. I really thought you had it in you. Well, I'm sure those undead will still be there
|
||||
later, so if you change your mind, feel free to stop on by and I'll help you the best I can. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077671;
|
||||
}
|
||||
}
|
||||
|
||||
/* You're making some progress, that i can tell, but you're not quite good enough to last for very long
|
||||
out there by yourself. Head back to Old Haven, to the east, and kill some more undead. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077672;
|
||||
}
|
||||
}
|
||||
|
||||
/* Hey, good job killing those undead! Hopefully someone will come along and clean up the mess. All that
|
||||
blood and guts tends to stink after a few days, and when the wind blows in from the east, it can raise a
|
||||
mighty stink!<br><br>Since you performed valiantly, please take these arms and use them well. I've seen
|
||||
a few too many harvests to be running around out there myself, so you might as well take it.<br><br>There
|
||||
is a lot left for you to learn, but I think you'll do fine. Remember to keep your elbows in and stick'em
|
||||
where it hurts the most! */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077674;
|
||||
}
|
||||
}
|
||||
|
||||
public TheArtOfWarQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ApprenticeObjective(SkillName.Tactics, 50, "Old Haven Training", 1077668, 1077669));
|
||||
|
||||
// 1077668 You feel like practicing combat here would really help you learn to fight better. Your ability to raise your Tactics skill is enhanced in this area.
|
||||
// 1077669 You feel less able to absorb the lessons of combat. Your Tactics learning potential is no longer enhanced.
|
||||
|
||||
this.AddReward(new BaseReward(typeof(ArmsOfArmstrong), 1077675));
|
||||
}
|
||||
|
||||
public override bool CanOffer()
|
||||
{
|
||||
#region Scroll of Alacrity
|
||||
PlayerMobile pm = this.Owner as PlayerMobile;
|
||||
if (pm.AcceleratedStart > DateTime.UtcNow)
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
return this.Owner.Skills.Tactics.Base < 50;
|
||||
}
|
||||
|
||||
public override void OnCompleted()
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077673, null, 0x23); // You have achieved the rank of Apprentice Warrior. Return to Alden Armstrong in New Haven to claim your reward.
|
||||
this.Owner.PlaySound(this.CompleteSound);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AldenArmstrong : MondainQuester
|
||||
{
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(TheArtOfWarQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public AldenArmstrong()
|
||||
: base("Alden Armstrong", "The Tactics Instructor")
|
||||
{
|
||||
this.SetSkill(SkillName.Anatomy, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Parry, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Healing, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Tactics, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Swords, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Focus, 120.0, 120.0);
|
||||
}
|
||||
|
||||
public AldenArmstrong(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1078136); // There is an art to slaying your enemies swiftly. It's called tactics, and I can teach it to you.
|
||||
}
|
||||
|
||||
public override void OnOfferFailed()
|
||||
{
|
||||
this.Say(1077772); // I cannot teach you, for you know all I can teach!
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Shoes());
|
||||
this.AddItem(new StuddedLegs());
|
||||
this.AddItem(new StuddedGloves());
|
||||
this.AddItem(new StuddedGorget());
|
||||
this.AddItem(new StuddedChest());
|
||||
this.AddItem(new StuddedArms());
|
||||
this.AddItem(new Katana());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
201
Scripts/Mobiles/NPCs/Alefian.cs
Normal file
201
Scripts/Mobiles/NPCs/Alefian.cs
Normal file
@@ -0,0 +1,201 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class DefyingTheArcaneQuest : BaseQuest
|
||||
{
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Defying the Arcane */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077621;
|
||||
}
|
||||
}
|
||||
|
||||
/* Head East out of town and go to Old Haven. Battle spell casting monsters there until you have raised your
|
||||
Resisting Spells skill to 50.<br><center>------</center><br>Hail and well met! To become a true master of
|
||||
the arcane art of Magery, I suggest learning the complementary skill known as Resisting Spells. While the
|
||||
name of this skill may suggest that it helps with resisting all spells, this is not the case. This skill
|
||||
helps you lessen the severity of spells that lower your stats or ones that last for a specific duration of
|
||||
time. It does not lessen damage from spells such as Energy Bolt or Flamestrike.<BR><BR>The Magery spells that
|
||||
can be resisted are Clumsy, Curse, Feeblemind, Mana Drain, Mana Vampire, Paralyze, Paralyze Field, Poison,
|
||||
Poison Field, and Weaken.<BR><BR>The Necromancy spells that can be resisted are Blood Oath, Corpse Skin, Mind
|
||||
Rot, and Pain Spike.<BR><BR>At higher ranks, the Resisting Spells skill also benefits you by adding a bonus to
|
||||
your minimum elemental resists. This bonus is only applied after all other resist modifications - such as from
|
||||
equipment - has been calculated. It's also not cumulative. It compares the number of your minimum resists to
|
||||
the calculated value of your modifications and uses the higher of the two values.<BR><BR>As you can see,
|
||||
Resisting Spells is a difficult skill to understand, and even more difficult to master. This is because in
|
||||
order to improve it, you will have to put yourself in harm's way - as in the path of one of the above spells.
|
||||
<BR><BR>Undead have plagued the town of Old Haven. We need your assistance in cleansing the town of this evil
|
||||
influence. Old Haven is located east of here. Battle the undead spell casters that inhabit there.<BR><BR>Come
|
||||
back to me once you feel that you are worthy of the rank of Apprentice Mage and I will reward you with an
|
||||
arcane prize. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077623;
|
||||
}
|
||||
}
|
||||
|
||||
/* The ability to resist powerful spells is a taxing experience. I understand your resistance in wanting to
|
||||
pursue it. If you wish to reconsider, feel free to return to me for Resisting Spells training. Good journey
|
||||
to you! */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077624;
|
||||
}
|
||||
}
|
||||
|
||||
/* You have not achieved the rank of Apprentice Mage. Come back to me once you feel that you are worthy of the
|
||||
rank of Apprentice Mage and I will reward you with an arcane prize. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077632;
|
||||
}
|
||||
}
|
||||
|
||||
/* You have successfully begun your journey in becoming a true master of Magery. On behalf of the New Haven Mage
|
||||
Council I wish to present you with this bracelet. When worn, the Bracelet of Resilience will enhance your resistances
|
||||
vs. the elements, physical, and poison harm. The Bracelet of Resilience also magically enhances your ability fend
|
||||
off ranged and melee attacks. I hope it serves you well.*/
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077626;
|
||||
}
|
||||
}
|
||||
|
||||
public DefyingTheArcaneQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ApprenticeObjective(SkillName.MagicResist, 50, "Old Haven Training", 1077494, 1077588));
|
||||
|
||||
// 1077494 Your Resisting Spells potential is greatly enhanced while questing in this area.
|
||||
// 1077588 You are not in the quest area for Apprentice Mage. Your Resisting Spells potential is not enhanced here.
|
||||
|
||||
this.AddReward(new BaseReward(typeof(BraceletOfResilience), 1077627));
|
||||
}
|
||||
|
||||
public override bool CanOffer()
|
||||
{
|
||||
#region Scroll of Alacrity
|
||||
PlayerMobile pm = this.Owner as PlayerMobile;
|
||||
if (pm.AcceleratedStart > DateTime.UtcNow)
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
return this.Owner.Skills.MagicResist.Base < 50;
|
||||
}
|
||||
|
||||
public override void OnCompleted()
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077625, null, 0x23); // You have achieved the rank of Apprentice Mage (for Resisting Spells). Return to Alefian in New Haven to receive your arcane prize.
|
||||
this.Owner.PlaySound(this.CompleteSound);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Alefian : MondainQuester
|
||||
{
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(DefyingTheArcaneQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public Alefian()
|
||||
: base("Alefian", "The Resisting Spells Instructor")
|
||||
{
|
||||
this.SetSkill(SkillName.EvalInt, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Inscribe, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Magery, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.MagicResist, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Wrestling, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Meditation, 120.0, 120.0);
|
||||
}
|
||||
|
||||
public Alefian(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1078130); // A mage should learn how to resist spells.
|
||||
}
|
||||
|
||||
public override void OnOfferFailed()
|
||||
{
|
||||
this.Say(1077772); // I cannot teach you, for you know all I can teach!
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Robe());
|
||||
this.AddItem(new Sandals());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Scripts/Mobiles/NPCs/Alejaha.cs
Normal file
127
Scripts/Mobiles/NPCs/Alejaha.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class ItsElementalQuest : BaseQuest
|
||||
{
|
||||
public ItsElementalQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new SlayObjective(typeof(FireElemental), "fire elementals", 4));
|
||||
this.AddObjective(new SlayObjective(typeof(WaterElemental), "water elementals", 4));
|
||||
this.AddObjective(new SlayObjective(typeof(EarthElemental), "earth elementals", 4));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* It's Elemental */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073089;
|
||||
}
|
||||
}
|
||||
/* The universe is all about balance my friend. Tip one end, you must balance the other. That's
|
||||
why I must ask you to kill not just one kind of elemental, but three kinds. Snuff out some Fire,
|
||||
douse a few Water, and crush some Earth elementals and I'll pay you for your trouble. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073579;
|
||||
}
|
||||
}
|
||||
/* I hope you'll reconsider. Until then, farwell. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073580;
|
||||
}
|
||||
}
|
||||
/* Four of each, that's all I ask. Water, earth and fire. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073599;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Alejaha : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Alejaha()
|
||||
: base("Elder Alejaha", "the wise")
|
||||
{
|
||||
this.SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
this.SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Alejaha(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(ItsElementalQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8361;
|
||||
this.HairItemID = 0x2FCD;
|
||||
this.HairHue = 0x852;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Sandals(0x1BB));
|
||||
this.AddItem(new Cloak(0x59));
|
||||
this.AddItem(new Skirt(0x901));
|
||||
this.AddItem(new GemmedCirclet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
92
Scripts/Mobiles/NPCs/AlelleTheAborist.cs
Normal file
92
Scripts/Mobiles/NPCs/AlelleTheAborist.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Alelle : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Alelle()
|
||||
: base("the aborist")
|
||||
{
|
||||
this.Name = "Alelle";
|
||||
}
|
||||
|
||||
public Alelle(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8374;
|
||||
this.HairItemID = 0x2FCC;
|
||||
this.HairHue = 0x238;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots(0x1BB));
|
||||
|
||||
Item item;
|
||||
|
||||
item = new LeafGloves();
|
||||
item.Hue = 0x1BB;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new LeafChest();
|
||||
item.Hue = 0x37;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new LeafLegs();
|
||||
item.Hue = 0x746;
|
||||
this.AddItem(item);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Scripts/Mobiles/NPCs/Alethanian.cs
Normal file
82
Scripts/Mobiles/NPCs/Alethanian.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Alethanian : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Alethanian()
|
||||
: base("the wise")
|
||||
{
|
||||
this.Name = "Elder Alethanian";
|
||||
}
|
||||
|
||||
public Alethanian(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x876C;
|
||||
this.HairItemID = 0x2FC2;
|
||||
this.HairHue = 0x368;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots());
|
||||
this.AddItem(new GemmedCirclet());
|
||||
this.AddItem(new HidePants());
|
||||
this.AddItem(new HideFemaleChest());
|
||||
this.AddItem(new HidePauldrons());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
232
Scripts/Mobiles/NPCs/Aliabeth.cs
Normal file
232
Scripts/Mobiles/NPCs/Aliabeth.cs
Normal file
@@ -0,0 +1,232 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
using Server.Mobiles;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class TheExchangeQuest : BaseQuest
|
||||
{
|
||||
public TheExchangeQuest()
|
||||
: base()
|
||||
|
||||
{
|
||||
this.AddObjective(new ObtainObjective(typeof(WhiteChocolate), "White Chocolates", 5, 0xF11));
|
||||
this.AddObjective(new ObtainObjective(typeof(DarkSapphire), "Dark Sapphire", 1, 0x3192));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(AverageImbuingBag), 1113768));//Average Imbuing Bag
|
||||
this.AddReward(new BaseReward("Loyalty Rating"));
|
||||
}
|
||||
|
||||
/*The Exchange*/
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113777;
|
||||
}
|
||||
}
|
||||
//Hello there! Hail and well met, and all of that. I must apologize in advance for being
|
||||
//so impatient, but you must help me! You see, my mother and my eldest sister are visiting
|
||||
//soon, and I haven<65>t seen them in quite awhile, so I want to present them both with a
|
||||
//surprise when they arrive.<br><br>My sister absolutely adores white chocolate, but
|
||||
//gargoyles don<6F>t seem to care for it much, so I haven<65>t been able to find any here.
|
||||
//It was recently my mother<65>s birthday, and I know that she would love some finely
|
||||
//crafted gargish jewelry, but the jeweler hasn<73>t had her favorite jewel in stock for
|
||||
//quite some time. If you could help me obtain five pieces of white chocolate and one
|
||||
//dark sapphire, I will reward you with a bag of hard to obtain imbuing ingredients.
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113778;
|
||||
}
|
||||
}
|
||||
//Oh, no, you must help me! Please say that you will!
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113779;
|
||||
}
|
||||
}
|
||||
//Remember, I need five pieces of white chocolate, and one dark sapphire. Please do hurry!
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113780;
|
||||
}
|
||||
}
|
||||
//Oh, thank you so very much! I cannot begin to thank you enough for helping me find
|
||||
//these presents. Here is your reward. You<6F>ll have to excuse me while I set this dark
|
||||
//sapphire in a setting that will best highlight the cut. Farewell!
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113781;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AWorthyPropositionQuest : BaseQuest
|
||||
{
|
||||
public AWorthyPropositionQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ObtainObjective(typeof(BambooFlute), "Bamboo Flutes", 10, 0x2805));
|
||||
this.AddObjective(new ObtainObjective(typeof(ElvenFletching), "Elven Fletching", 1, 0x5737));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(ValuableImbuingBag), 1113769));//Valuable Imbuing Bag
|
||||
this.AddReward(new BaseReward("Loyalty Rating"));
|
||||
}
|
||||
|
||||
/* A Worthy Proposition */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113782;
|
||||
}
|
||||
}
|
||||
|
||||
//Hello, welcome to the shop. I don't own it, but the gargoyles here are as keen to
|
||||
//learn from me as I am from them. They've been helping me with the work on my latest
|
||||
//invention, but I am short some parts. Perhaps you could help me?<br><br>I have heard
|
||||
//that the bamboo flutes of the Tokuno Islands are exceptionally strong for their weight,
|
||||
//and nothing can beat elven fletching for strength in holding them together. If you
|
||||
//would bring me, say, ten bamboo flutes and some elven fletching, I have some valuable
|
||||
//imbuing ingredients I<>ll give you in exchange. What do you say?
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113783;
|
||||
}
|
||||
}
|
||||
//Well, if you change your mind, I<>ll be here.
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113784;
|
||||
}
|
||||
}
|
||||
//Hmm, what is that? Oh yes, I would like you to bring me ten bamboo flutes and some elven
|
||||
//fletching for my fly<6C> er, my invention.
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113785;
|
||||
}
|
||||
}
|
||||
//These are of fine quality! I think they will work just fine to reinforce the floor of the
|
||||
//basket. What<61>s that? Did I say basket? I meant, bakery! Yes, I am inventing a, um, floor
|
||||
//for a bakery. There is a great need for that, you know! Ok, now please leave so I can get
|
||||
//back to work. Thank you, bye, bye!
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1113786;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Aliabeth : MondainQuester
|
||||
{
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
this.SBInfos.Add(new SBTinker(this));
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public Aliabeth()
|
||||
: base("Aliabeth", "the Tinker")
|
||||
{
|
||||
this.SetSkill(SkillName.Lockpicking, 60.0, 83.0);
|
||||
this.SetSkill(SkillName.RemoveTrap, 75.0, 98.0);
|
||||
this.SetSkill(SkillName.Tinkering, 64.0, 100.0);
|
||||
}
|
||||
|
||||
public Aliabeth(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(AWorthyPropositionQuest),
|
||||
typeof(TheExchangeQuest),
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = true;
|
||||
//this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
|
||||
this.AddItem(new Kilt(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new Shirt(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new Sandals());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Scripts/Mobiles/NPCs/AluniolTheHealer.cs
Normal file
80
Scripts/Mobiles/NPCs/AluniolTheHealer.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Aluniol : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Aluniol()
|
||||
: base("the healer")
|
||||
{
|
||||
this.Name = "Aluniol";
|
||||
}
|
||||
|
||||
public Aluniol(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8383;
|
||||
this.HairItemID = 0x2FBF;
|
||||
this.HairHue = 0x323;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots(0x1BB));
|
||||
this.AddItem(new MaleElvenRobe(0x47E));
|
||||
this.AddItem(new WildStaff());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
241
Scripts/Mobiles/NPCs/AmbitiousSolenQueen.cs
Normal file
241
Scripts/Mobiles/NPCs/AmbitiousSolenQueen.cs
Normal file
@@ -0,0 +1,241 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests.Ambitious
|
||||
{
|
||||
public abstract class BaseAmbitiousSolenQueen : BaseQuester
|
||||
{
|
||||
public BaseAmbitiousSolenQueen()
|
||||
{
|
||||
}
|
||||
|
||||
public BaseAmbitiousSolenQueen(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public abstract bool RedSolen { get; }
|
||||
public override bool DisallowAllMoves
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Name = "an ambitious solen queen";
|
||||
|
||||
this.Body = 0x30F;
|
||||
|
||||
if (!this.RedSolen)
|
||||
this.Hue = 0x453;
|
||||
|
||||
this.SpeechHue = 0;
|
||||
}
|
||||
|
||||
public override int GetIdleSound()
|
||||
{
|
||||
return 0x10D;
|
||||
}
|
||||
|
||||
public override void OnTalk(PlayerMobile player, bool contextMenu)
|
||||
{
|
||||
this.Direction = this.GetDirectionTo(player);
|
||||
|
||||
AmbitiousQueenQuest qs = player.Quest as AmbitiousQueenQuest;
|
||||
|
||||
if (qs != null && qs.RedSolen == this.RedSolen)
|
||||
{
|
||||
if (qs.IsObjectiveInProgress(typeof(KillQueensObjective)))
|
||||
{
|
||||
qs.AddConversation(new DuringKillQueensConversation());
|
||||
}
|
||||
else
|
||||
{
|
||||
QuestObjective obj = qs.FindObjective(typeof(ReturnAfterKillsObjective));
|
||||
|
||||
if (obj != null && !obj.Completed)
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
else if (qs.IsObjectiveInProgress(typeof(GatherFungiObjective)))
|
||||
{
|
||||
qs.AddConversation(new DuringFungiGatheringConversation());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetRewardObjective lastObj = qs.FindObjective(typeof(GetRewardObjective)) as GetRewardObjective;
|
||||
|
||||
if (lastObj != null && !lastObj.Completed)
|
||||
{
|
||||
bool bagOfSending = lastObj.BagOfSending;
|
||||
bool powderOfTranslocation = lastObj.PowderOfTranslocation;
|
||||
bool gold = lastObj.Gold;
|
||||
|
||||
AmbitiousQueenQuest.GiveRewardTo(player, ref bagOfSending, ref powderOfTranslocation, ref gold);
|
||||
|
||||
lastObj.BagOfSending = bagOfSending;
|
||||
lastObj.PowderOfTranslocation = powderOfTranslocation;
|
||||
lastObj.Gold = gold;
|
||||
|
||||
if (!bagOfSending && !powderOfTranslocation && !gold)
|
||||
{
|
||||
lastObj.Complete();
|
||||
}
|
||||
else
|
||||
{
|
||||
qs.AddConversation(new FullBackpackConversation(false, lastObj.BagOfSending, lastObj.PowderOfTranslocation, lastObj.Gold));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QuestSystem newQuest = new AmbitiousQueenQuest(player, this.RedSolen);
|
||||
|
||||
if (player.Quest == null && QuestSystem.CanOfferQuest(player, typeof(AmbitiousQueenQuest)))
|
||||
{
|
||||
newQuest.SendOffer();
|
||||
}
|
||||
else
|
||||
{
|
||||
newQuest.AddConversation(new DontOfferConversation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnDragDrop(Mobile from, Item dropped)
|
||||
{
|
||||
this.Direction = this.GetDirectionTo(from);
|
||||
|
||||
PlayerMobile player = from as PlayerMobile;
|
||||
|
||||
if (player != null)
|
||||
{
|
||||
AmbitiousQueenQuest qs = player.Quest as AmbitiousQueenQuest;
|
||||
|
||||
if (qs != null && qs.RedSolen == this.RedSolen)
|
||||
{
|
||||
QuestObjective obj = qs.FindObjective(typeof(GatherFungiObjective));
|
||||
|
||||
if (obj != null && !obj.Completed)
|
||||
{
|
||||
if (dropped is ZoogiFungus)
|
||||
{
|
||||
ZoogiFungus fungi = (ZoogiFungus)dropped;
|
||||
|
||||
if (fungi.Amount >= 50)
|
||||
{
|
||||
obj.Complete();
|
||||
|
||||
fungi.Amount -= 50;
|
||||
|
||||
if (fungi.Amount == 0)
|
||||
{
|
||||
fungi.Delete();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SayTo(player, 1054072); // Our arrangement was for 50 of the zoogi fungus. Please return to me when you have that amount.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnDragDrop(from, dropped);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class RedAmbitiousSolenQueen : BaseAmbitiousSolenQueen
|
||||
{
|
||||
[Constructable]
|
||||
public RedAmbitiousSolenQueen()
|
||||
{
|
||||
}
|
||||
|
||||
public RedAmbitiousSolenQueen(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool RedSolen
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class BlackAmbitiousSolenQueen : BaseAmbitiousSolenQueen
|
||||
{
|
||||
[Constructable]
|
||||
public BlackAmbitiousSolenQueen()
|
||||
{
|
||||
}
|
||||
|
||||
public BlackAmbitiousSolenQueen(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool RedSolen
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
204
Scripts/Mobiles/NPCs/Amelia.cs
Normal file
204
Scripts/Mobiles/NPCs/Amelia.cs
Normal file
@@ -0,0 +1,204 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class TheRightToolForTheJobQuest : BaseQuest
|
||||
{
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* The Right Tool for the Job */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077741;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create new scissors and hammers while inside Amelia's workshop. Try making scissors up to 45 skill, the switch
|
||||
to making hammers until 50 skill.<br><center>-----</center><br>Hello! I guess you're here to learn something about
|
||||
Tinkering, eh? You've come to the right place, as Tinkering is what I've dedicated my life to. <br><br>You'll need
|
||||
two things to get started: a supply of ingots and the right tools for the job. You can either buy ingots from the
|
||||
market, or go mine them yourself. As for tools, you can try making your own set of Tinker's Tools, or if you'd prefer
|
||||
to buy them, I have some for sale.<br><br>Working here in my shop will let me give you pointers as you go, so you'll
|
||||
be able to learn faster than anywhere else. Start off making scissors until you reach 45 tinkering skill, then switch
|
||||
to hammers until you've achieved 50. Once you've done that, come talk to me and I'll give you something for your hard
|
||||
work. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077744;
|
||||
}
|
||||
}
|
||||
|
||||
/* I<>m disappointed that you aren<65>t interested in learning more about Tinkering. It<49>s really such a useful skill!<br><br>
|
||||
*Amelia smiles*<br><br>At least you know where to find me if you change your mind, since I rarely spend time outside
|
||||
of this shop. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077745;
|
||||
}
|
||||
}
|
||||
|
||||
/* Nice going! You're not quite at Apprentice Tinkering yet, though, so you better get back to work. Remember that the
|
||||
quickest way to learn is to make scissors up until 45 skill, and then switch to hammers. Also, don't forget that working
|
||||
here in my shop will let me give you tips so you can learn faster. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077746;
|
||||
}
|
||||
}
|
||||
|
||||
/* You've done it! Look at our brand new Apprentice Tinker! You've still got quite a lot to learn if you want to be a
|
||||
Grandmaster Tinker, but I believe you can do it! Just keep in mind that if you're tinkering just to practice and improve
|
||||
your skill, make items that are moderately difficult (60-80% success chance), and try to stick to ones that use less
|
||||
ingots. <br><br>Come here, my brand new Apprentice Tinker, I want to give you something special. I created this just
|
||||
for you, so I hope you like it. It's a set of Tinker's Tools that contains a bit of magic. These tools have more charges
|
||||
than any Tinker's Tools a Tinker can make. You can even use them to make a normal set of tools, so that way you won't
|
||||
ever find yourself stuck somewhere with no tools! */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077748;
|
||||
}
|
||||
}
|
||||
|
||||
public TheRightToolForTheJobQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ApprenticeObjective(SkillName.Tinkering, 50, "Springs And Things Workshop", 1077742, 1077743));
|
||||
|
||||
// 1077742 By tinkering inside of Amelia<69>s workshop, she is able to give you advice. This helps you hone your Tinkering skill faster than normal.
|
||||
// 1077743 Since you<6F>ve left Amelia<69>s workshop, she cannot give you advice. Your Tinkering learning potential is no longer enhanced.
|
||||
|
||||
this.AddReward(new BaseReward(typeof(AmeliasToolbox), 1077749));
|
||||
}
|
||||
|
||||
public override bool CanOffer()
|
||||
{
|
||||
#region Scroll of Alacrity
|
||||
PlayerMobile pm = this.Owner as PlayerMobile;
|
||||
if (pm.AcceleratedStart > DateTime.UtcNow)
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
return this.Owner.Skills.Tinkering.Base < 50;
|
||||
}
|
||||
|
||||
public override void OnCompleted()
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077747, null, 0x23); // You have achieved the rank of Apprentice Tinker. Talk to Amelia Youngstone in New Haven to see what kind of reward she has waiting for you.
|
||||
this.Owner.PlaySound(this.CompleteSound);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Amelia : MondainQuester
|
||||
{
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(TheRightToolForTheJobQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
this.SBInfos.Add(new SBTinker(this));
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public Amelia()
|
||||
: base("Amelia Youngstone", "The Tinkering Instructor")
|
||||
{
|
||||
this.SetSkill(SkillName.ArmsLore, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Blacksmith, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Magery, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Tactics, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Swords, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Tinkering, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Mining, 120.0, 120.0);
|
||||
}
|
||||
|
||||
public Amelia(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1078123); // Tinkering is very useful for a blacksmith. You can make your own tools.
|
||||
}
|
||||
|
||||
public override void OnOfferFailed()
|
||||
{
|
||||
this.Say(1077772); // I cannot teach you, for you know all I can teach!
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = true;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Sandals());
|
||||
this.AddItem(new ShortPants());
|
||||
this.AddItem(new HalfApron(0x8AB));
|
||||
this.AddItem(new Doublet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Scripts/Mobiles/NPCs/Aminia.cs
Normal file
69
Scripts/Mobiles/NPCs/Aminia.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Aminia : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public Aminia()
|
||||
: base(AIType.AI_Melee, FightMode.None, 2, 1, 0.5, 2)
|
||||
{
|
||||
this.Name = "Aminia";
|
||||
this.Title = "the master weaponsmith's wife";
|
||||
this.Blessed = true;
|
||||
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x83ED;
|
||||
this.HairItemID = 0x203B;
|
||||
this.HairHue = 0x454;
|
||||
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Sandals(0x75B));
|
||||
this.AddItem(new Tunic(0x4BF));
|
||||
this.AddItem(new Skirt(0x8FD));
|
||||
}
|
||||
|
||||
public Aminia(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnThink()
|
||||
{
|
||||
int hours = 0;
|
||||
int minutes = 0;
|
||||
|
||||
Clock.GetTime(this.Map, this.Location.X, this.Location.Y, out hours, out minutes);
|
||||
|
||||
if (hours == 21)
|
||||
{
|
||||
this.Blessed = false;
|
||||
this.Body = 0x17;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Blessed = true;
|
||||
this.Body = 0x191;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
194
Scripts/Mobiles/NPCs/AndreasVesalius.cs
Normal file
194
Scripts/Mobiles/NPCs/AndreasVesalius.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class KnowThineEnemyQuest : BaseQuest
|
||||
{
|
||||
public override bool DoneOnce
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Knowing Thine Enemy */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077685;
|
||||
}
|
||||
}
|
||||
|
||||
/* Head East out of town to Old Haven. Battle monsters there, or heal yourself and other players, until you
|
||||
have raised your Anatomy skill to 50.<br><center>------</center><br>Hail and well met. You must be here to
|
||||
improve your knowledge of Anatomy. Well, you've come to the right place because I can teach you what you need
|
||||
to know. At least all you'll need to know for now. Haha!<br><br>Knowing about how living things work inside
|
||||
can be a very useful skill. Not only can you learn where to strike an opponent to hurt him the most, but you
|
||||
can use what you learn to heal wounds better as well. Just walking around town, you can even tell if someone
|
||||
is strong or weak or if they happen to be particularly dexterous or not.<BR><BR>If you're interested in learning
|
||||
more, I'd advise you to head out to Old Haven, just to the east, and jump into the fray. You'll learn best by
|
||||
engaging in combat while keeping you and your fellow adventurers healed, or you can even try sizing up your
|
||||
opponents.<br><br>While you're gone, I'll dig up something you may find useful. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077688;
|
||||
}
|
||||
}
|
||||
|
||||
/* It's your choice, but I wouldn't head out there without knowing what makes those things tick inside! If you
|
||||
change your mind, you can find me right here dissecting frogs, cats or even the occasional unlucky adventurer. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077689;
|
||||
}
|
||||
}
|
||||
|
||||
/* I'm surprised to see you back so soon. You've still got a ways to go if you want to really understand the
|
||||
science of Anatomy. Head out to Old Haven and practice combat and healing yourself or other adventurers. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077690;
|
||||
}
|
||||
}
|
||||
|
||||
/* By the Virtues, you've done it! Congratulations mate! You still have quite a ways to go if you want to perfect
|
||||
your knowledge of Anatomy, but I know you'll get there someday. Just keep at it.<br><br>In the meantime, here's a
|
||||
piece of armor that you might find useful. It's not fancy, but it'll serve you well if you choose to wear it.<br>
|
||||
<br>Happy adventuring, and remember to keep your cranium separate from your clavicle! */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1077692;
|
||||
}
|
||||
}
|
||||
|
||||
public KnowThineEnemyQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ApprenticeObjective(SkillName.Anatomy, 50, "Old Haven Training", 1077686, 1077687));
|
||||
|
||||
// 1077686 You feel very willing to learn more about the body. Your ability to hone your Anatomy skill is enhanced in this area.
|
||||
// 1077687 You lose your ambition to learn about the body. Your Anatomy skill learning potential is no longer enhanced.
|
||||
|
||||
this.AddReward(new BaseReward(typeof(TunicOfGuarding), 1077693));
|
||||
}
|
||||
|
||||
public override bool CanOffer()
|
||||
{
|
||||
#region Scroll of Alacrity
|
||||
PlayerMobile pm = this.Owner as PlayerMobile;
|
||||
if (pm.AcceleratedStart > DateTime.UtcNow)
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077951); // You are already under the effect of an accelerated skillgain scroll.
|
||||
return false;
|
||||
}
|
||||
#endregion
|
||||
else
|
||||
return this.Owner.Skills.Anatomy.Base < 50;
|
||||
}
|
||||
|
||||
public override void OnCompleted()
|
||||
{
|
||||
this.Owner.SendLocalizedMessage(1077691, null, 0x23); // You have achieved the rank of Apprentice Healer (for Anatomy). Return to Andreas Vesalius in New Haven as soon as you can to claim your reward.
|
||||
this.Owner.PlaySound(this.CompleteSound);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AndreasVesalius : MondainQuester
|
||||
{
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(KnowThineEnemyQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public AndreasVesalius()
|
||||
: base("Andreas Vesalius", "The Anatomy Instructor")
|
||||
{
|
||||
this.SetSkill(SkillName.Anatomy, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Parry, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Healing, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Tactics, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Swords, 120.0, 120.0);
|
||||
this.SetSkill(SkillName.Focus, 120.0, 120.0);
|
||||
}
|
||||
|
||||
public AndreasVesalius(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1078138); // Learning of the body will allow you to excel in combat.
|
||||
}
|
||||
|
||||
public override void OnOfferFailed()
|
||||
{
|
||||
this.Say(1077772); // I cannot teach you, for you know all I can teach!
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
base.InitBody();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new BlackStaff());
|
||||
this.AddItem(new Boots());
|
||||
this.AddItem(new LongPants());
|
||||
this.AddItem(new Tunic(0x66D));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
185
Scripts/Mobiles/NPCs/Andric.cs
Normal file
185
Scripts/Mobiles/NPCs/Andric.cs
Normal file
@@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class SplitEndsQuest : BaseQuest
|
||||
{
|
||||
public SplitEndsQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ObtainObjective(typeof(Arrow), "arrow", 20, 0xF3F));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(FletchersSatchel), 1074282)); // Craftsman's Satchel
|
||||
}
|
||||
|
||||
/* Split Ends */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075506;
|
||||
}
|
||||
}
|
||||
/* *sighs* I think bowcrafting is a might beyond my talents. Say there, you look a bit more confident with tools.
|
||||
Can I persuade thee to make a few arrows? You could have my satchel in return... 'tis useless to me! You'll need a
|
||||
fletching kit to start, some feathers, and a few arrow shafts. Just use the fletching kit while you have the other
|
||||
things, and I'm sure you'll figure out the rest. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075507;
|
||||
}
|
||||
}
|
||||
/* Oh. Well. I'll just keep trying alone, I suppose... */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075508;
|
||||
}
|
||||
}
|
||||
/* You're not quite done yet. Get back to work! */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072271;
|
||||
}
|
||||
}
|
||||
/* Thanks for helping me out. Here's the reward I promised you. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072272;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Andric : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Andric()
|
||||
: base("Andric", "the archer trainer")
|
||||
{
|
||||
this.SetSkill(SkillName.Archery, 65.0, 88.0);
|
||||
}
|
||||
|
||||
public Andric(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(SplitEndsQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x8407;
|
||||
this.HairItemID = 0x2049;
|
||||
this.HairHue = 0x6CE;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Boots(0x1BB));
|
||||
|
||||
Item item;
|
||||
|
||||
item = new LeatherLegs();
|
||||
item.Hue = 0x6C8;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new LeatherGloves();
|
||||
item.Hue = 0x1BB;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new LeatherChest();
|
||||
item.Hue = 0x1BB;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new LeatherArms();
|
||||
item.Hue = 0x4C7;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new CompositeBow();
|
||||
item.Hue = 0x5DD;
|
||||
this.AddItem(item);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class FletchersSatchel : Backpack
|
||||
{
|
||||
[Constructable]
|
||||
public FletchersSatchel()
|
||||
: base()
|
||||
{
|
||||
this.Hue = BaseReward.SatchelHue();
|
||||
|
||||
this.AddItem(new Feather(10));
|
||||
this.AddItem(new FletcherTools());
|
||||
}
|
||||
|
||||
public FletchersSatchel(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Scripts/Mobiles/NPCs/Andros.cs
Normal file
64
Scripts/Mobiles/NPCs/Andros.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class Andros : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Andros()
|
||||
: base("Andros", "the blacksmith")
|
||||
{
|
||||
}
|
||||
|
||||
public Andros(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x8409;
|
||||
this.HairItemID = 0x2049;
|
||||
this.HairHue = 0x45E;
|
||||
this.FacialHairItemID = 0x2041;
|
||||
this.FacialHairHue = 0x45E;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Boots(0x901));
|
||||
this.AddItem(new LongPants(0x1BB));
|
||||
this.AddItem(new FancyShirt(0x60B));
|
||||
this.AddItem(new FullApron(0x901));
|
||||
this.AddItem(new SmithHammer());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Scripts/Mobiles/NPCs/Aneen.cs
Normal file
80
Scripts/Mobiles/NPCs/Aneen.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Aneen : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Aneen()
|
||||
: base("the keeper of tradition")
|
||||
{
|
||||
this.Name = "Lorekeeper Aneen";
|
||||
}
|
||||
|
||||
public Aneen(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x83E5;
|
||||
this.HairItemID = 0x2FBF;
|
||||
this.HairHue = 0x90;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Sandals(0x1BB));
|
||||
this.AddItem(new MaleElvenRobe(0x48F));
|
||||
this.AddItem(new Item(0xDF2));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
255
Scripts/Mobiles/NPCs/Aniel.cs
Normal file
255
Scripts/Mobiles/NPCs/Aniel.cs
Normal file
@@ -0,0 +1,255 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class CircleOfLifeQuest : BaseQuest
|
||||
{
|
||||
public CircleOfLifeQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new SlayObjective(typeof(BogThing), "bog things", 8));
|
||||
|
||||
AddReward(new BaseReward(typeof(LargeTreasureBag), 1072706));
|
||||
}
|
||||
|
||||
/* Circle of Life */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073656;
|
||||
}
|
||||
}
|
||||
/* There's been a bumper crop of evil with the Bog Things in these parts, my friend. Though they are
|
||||
foul creatures, they are also most fecund. Slay one and you make the land more fertile. Even better,
|
||||
slay several and I will give you whatever coin I can spare. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073695;
|
||||
}
|
||||
}
|
||||
/* Perhaps you'll change your mind and return at some point. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073733;
|
||||
}
|
||||
}
|
||||
/* Continue to seek and kill the Bog Things. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073736;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class DustToDustQuest : BaseQuest
|
||||
{
|
||||
public DustToDustQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new SlayObjective(typeof(EarthElemental), "earth elementals", 12));
|
||||
|
||||
AddReward(new BaseReward(typeof(TreasureBag), 1072583));
|
||||
}
|
||||
|
||||
/* Dust to Dust */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073074;
|
||||
}
|
||||
}
|
||||
/* You want to hear about trouble? I got trouble. How's angry piles of granite walking around for
|
||||
trouble? Maybe they don't like the mining, maybe it's the farming. I don't know. All I know is
|
||||
someone's got to turn them back to potting soil. And it'd be worth a pretty penny to the soul that
|
||||
does it. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073564;
|
||||
}
|
||||
}
|
||||
/* I hope you'll reconsider. Until then, farwell. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073580;
|
||||
}
|
||||
}
|
||||
/* You got rocks in your head? I said to kill 12 earth elementals, okay? */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073584;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class ArchSupportQuest : BaseQuest
|
||||
{
|
||||
public ArchSupportQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(FootStool), "foot stools", 10, 0xB5E));
|
||||
|
||||
AddReward(new BaseReward(typeof(CarpentersCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* Arch Support */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073882;
|
||||
}
|
||||
}
|
||||
/* How clever humans are - to understand the need of feet to rest from time to time! Imagine creating
|
||||
a special stool just for weary toes. I would like to examine and learn the secret of their making.
|
||||
Would you bring me some foot stools to examine? */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074072;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me foot stools. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073928;
|
||||
}
|
||||
}
|
||||
/* My thanks for your service. Now, I will show you something of elven carpentry. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073969;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Aniel : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Aniel()
|
||||
: base("Aniel", "the aborist")
|
||||
{
|
||||
SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Aniel(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(GlassyFoeQuest),
|
||||
typeof(CircleOfLifeQuest),
|
||||
typeof(DustToDustQuest),
|
||||
typeof(ArchSupportQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
InitStats(100, 100, 25);
|
||||
|
||||
Female = false;
|
||||
Race = Race.Elf;
|
||||
|
||||
Hue = 0x8384;
|
||||
HairItemID = 0x2FC2;
|
||||
HairHue = 0x36;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
AddItem(new ElvenBoots(0x901));
|
||||
AddItem(new HalfApron(0x759));
|
||||
AddItem(new ElvenPants(0x901));
|
||||
AddItem(new LeafChest());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
674
Scripts/Mobiles/NPCs/AnimalTrainer.cs
Normal file
674
Scripts/Mobiles/NPCs/AnimalTrainer.cs
Normal file
@@ -0,0 +1,674 @@
|
||||
#region References
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
using Server.Engines.Quests;
|
||||
using System.Linq;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class AnimalTrainer : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
|
||||
[Constructable]
|
||||
public AnimalTrainer()
|
||||
: base("the animal trainer")
|
||||
{
|
||||
SetSkill(SkillName.AnimalLore, 64.0, 100.0);
|
||||
SetSkill(SkillName.AnimalTaming, 90.0, 100.0);
|
||||
SetSkill(SkillName.Veterinary, 65.0, 88.0);
|
||||
}
|
||||
|
||||
public AnimalTrainer(Serial serial)
|
||||
: base(serial)
|
||||
{ }
|
||||
|
||||
protected override List<SBInfo> SBInfos { get { return m_SBInfos; } }
|
||||
public override VendorShoeType ShoeType { get { return Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots; } }
|
||||
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
m_SBInfos.Add(new SBAnimalTrainer());
|
||||
}
|
||||
|
||||
public override int GetShoeHue()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(Utility.RandomBool() ? new QuarterStaff() : (Item)new ShepherdsCrook());
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
if (from.Alive)
|
||||
{
|
||||
list.Add(new StableEntry(this, from));
|
||||
|
||||
if (from.Stabled.Count > 0)
|
||||
{
|
||||
list.Add(new ClaimAllEntry(this, from));
|
||||
}
|
||||
}
|
||||
|
||||
base.AddCustomContextEntries(from, list);
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
if (PetTrainingHelper.Enabled)
|
||||
{
|
||||
list.Add(1072269); // Quest Giver
|
||||
}
|
||||
}
|
||||
|
||||
private DateTime _NextTalk;
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
if (PetTrainingHelper.Enabled && m.Alive && !m.Hidden && m is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = (PlayerMobile)m;
|
||||
|
||||
if (InLOS(m) && InRange(m, 8) && !InRange(oldLocation, 8) && DateTime.UtcNow >= _NextTalk)
|
||||
{
|
||||
if (Utility.Random(100) < 50)
|
||||
Say(1157526); // Such an exciting time to be an Animal Trainer! New taming techniques have been discovered!
|
||||
|
||||
_NextTalk = DateTime.UtcNow + TimeSpan.FromSeconds(15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] _Quests = { typeof(TamingPetQuest), typeof(UsingAnimalLoreQuest), typeof(LeadingIntoBattleQuest), typeof(TeachingSomethingNewQuest) };
|
||||
|
||||
public override void OnDoubleClick(Mobile m)
|
||||
{
|
||||
if (PetTrainingHelper.Enabled && m is PlayerMobile && m.InRange(Location, 5))
|
||||
{
|
||||
CheckQuest((PlayerMobile)m);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckQuest(PlayerMobile player)
|
||||
{
|
||||
for (int i = 0; i < _Quests.Length; i++)
|
||||
{
|
||||
var quest = player.Quests.FirstOrDefault(q => q.GetType() == _Quests[i]);
|
||||
|
||||
if (quest != null)
|
||||
{
|
||||
if (quest.Completed)
|
||||
{
|
||||
if (quest.GetType() != typeof(TeachingSomethingNewQuest))
|
||||
{
|
||||
quest.GiveRewards();
|
||||
}
|
||||
else
|
||||
{
|
||||
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.Complete, false, true));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
player.SendGump(new MondainQuestGump(quest, MondainQuestGump.Section.InProgress, false));
|
||||
quest.InProgress();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
BaseQuest questt = new TamingPetQuest();
|
||||
questt.Owner = player;
|
||||
questt.Quester = this;
|
||||
player.CloseGump(typeof(MondainQuestGump));
|
||||
player.SendGump(new MondainQuestGump(questt));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static int GetMaxStabled(Mobile from)
|
||||
{
|
||||
var taming = from.Skills[SkillName.AnimalTaming].Value;
|
||||
var anlore = from.Skills[SkillName.AnimalLore].Value;
|
||||
var vetern = from.Skills[SkillName.Veterinary].Value;
|
||||
var sklsum = taming + anlore + vetern;
|
||||
|
||||
int max = from is PlayerMobile ? ((PlayerMobile)from).RewardStableSlots : 0;
|
||||
|
||||
if (sklsum >= 240.0)
|
||||
{
|
||||
max += 5;
|
||||
}
|
||||
else if (sklsum >= 200.0)
|
||||
{
|
||||
max += 4;
|
||||
}
|
||||
else if (sklsum >= 160.0)
|
||||
{
|
||||
max += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
max += 2;
|
||||
}
|
||||
|
||||
// bonus SA stable slots
|
||||
if (Core.SA)
|
||||
{
|
||||
max += 2;
|
||||
}
|
||||
//bonus ToL stable slots
|
||||
if (Core.TOL)
|
||||
{
|
||||
max += 2;
|
||||
}
|
||||
|
||||
if (taming >= 100.0)
|
||||
{
|
||||
max += (int)((taming - 90.0) / 10);
|
||||
}
|
||||
|
||||
if (anlore >= 100.0)
|
||||
{
|
||||
max += (int)((anlore - 90.0) / 10);
|
||||
}
|
||||
|
||||
if (vetern >= 100.0)
|
||||
{
|
||||
max += (int)((vetern - 90.0) / 10);
|
||||
}
|
||||
|
||||
return max + Server.Spells.SkillMasteries.MasteryInfo.BoardingSlotIncrease(from);
|
||||
}
|
||||
|
||||
private void CloseClaimList(Mobile from)
|
||||
{
|
||||
from.CloseGump(typeof(ClaimListGump));
|
||||
}
|
||||
|
||||
public void BeginClaimList(Mobile from)
|
||||
{
|
||||
if (Deleted || !from.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var list = new List<BaseCreature>();
|
||||
|
||||
for (var i = 0; i < from.Stabled.Count; ++i)
|
||||
{
|
||||
var pet = from.Stabled[i] as BaseCreature;
|
||||
|
||||
if (pet == null || pet.Deleted)
|
||||
{
|
||||
if (pet != null)
|
||||
{
|
||||
pet.IsStabled = false;
|
||||
pet.StabledBy = null;
|
||||
}
|
||||
|
||||
from.Stabled.RemoveAt(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
list.Add(pet);
|
||||
}
|
||||
|
||||
if (list.Count > 0)
|
||||
{
|
||||
from.SendGump(new ClaimListGump(this, from, list));
|
||||
}
|
||||
else
|
||||
{
|
||||
SayTo(from, 502671); // But I have no animals stabled with me at the moment!
|
||||
}
|
||||
}
|
||||
|
||||
public void EndClaimList(Mobile from, BaseCreature pet)
|
||||
{
|
||||
if (pet == null || pet.Deleted || from.Map != Map || !from.Stabled.Contains(pet) || !from.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!from.InRange(this, 14))
|
||||
{
|
||||
from.SendLocalizedMessage(500446); // That is too far away.
|
||||
return;
|
||||
}
|
||||
|
||||
if (CanClaim(from, pet))
|
||||
{
|
||||
DoClaim(from, pet);
|
||||
|
||||
from.Stabled.Remove(pet);
|
||||
|
||||
if (from is PlayerMobile)
|
||||
{
|
||||
((PlayerMobile)from).AutoStabled.Remove(pet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers.
|
||||
}
|
||||
}
|
||||
|
||||
public void BeginStable(Mobile from)
|
||||
{
|
||||
if (Deleted || !from.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((from.Backpack == null || from.Backpack.GetAmount(typeof(Gold)) < 30) && Banker.GetBalance(from) < 30)
|
||||
{
|
||||
SayTo(from, 1042556); // Thou dost not have enough gold, not even in thy bank account.
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* I charge 30 gold per pet for a real week's stable time.
|
||||
* I will withdraw it from thy bank account.
|
||||
* Which animal wouldst thou like to stable here?
|
||||
*/
|
||||
from.SendLocalizedMessage(1042558);
|
||||
|
||||
from.Target = new StableTarget(this);
|
||||
}
|
||||
|
||||
public void EndStable(Mobile from, BaseCreature pet)
|
||||
{
|
||||
if (Deleted || !from.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pet.Body.IsHuman)
|
||||
{
|
||||
SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn.
|
||||
}
|
||||
else if (!pet.Controlled)
|
||||
{
|
||||
SayTo(from, 1048053); // You can't stable that!
|
||||
}
|
||||
else if (pet.ControlMaster != from)
|
||||
{
|
||||
SayTo(from, 1042562); // You do not own that pet!
|
||||
}
|
||||
else if (pet.IsDeadPet)
|
||||
{
|
||||
SayTo(from, 1049668); // Living pets only, please.
|
||||
}
|
||||
else if (pet.Summoned)
|
||||
{
|
||||
SayTo(from, 502673); // I can not stable summoned creatures.
|
||||
}
|
||||
else if (pet.Allured)
|
||||
{
|
||||
SayTo(from, 1048053); // You can't stable that!
|
||||
}
|
||||
else if ((pet is PackLlama || pet is PackHorse || pet is Beetle) &&
|
||||
(pet.Backpack != null && pet.Backpack.Items.Count > 0))
|
||||
{
|
||||
SayTo(from, 1042563); // You need to unload your pet.
|
||||
}
|
||||
else if (pet.Combatant != null && pet.InRange(pet.Combatant, 12) && pet.Map == pet.Combatant.Map)
|
||||
{
|
||||
SayTo(from, 1042564); // I'm sorry. Your pet seems to be busy.
|
||||
}
|
||||
else if (from.Stabled.Count >= GetMaxStabled(from))
|
||||
{
|
||||
SayTo(from, 1042565); // You have too many pets in the stables!
|
||||
}
|
||||
else if ((from.Backpack != null && from.Backpack.ConsumeTotal(typeof(Gold), 30)) || Banker.Withdraw(from, 30))
|
||||
{
|
||||
pet.ControlTarget = null;
|
||||
pet.ControlOrder = OrderType.Stay;
|
||||
pet.Internalize();
|
||||
|
||||
pet.SetControlMaster(null);
|
||||
pet.SummonMaster = null;
|
||||
|
||||
pet.IsStabled = true;
|
||||
pet.StabledBy = from;
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
pet.Loyalty = MaxLoyalty; // Wonderfully happy
|
||||
}
|
||||
|
||||
from.Stabled.Add(pet);
|
||||
|
||||
SayTo(from, Core.AOS ? 1049677 : 502679);
|
||||
// [AOS: Your pet has been stabled.] Very well, thy pet is stabled.
|
||||
// Thou mayst recover it by saying 'claim' to me. In one real world week,
|
||||
// I shall sell it off if it is not claimed!
|
||||
}
|
||||
else
|
||||
{
|
||||
SayTo(from, 502677); // But thou hast not the funds in thy bank account!
|
||||
}
|
||||
}
|
||||
|
||||
public void Claim(Mobile from)
|
||||
{
|
||||
Claim(from, null);
|
||||
}
|
||||
|
||||
public void Claim(Mobile from, string petName)
|
||||
{
|
||||
if (Deleted || !from.CheckAlive())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var claimed = false;
|
||||
var stabled = 0;
|
||||
|
||||
var claimByName = (petName != null);
|
||||
|
||||
for (var i = 0; i < from.Stabled.Count; ++i)
|
||||
{
|
||||
var pet = from.Stabled[i] as BaseCreature;
|
||||
|
||||
if (pet == null || pet.Deleted)
|
||||
{
|
||||
if (pet != null)
|
||||
{
|
||||
pet.IsStabled = false;
|
||||
pet.StabledBy = null;
|
||||
}
|
||||
|
||||
from.Stabled.RemoveAt(i--);
|
||||
continue;
|
||||
}
|
||||
|
||||
++stabled;
|
||||
|
||||
if (claimByName && !Insensitive.Equals(pet.Name, petName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CanClaim(from, pet))
|
||||
{
|
||||
DoClaim(from, pet);
|
||||
|
||||
from.Stabled.RemoveAt(i);
|
||||
|
||||
if (from is PlayerMobile)
|
||||
{
|
||||
((PlayerMobile)from).AutoStabled.Remove(pet);
|
||||
}
|
||||
|
||||
--i;
|
||||
|
||||
claimed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SayTo(from, 1049612, pet.Name); // ~1_NAME~ remained in the stables because you have too many followers.
|
||||
}
|
||||
}
|
||||
|
||||
if (claimed)
|
||||
{
|
||||
SayTo(from, 1042559); // Here you go... and good day to you!
|
||||
}
|
||||
else if (stabled == 0)
|
||||
{
|
||||
SayTo(from, 502671); // But I have no animals stabled with me at the moment!
|
||||
}
|
||||
else if (claimByName)
|
||||
{
|
||||
BeginClaimList(from);
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanClaim(Mobile from, BaseCreature pet)
|
||||
{
|
||||
return ((from.Followers + pet.ControlSlots) <= from.FollowersMax);
|
||||
}
|
||||
|
||||
private void DoClaim(Mobile from, BaseCreature pet)
|
||||
{
|
||||
pet.SetControlMaster(from);
|
||||
|
||||
if (pet.Summoned)
|
||||
{
|
||||
pet.SummonMaster = from;
|
||||
}
|
||||
|
||||
pet.ControlTarget = from;
|
||||
pet.ControlOrder = OrderType.Follow;
|
||||
|
||||
pet.MoveToWorld(from.Location, from.Map);
|
||||
|
||||
pet.IsStabled = false;
|
||||
pet.StabledBy = null;
|
||||
|
||||
if (Core.SE)
|
||||
{
|
||||
pet.Loyalty = MaxLoyalty; // Wonderfully Happy
|
||||
}
|
||||
}
|
||||
|
||||
public override bool HandlesOnSpeech(Mobile from)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnSpeech(SpeechEventArgs e)
|
||||
{
|
||||
if (e.Mobile.Map.Rules != MapRules.FeluccaRules && !CheckVendorAccess(e.Mobile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!e.Handled && e.HasKeyword(0x0008)) // *stable*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
CloseClaimList(e.Mobile);
|
||||
BeginStable(e.Mobile);
|
||||
}
|
||||
else if (!e.Handled && e.HasKeyword(0x0009)) // *claim*
|
||||
{
|
||||
e.Handled = true;
|
||||
|
||||
CloseClaimList(e.Mobile);
|
||||
|
||||
var index = e.Speech.IndexOf(' ');
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
Claim(e.Mobile, e.Speech.Substring(index).Trim());
|
||||
}
|
||||
else
|
||||
{
|
||||
Claim(e.Mobile);
|
||||
}
|
||||
}
|
||||
else if (!e.Handled && e.Speech.ToLower().IndexOf("stablecount") >= 0)
|
||||
{
|
||||
IPooledEnumerable eable = e.Mobile.Map.GetMobilesInRange(e.Mobile.Location, 8);
|
||||
e.Handled = true;
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m is AnimalTrainer)
|
||||
{
|
||||
e.Mobile.SendLocalizedMessage(1071250, String.Format("{0}\t{1}", e.Mobile.Stabled.Count.ToString(), GetMaxStabled(e.Mobile).ToString())); // ~1_USED~/~2_MAX~ stable stalls used.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
else
|
||||
{
|
||||
base.OnSpeech(e);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
reader.ReadInt();
|
||||
}
|
||||
|
||||
private class StableEntry : ContextMenuEntry
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly AnimalTrainer m_Trainer;
|
||||
|
||||
public StableEntry(AnimalTrainer trainer, Mobile from)
|
||||
: base(6126, 12)
|
||||
{
|
||||
m_Trainer = trainer;
|
||||
m_From = from;
|
||||
|
||||
Enabled = from.Map.Rules == MapRules.FeluccaRules || trainer.CheckVendorAccess(from);
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Trainer.BeginStable(m_From);
|
||||
}
|
||||
}
|
||||
|
||||
private class ClaimListGump : Gump
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly List<BaseCreature> m_List;
|
||||
private readonly AnimalTrainer m_Trainer;
|
||||
|
||||
public ClaimListGump(AnimalTrainer trainer, Mobile from, List<BaseCreature> list)
|
||||
: base(50, 50)
|
||||
{
|
||||
m_Trainer = trainer;
|
||||
m_From = from;
|
||||
m_List = list;
|
||||
|
||||
from.CloseGump(typeof(ClaimListGump));
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 325, 50 + (list.Count * 20), 9250);
|
||||
AddAlphaRegion(5, 5, 315, 40 + (list.Count * 20));
|
||||
|
||||
AddHtml(
|
||||
15,
|
||||
15,
|
||||
275,
|
||||
20,
|
||||
"<BASEFONT COLOR=#000008>Select a pet to retrieve from the stables:</BASEFONT>",
|
||||
false,
|
||||
false);
|
||||
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
{
|
||||
var pet = list[i];
|
||||
|
||||
if (pet == null || pet.Deleted)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddButton(15, 39 + (i * 20), 10006, 10006, i + 1, GumpButtonType.Reply, 0);
|
||||
AddHtml(
|
||||
32,
|
||||
35 + (i * 20),
|
||||
275,
|
||||
18,
|
||||
String.Format("<BASEFONT COLOR=#C6C6EF>{0}</BASEFONT>", pet.Name),
|
||||
false,
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
var index = info.ButtonID - 1;
|
||||
|
||||
if (index >= 0 && index < m_List.Count)
|
||||
{
|
||||
m_Trainer.EndClaimList(m_From, m_List[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ClaimAllEntry : ContextMenuEntry
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly AnimalTrainer m_Trainer;
|
||||
|
||||
public ClaimAllEntry(AnimalTrainer trainer, Mobile from)
|
||||
: base(6127, 12)
|
||||
{
|
||||
m_Trainer = trainer;
|
||||
m_From = from;
|
||||
|
||||
Enabled = from.Map.Rules == MapRules.FeluccaRules || trainer.CheckVendorAccess(from);
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Trainer.Claim(m_From);
|
||||
}
|
||||
}
|
||||
|
||||
private class StableTarget : Target
|
||||
{
|
||||
private readonly AnimalTrainer m_Trainer;
|
||||
|
||||
public StableTarget(AnimalTrainer trainer)
|
||||
: base(12, false, TargetFlags.None)
|
||||
{
|
||||
m_Trainer = trainer;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is BaseCreature)
|
||||
{
|
||||
m_Trainer.EndStable(from, (BaseCreature)targeted);
|
||||
}
|
||||
else if (targeted == from)
|
||||
{
|
||||
m_Trainer.SayTo(from, 502672); // HA HA HA! Sorry, I am not an inn.
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Trainer.SayTo(from, 1048053); // You can't stable that!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Scripts/Mobiles/NPCs/Anolly.cs
Normal file
200
Scripts/Mobiles/NPCs/Anolly.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class StopHarpingOnMeQuest : BaseQuest
|
||||
{
|
||||
public StopHarpingOnMeQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(LapHarp), "lap harp", 20, 0xEB2));
|
||||
|
||||
AddReward(new BaseReward(typeof(CarpentersCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* Stop Harping on Me */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073881;
|
||||
}
|
||||
}
|
||||
/* Humans artistry can be a remarkable thing. For instance, I have heard of a wonderful
|
||||
instrument which creates the most melodious of music. A lap harp. I would be ever so
|
||||
grateful if I could examine one in person. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074071;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me lap harp. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073927;
|
||||
}
|
||||
}
|
||||
/* My thanks for your service. Now, I will show you something of elven carpentry. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073969;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class TheFarEyeQuest : BaseQuest
|
||||
{
|
||||
public TheFarEyeQuest()
|
||||
: base()
|
||||
{
|
||||
AddObjective(new ObtainObjective(typeof(Spyglass), "spyglasses", 20, 0x14F5));
|
||||
|
||||
AddReward(new BaseReward(typeof(TinkersCraftsmanSatchel), 1074282));
|
||||
}
|
||||
|
||||
/* The Far Eye */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073908;
|
||||
}
|
||||
}
|
||||
/* The wonders of human invention! Turning sand and metal into a far-seeing eye! This is
|
||||
something I must experience for myself. Bring me some of these spyglasses friend human. */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1074098;
|
||||
}
|
||||
}
|
||||
/* I will patiently await your reconsideration. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073921;
|
||||
}
|
||||
}
|
||||
/* I will be in your debt if you bring me spyglasses. */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073954;
|
||||
}
|
||||
}
|
||||
/* Enjoy my thanks for your service. */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073978;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Anolly : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Anolly()
|
||||
: base("Anolly", "the bark weaver")
|
||||
{
|
||||
SetSkill(SkillName.Meditation, 60.0, 83.0);
|
||||
SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Anolly(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(StopHarpingOnMeQuest),
|
||||
typeof(TheFarEyeQuest),
|
||||
typeof(NothingFancyQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
InitStats(100, 100, 25);
|
||||
|
||||
Female = false;
|
||||
Race = Race.Elf;
|
||||
|
||||
Hue = 0x8835;
|
||||
HairItemID = 0x2FC0;
|
||||
HairHue = 0x325;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
AddItem(new Sandals(0x901));
|
||||
AddItem(new FullApron(0x1BB));
|
||||
AddItem(new ShortPants(0x3B2));
|
||||
AddItem(new SmithHammer());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
147
Scripts/Mobiles/NPCs/AnsellaGryen.cs
Normal file
147
Scripts/Mobiles/NPCs/AnsellaGryen.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.Quests.Zento
|
||||
{
|
||||
public class AnsellaGryen : BaseQuester
|
||||
{
|
||||
[Constructable]
|
||||
public AnsellaGryen()
|
||||
{
|
||||
}
|
||||
|
||||
public AnsellaGryen(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Hue = 0x83EA;
|
||||
|
||||
this.Female = true;
|
||||
this.Body = 0x191;
|
||||
this.Name = "Ansella Gryen";
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.HairItemID = 0x203B;
|
||||
this.HairHue = 0x1BB;
|
||||
|
||||
this.AddItem(new SamuraiTabi(0x8FD));
|
||||
this.AddItem(new FemaleKimono(0x4B6));
|
||||
this.AddItem(new Obi(0x526));
|
||||
|
||||
this.AddItem(new GoldBracelet());
|
||||
}
|
||||
|
||||
public override int GetAutoTalkRange(PlayerMobile m)
|
||||
{
|
||||
if (m.Quest == null)
|
||||
return 3;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
public override void OnTalk(PlayerMobile player, bool contextMenu)
|
||||
{
|
||||
QuestSystem qs = player.Quest;
|
||||
|
||||
if (qs is TerribleHatchlingsQuest)
|
||||
{
|
||||
if (qs.IsObjectiveInProgress(typeof(FirstKillObjective)))
|
||||
{
|
||||
qs.AddConversation(new DirectionConversation());
|
||||
}
|
||||
else if (qs.IsObjectiveInProgress(typeof(SecondKillObjective)) ||
|
||||
qs.IsObjectiveInProgress(typeof(ThirdKillObjective)))
|
||||
{
|
||||
qs.AddConversation(new TakeCareConversation());
|
||||
}
|
||||
else
|
||||
{
|
||||
QuestObjective obj = qs.FindObjective(typeof(ReturnObjective));
|
||||
|
||||
if (obj != null && !obj.Completed)
|
||||
{
|
||||
Container cont = GetNewContainer();
|
||||
|
||||
cont.DropItem(new Gold(Utility.RandomMinMax(100, 200)));
|
||||
|
||||
if (Utility.RandomBool())
|
||||
{
|
||||
BaseWeapon weapon = Loot.Construct(Loot.SEWeaponTypes) as BaseWeapon;
|
||||
|
||||
if (weapon != null)
|
||||
{
|
||||
BaseRunicTool.ApplyAttributesTo(weapon, 3, 10, 30);
|
||||
cont.DropItem(weapon);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseArmor armor = Loot.Construct(Loot.SEArmorTypes) as BaseArmor;
|
||||
|
||||
if (armor != null)
|
||||
{
|
||||
BaseRunicTool.ApplyAttributesTo(armor, 1, 10, 20);
|
||||
cont.DropItem(armor);
|
||||
}
|
||||
}
|
||||
|
||||
if (player.PlaceInBackpack(cont))
|
||||
{
|
||||
obj.Complete();
|
||||
}
|
||||
else
|
||||
{
|
||||
cont.Delete();
|
||||
player.SendLocalizedMessage(1046260); // You need to clear some space in your inventory to continue with the quest. Come back here when you have more space in your inventory.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TerribleHatchlingsQuest newQuest = new TerribleHatchlingsQuest(player);
|
||||
bool inRestartPeriod = false;
|
||||
|
||||
if (qs != null)
|
||||
{
|
||||
if (contextMenu)
|
||||
this.SayTo(player, 1063322); // Before you can help me with the Terrible Hatchlings, you'll need to finish the quest you've already taken!
|
||||
}
|
||||
else if (QuestSystem.CanOfferQuest(player, typeof(TerribleHatchlingsQuest), out inRestartPeriod))
|
||||
{
|
||||
newQuest.SendOffer();
|
||||
}
|
||||
else if (inRestartPeriod && contextMenu)
|
||||
{
|
||||
this.SayTo(player, 1049357); // I have nothing more for you at this time.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
|
||||
public override void TurnToTokuno()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Scripts/Mobiles/NPCs/Ansikart.cs
Normal file
69
Scripts/Mobiles/NPCs/Ansikart.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class Ansikart : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Ansikart()
|
||||
: base("Ansikart", "the Artificer")
|
||||
{
|
||||
SetSkill(SkillName.ItemID, 60.0, 83.0);
|
||||
SetSkill(SkillName.Imbuing, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Ansikart(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(MasteringtheSoulforge),
|
||||
typeof(ALittleSomething)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
InitStats(100, 100, 25);
|
||||
|
||||
CantWalk = true;
|
||||
Race = Race.Gargoyle;
|
||||
|
||||
Hue = 0x86DF;
|
||||
HairItemID = 0x425D;
|
||||
HairHue = 0x321;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
AddItem(new SerpentStoneStaff());
|
||||
AddItem(new GargishClothChest(1428));
|
||||
AddItem(new GargishClothArms(1445));
|
||||
AddItem(new GargishClothKilt(1443));
|
||||
}
|
||||
|
||||
public override void Advertise()
|
||||
{
|
||||
this.Say(1112528); // Master the art of unraveling magic.
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
144
Scripts/Mobiles/NPCs/Arabella.cs
Normal file
144
Scripts/Mobiles/NPCs/Arabella.cs
Normal file
@@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class FoldedSteel : BaseCollectionMobile
|
||||
{
|
||||
[Constructable]
|
||||
public FoldedSteel()
|
||||
: base("Arabella", "the samurai")
|
||||
{
|
||||
this.StartTier = 10000000;
|
||||
this.DailyDecay = 100000;
|
||||
|
||||
this.DonationLabel = 1073448; // Folded Steel Section Donation Representative.
|
||||
}
|
||||
|
||||
public FoldedSteel(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Collection CollectionID
|
||||
{
|
||||
get
|
||||
{
|
||||
return Collection.FoldedSteel;
|
||||
}
|
||||
}
|
||||
public override int MaxTier
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x83EA;
|
||||
this.HairItemID = 0x2048;
|
||||
this.HairHue = 0x476;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new NoDachi());
|
||||
this.AddItem(new SamuraiTabi(0x589));
|
||||
this.AddItem(new LeatherSuneate());
|
||||
this.AddItem(new LeatherJingasa());
|
||||
this.AddItem(new LeatherDo());
|
||||
this.AddItem(new LeatherHiroSode());
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
{
|
||||
base.Init();
|
||||
|
||||
this.Donations.Add(new CollectionItem(typeof(Gold), 0xEEF, 1073116, 0x0, 0.06666));
|
||||
this.Donations.Add(new CollectionItem(typeof(BankCheck), 0x14F0, 1075013, 0x34, 0.06666));
|
||||
this.Donations.Add(new CollectionItem(typeof(BrownBook), 0xFEF, 1074906, 0x0, 3));
|
||||
this.Donations.Add(new CollectionItem(typeof(TanBook), 0xFF0, 1074906, 0x0, 3));
|
||||
this.Donations.Add(new CollectionItem(typeof(Bokuto), 0x27A8, 1074913, 0x0, 8));
|
||||
this.Donations.Add(new CollectionItem(typeof(Daisho), 0x27A9, 1074914, 0x0, 22));
|
||||
this.Donations.Add(new CollectionItem(typeof(NoDachi), 0x27A2, 1074915, 0x0, 27));
|
||||
this.Donations.Add(new CollectionItem(typeof(BookOfBushido), 0x238C, 1070814, 0x0, 30));
|
||||
|
||||
int[] hues = new int[] { 0x1E0, 0x190, 0x151 };
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendBodySash), 0x1541, 1073346, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendFeatheredHat), 0x171A, 1073347, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendSurcoat), 0x1FFD, 1073348, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendPants), 0x1539, 1073349, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendCloak), 0x1515, 1073350, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendDoublet), 0x1F7B, 1073351, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendSkirt), 0x1537, 1073352, 0x190, 100000.0, hues));
|
||||
this.Rewards.Add(new CollectionTitle(1073341, 1073859, 100000.0)); // Britain Public Library Contributor
|
||||
|
||||
hues = new int[] { 0x0, 0x1C2, 0x320, 0x190, 0x1E0 };
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendLantern), 0xA25, 1073339, 0x1C2, 200000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(LibraryFriendReadingChair), 0x2DEB, 1073340, 0x1C2, 200000.0, hues));
|
||||
this.Rewards.Add(new CollectionTitle(1073342, 1073860, 200000.0)); // Distinguished Library Contributor
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(SherryTheMouseQuotes), 0xFBD, 1073300, 0x1C2, 350000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(WyrdBeastmasterQuotes), 0xFBD, 1073310, 0x1C2, 350000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(MercenaryJustinQuotes), 0xFBD, 1073317, 0x1C2, 350000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(HeigelOfMoonglowQuotes), 0xFBD, 1073327, 0x1C2, 350000.0, hues));
|
||||
this.Rewards.Add(new CollectionHuedItem(typeof(TraderHoraceQuotes), 0xFBD, 1073338, 0x1C2, 350000.0, hues));
|
||||
this.Rewards.Add(new CollectionTitle(1073343, 1073861, 350000.0)); // Honored Library Contributor
|
||||
this.Rewards.Add(new CollectionItem(typeof(TreatiseonAlchemyTalisman), 0x2F58, 1073353, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(PrimerOnArmsTalisman), 0x2F59, 1073354, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(MyBookTalisman), 0x2F5A, 1073355, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(TalkingtoWispsTalisman), 0x2F5B, 1073356, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(GrammarOfOrchishTalisman), 0x2F59, 1073358, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(BirdsofBritanniaTalisman), 0x2F5A, 1073359, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionItem(typeof(TheLifeOfTravelingMinstrelTalisman), 0x2F5A, 1073360, 0x0, 550000.0));
|
||||
this.Rewards.Add(new CollectionTitle(1073344, 1073862, 550000.0)); // Prominent Library Contributor
|
||||
this.Rewards.Add(new CollectionTitle(1073345, 1073863, 800000.0)); // Eminent Library Contributor
|
||||
this.Rewards.Add(new CollectionItem(typeof(FoldedSteelGlasses), 0x2FB8, 1073380, 0x47E, 800000.0));
|
||||
}
|
||||
|
||||
public override bool CanDonate(PlayerMobile player)
|
||||
{
|
||||
bool can = player.LibraryFriend;
|
||||
|
||||
if (!can)
|
||||
player.SendLocalizedMessage(1074273); // You must speak with Librarian Verity before you can donate to this collection.
|
||||
|
||||
return can;
|
||||
}
|
||||
|
||||
/*public override void IncreaseTier()
|
||||
{
|
||||
base.IncreaseTier();
|
||||
|
||||
List<object> list = new List<object>();
|
||||
Item c;
|
||||
|
||||
switch ( Tier )
|
||||
{
|
||||
}
|
||||
|
||||
if ( list.Count > 0 )
|
||||
Tiers.Add( list );
|
||||
}*/
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
416
Scripts/Mobiles/NPCs/ArcherGuard.cs
Normal file
416
Scripts/Mobiles/NPCs/ArcherGuard.cs
Normal file
@@ -0,0 +1,416 @@
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using Server.Items;
|
||||
#endregion
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class ArcherGuard : BaseGuard
|
||||
{
|
||||
private Timer m_AttackTimer, m_IdleTimer;
|
||||
private Mobile m_Focus;
|
||||
|
||||
[Constructable]
|
||||
public ArcherGuard()
|
||||
: this(null)
|
||||
{ }
|
||||
|
||||
public ArcherGuard(Mobile target)
|
||||
: base(target)
|
||||
{
|
||||
InitStats(100, 125, 25);
|
||||
Title = "the guard";
|
||||
|
||||
SpeechHue = Utility.RandomDyedHue();
|
||||
|
||||
Hue = Utility.RandomSkinHue();
|
||||
|
||||
if (Female = Utility.RandomBool())
|
||||
{
|
||||
Body = 0x191;
|
||||
Name = NameList.RandomName("female");
|
||||
}
|
||||
else
|
||||
{
|
||||
Body = 0x190;
|
||||
Name = NameList.RandomName("male");
|
||||
}
|
||||
|
||||
new Horse().Rider = this;
|
||||
|
||||
AddItem(new StuddedChest());
|
||||
AddItem(new StuddedArms());
|
||||
AddItem(new StuddedGloves());
|
||||
AddItem(new StuddedGorget());
|
||||
AddItem(new StuddedLegs());
|
||||
AddItem(new Boots());
|
||||
AddItem(new SkullCap());
|
||||
|
||||
Bow bow = new Bow();
|
||||
|
||||
bow.Movable = false;
|
||||
bow.Crafter = this;
|
||||
bow.Quality = ItemQuality.Exceptional;
|
||||
|
||||
AddItem(bow);
|
||||
|
||||
Container pack = new Backpack();
|
||||
|
||||
pack.Movable = false;
|
||||
|
||||
Arrow arrows = new Arrow(250);
|
||||
|
||||
arrows.LootType = LootType.Newbied;
|
||||
|
||||
pack.DropItem(arrows);
|
||||
pack.DropItem(new Gold(10, 25));
|
||||
|
||||
AddItem(pack);
|
||||
|
||||
Skills[SkillName.Anatomy].Base = 120.0;
|
||||
Skills[SkillName.Tactics].Base = 120.0;
|
||||
Skills[SkillName.Archery].Base = 120.0;
|
||||
Skills[SkillName.MagicResist].Base = 120.0;
|
||||
Skills[SkillName.DetectHidden].Base = 100.0;
|
||||
|
||||
NextCombatTime = Core.TickCount + 500;
|
||||
Focus = target;
|
||||
}
|
||||
|
||||
public ArcherGuard(Serial serial)
|
||||
: base(serial)
|
||||
{ }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override Mobile Focus
|
||||
{
|
||||
get { return m_Focus; }
|
||||
set
|
||||
{
|
||||
if (Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Mobile oldFocus = m_Focus;
|
||||
|
||||
if (oldFocus != value)
|
||||
{
|
||||
m_Focus = value;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
AggressiveAction(value);
|
||||
}
|
||||
|
||||
Combatant = value;
|
||||
|
||||
if (oldFocus != null && !oldFocus.Alive)
|
||||
{
|
||||
Say("Thou hast suffered thy punishment, scoundrel.");
|
||||
}
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
Say(500131); // Thou wilt regret thine actions, swine!
|
||||
}
|
||||
|
||||
if (m_AttackTimer != null)
|
||||
{
|
||||
m_AttackTimer.Stop();
|
||||
m_AttackTimer = null;
|
||||
}
|
||||
|
||||
if (m_IdleTimer != null)
|
||||
{
|
||||
m_IdleTimer.Stop();
|
||||
m_IdleTimer = null;
|
||||
}
|
||||
|
||||
if (m_Focus != null)
|
||||
{
|
||||
m_AttackTimer = new AttackTimer(this);
|
||||
m_AttackTimer.Start();
|
||||
((AttackTimer)m_AttackTimer).DoOnTick();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_IdleTimer = new IdleTimer(this);
|
||||
m_IdleTimer.Start();
|
||||
}
|
||||
}
|
||||
else if (m_Focus == null && m_IdleTimer == null)
|
||||
{
|
||||
m_IdleTimer = new IdleTimer(this);
|
||||
m_IdleTimer.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnBeforeDeath()
|
||||
{
|
||||
if (m_Focus != null && m_Focus.Alive)
|
||||
{
|
||||
new AvengeTimer(m_Focus).Start(); // If a guard dies, three more guards will spawn
|
||||
}
|
||||
|
||||
return base.OnBeforeDeath();
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(m_Focus);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_Focus = reader.ReadMobile();
|
||||
|
||||
if (m_Focus != null)
|
||||
{
|
||||
m_AttackTimer = new AttackTimer(this);
|
||||
m_AttackTimer.Start();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_IdleTimer = new IdleTimer(this);
|
||||
m_IdleTimer.Start();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
if (m_AttackTimer != null)
|
||||
{
|
||||
m_AttackTimer.Stop();
|
||||
m_AttackTimer = null;
|
||||
}
|
||||
|
||||
if (m_IdleTimer != null)
|
||||
{
|
||||
m_IdleTimer.Stop();
|
||||
m_IdleTimer = null;
|
||||
}
|
||||
|
||||
base.OnAfterDelete();
|
||||
}
|
||||
|
||||
private class AvengeTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Focus;
|
||||
|
||||
public AvengeTimer(Mobile focus)
|
||||
: base(TimeSpan.FromSeconds(2.5), TimeSpan.FromSeconds(1.0), 3)
|
||||
// After 2.5 seconds, one guard will spawn every 1.0 second, three times
|
||||
{
|
||||
m_Focus = focus;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
Spawn(m_Focus, m_Focus, 1, true);
|
||||
}
|
||||
}
|
||||
|
||||
private class AttackTimer : Timer
|
||||
{
|
||||
private readonly ArcherGuard m_Owner;
|
||||
// private bool m_Shooting;
|
||||
public AttackTimer(ArcherGuard owner)
|
||||
: base(TimeSpan.FromSeconds(0.25), TimeSpan.FromSeconds(0.1))
|
||||
{
|
||||
m_Owner = owner;
|
||||
}
|
||||
|
||||
public void DoOnTick()
|
||||
{
|
||||
OnTick();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Owner.Deleted)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
m_Owner.Criminal = false;
|
||||
m_Owner.Kills = 0;
|
||||
m_Owner.Stam = m_Owner.StamMax;
|
||||
|
||||
Mobile target = m_Owner.Focus;
|
||||
|
||||
if (target != null && (target.Deleted || !target.Alive || !m_Owner.CanBeHarmful(target)))
|
||||
{
|
||||
m_Owner.Focus = null;
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
else if (m_Owner.Weapon is Fists)
|
||||
{
|
||||
m_Owner.Kill();
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (target != null && m_Owner.Combatant != target)
|
||||
{
|
||||
m_Owner.Combatant = target;
|
||||
}
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
// <instakill>
|
||||
TeleportTo(target);
|
||||
target.BoltEffect(0);
|
||||
|
||||
if (target is BaseCreature)
|
||||
{
|
||||
((BaseCreature)target).NoKillAwards = true;
|
||||
}
|
||||
|
||||
target.Damage(target.HitsMax, m_Owner);
|
||||
target.Kill(); // just in case, maybe Damage is overriden on some shard
|
||||
|
||||
if (target.Corpse != null && !target.Player)
|
||||
{
|
||||
target.Corpse.Delete();
|
||||
}
|
||||
|
||||
m_Owner.Focus = null;
|
||||
Stop();
|
||||
} // </instakill>
|
||||
/*else if ( !m_Owner.InRange( target, 20 ) )
|
||||
{
|
||||
m_Shooting = false;
|
||||
m_Owner.Focus = null;
|
||||
}
|
||||
else if ( !m_Owner.InLOS( target ) )
|
||||
{
|
||||
m_Shooting = false;
|
||||
TeleportTo( target );
|
||||
}
|
||||
else if ( !m_Owner.CanSee( target ) )
|
||||
{
|
||||
m_Shooting = false;
|
||||
if ( !m_Owner.InRange( target, 2 ) )
|
||||
{
|
||||
if ( !m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ) )
|
||||
TeleportTo( target );
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( !m_Owner.UseSkill( SkillName.DetectHidden ) && Utility.Random( 50 ) == 0 )
|
||||
m_Owner.Say( "Reveal!" );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( m_Shooting && (TimeToSpare() || OutOfMaxDistance( target )) )
|
||||
m_Shooting = false;
|
||||
else if ( !m_Shooting && InMinDistance( target ) )
|
||||
m_Shooting = true;
|
||||
if ( !m_Shooting )
|
||||
{
|
||||
if ( m_Owner.InRange( target, 1 ) )
|
||||
{
|
||||
if ( !m_Owner.Move( (Direction)(m_Owner.GetDirectionTo( target ) - 4) | Direction.Running ) && OutOfMaxDistance( target ) ) // Too close, move away
|
||||
TeleportTo( target );
|
||||
}
|
||||
else if ( !m_Owner.InRange( target, 2 ) )
|
||||
{
|
||||
if ( !m_Owner.Move( m_Owner.GetDirectionTo( target ) | Direction.Running ) && OutOfMaxDistance( target ) )
|
||||
TeleportTo( target );
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private bool TimeToSpare()
|
||||
{
|
||||
return (m_Owner.NextCombatTime - Core.TickCount) > 1000;
|
||||
}
|
||||
|
||||
private bool OutOfMaxDistance(Mobile target)
|
||||
{
|
||||
return !m_Owner.InRange(target, m_Owner.Weapon.MaxRange);
|
||||
}
|
||||
|
||||
private bool InMinDistance(Mobile target)
|
||||
{
|
||||
return m_Owner.InRange(target, 4);
|
||||
}
|
||||
|
||||
private void TeleportTo(Mobile target)
|
||||
{
|
||||
Point3D from = m_Owner.Location;
|
||||
Point3D to = target.Location;
|
||||
|
||||
m_Owner.Location = to;
|
||||
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(from, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023);
|
||||
Effects.SendLocationParticles(EffectItem.Create(to, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 5023);
|
||||
|
||||
m_Owner.PlaySound(0x1FE);
|
||||
}
|
||||
}
|
||||
|
||||
private class IdleTimer : Timer
|
||||
{
|
||||
private readonly ArcherGuard m_Owner;
|
||||
private int m_Stage;
|
||||
|
||||
public IdleTimer(ArcherGuard owner)
|
||||
: base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.5))
|
||||
{
|
||||
m_Owner = owner;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Owner.Deleted)
|
||||
{
|
||||
Stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if ((m_Stage++ % 4) == 0 || !m_Owner.Move(m_Owner.Direction))
|
||||
{
|
||||
m_Owner.Direction = (Direction)Utility.Random(8);
|
||||
}
|
||||
|
||||
if (m_Stage > 16)
|
||||
{
|
||||
Effects.SendLocationParticles(
|
||||
EffectItem.Create(m_Owner.Location, m_Owner.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023);
|
||||
m_Owner.PlaySound(0x1FE);
|
||||
|
||||
m_Owner.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
56
Scripts/Mobiles/NPCs/Architect.cs
Normal file
56
Scripts/Mobiles/NPCs/Architect.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Architect : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Architect()
|
||||
: base("the architect")
|
||||
{
|
||||
}
|
||||
|
||||
public Architect(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override NpcGuild NpcGuild
|
||||
{
|
||||
get
|
||||
{
|
||||
return NpcGuild.TinkersGuild;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
if (!Core.AOS)
|
||||
this.m_SBInfos.Add(new SBHouseDeed());
|
||||
|
||||
this.m_SBInfos.Add(new SBArchitect());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Scripts/Mobiles/NPCs/Arielle.cs
Normal file
53
Scripts/Mobiles/NPCs/Arielle.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class Arielle : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Arielle()
|
||||
: base("Arielle")
|
||||
{
|
||||
this.BaseSoundID = 0x46F;
|
||||
|
||||
this.SetSkill(SkillName.Focus, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Arielle(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(TheJoysOfLifeQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = true;
|
||||
this.Body = 128;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
41
Scripts/Mobiles/NPCs/AriellesBauble.cs
Normal file
41
Scripts/Mobiles/NPCs/AriellesBauble.cs
Normal file
@@ -0,0 +1,41 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class AriellesBauble : Item
|
||||
{
|
||||
[Constructable]
|
||||
public AriellesBauble()
|
||||
: base(0x23B)
|
||||
{
|
||||
this.Weight = 2.0;
|
||||
this.LootType = LootType.Blessed;
|
||||
}
|
||||
|
||||
public AriellesBauble(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override int LabelNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1073137;
|
||||
}
|
||||
}// A bauble
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Scripts/Mobiles/NPCs/Armorer.cs
Normal file
165
Scripts/Mobiles/NPCs/Armorer.cs
Normal file
@@ -0,0 +1,165 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server.Engines.BulkOrders;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Armorer : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
|
||||
[Constructable]
|
||||
public Armorer()
|
||||
: base("the armourer")
|
||||
{
|
||||
SetSkill(SkillName.ArmsLore, 64.0, 100.0);
|
||||
SetSkill(SkillName.Blacksmith, 60.0, 83.0);
|
||||
}
|
||||
|
||||
public Armorer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override VendorShoeType ShoeType
|
||||
{
|
||||
get
|
||||
{
|
||||
return VendorShoeType.Boots;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
switch ( Utility.Random(4))
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
m_SBInfos.Add(new SBLeatherArmor());
|
||||
m_SBInfos.Add(new SBStuddedArmor());
|
||||
m_SBInfos.Add(new SBMetalShields());
|
||||
m_SBInfos.Add(new SBPlateArmor());
|
||||
m_SBInfos.Add(new SBHelmetArmor());
|
||||
m_SBInfos.Add(new SBChainmailArmor());
|
||||
m_SBInfos.Add(new SBRingmailArmor());
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
m_SBInfos.Add(new SBStuddedArmor());
|
||||
m_SBInfos.Add(new SBLeatherArmor());
|
||||
m_SBInfos.Add(new SBMetalShields());
|
||||
m_SBInfos.Add(new SBHelmetArmor());
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
m_SBInfos.Add(new SBMetalShields());
|
||||
m_SBInfos.Add(new SBPlateArmor());
|
||||
m_SBInfos.Add(new SBHelmetArmor());
|
||||
m_SBInfos.Add(new SBChainmailArmor());
|
||||
m_SBInfos.Add(new SBRingmailArmor());
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
m_SBInfos.Add(new SBMetalShields());
|
||||
m_SBInfos.Add(new SBHelmetArmor());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (IsTokunoVendor)
|
||||
{
|
||||
m_SBInfos.Add(new SBSELeatherArmor());
|
||||
m_SBInfos.Add(new SBSEArmor());
|
||||
}
|
||||
}
|
||||
|
||||
#region Bulk Orders
|
||||
public override BODType BODType { get { return BODType.Smith; } }
|
||||
|
||||
public override Item CreateBulkOrder(Mobile from, bool fromContextMenu)
|
||||
{
|
||||
PlayerMobile pm = from as PlayerMobile;
|
||||
|
||||
if (pm != null && pm.NextSmithBulkOrder == TimeSpan.Zero && (fromContextMenu || 0.2 > Utility.RandomDouble()))
|
||||
{
|
||||
double theirSkill = pm.Skills[SkillName.Blacksmith].Base;
|
||||
|
||||
if (theirSkill >= 70.1)
|
||||
pm.NextSmithBulkOrder = TimeSpan.FromHours(6.0);
|
||||
else if (theirSkill >= 50.1)
|
||||
pm.NextSmithBulkOrder = TimeSpan.FromHours(2.0);
|
||||
else
|
||||
pm.NextSmithBulkOrder = TimeSpan.FromHours(1.0);
|
||||
|
||||
if (theirSkill >= 70.1 && ((theirSkill - 40.0) / 300.0) > Utility.RandomDouble())
|
||||
return new LargeSmithBOD();
|
||||
|
||||
return SmallSmithBOD.CreateRandomFor(from);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override bool IsValidBulkOrder(Item item)
|
||||
{
|
||||
return (item is SmallSmithBOD || item is LargeSmithBOD);
|
||||
}
|
||||
|
||||
public override bool SupportsBulkOrders(Mobile from)
|
||||
{
|
||||
return (from is PlayerMobile && from.Skills[SkillName.Blacksmith].Base > 0);
|
||||
}
|
||||
|
||||
public override TimeSpan GetNextBulkOrder(Mobile from)
|
||||
{
|
||||
if (from is PlayerMobile)
|
||||
return ((PlayerMobile)from).NextSmithBulkOrder;
|
||||
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
|
||||
public override void OnSuccessfulBulkOrderReceive(Mobile from)
|
||||
{
|
||||
if (Core.SE && from is PlayerMobile)
|
||||
((PlayerMobile)from).NextSmithBulkOrder = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
base.InitOutfit();
|
||||
|
||||
AddItem(new Server.Items.HalfApron(Utility.RandomYellowHue()));
|
||||
AddItem(new Server.Items.Bascinet());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)1); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
Title = "the armourer";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Scripts/Mobiles/NPCs/Artist.cs
Normal file
79
Scripts/Mobiles/NPCs/Artist.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Artist : BaseCreature
|
||||
{
|
||||
[Constructable]
|
||||
public Artist()
|
||||
: base(AIType.AI_Animal, FightMode.None, 10, 1, 0.2, 0.4)
|
||||
{
|
||||
this.InitStats(31, 41, 51);
|
||||
|
||||
this.SetSkill(SkillName.Healing, 36, 68);
|
||||
|
||||
this.SpeechHue = Utility.RandomDyedHue();
|
||||
this.Title = "the artist";
|
||||
this.Hue = Utility.RandomSkinHue();
|
||||
|
||||
if (this.Female = Utility.RandomBool())
|
||||
{
|
||||
this.Body = 0x191;
|
||||
this.Name = NameList.RandomName("female");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Body = 0x190;
|
||||
this.Name = NameList.RandomName("male");
|
||||
}
|
||||
this.AddItem(new Doublet(Utility.RandomDyedHue()));
|
||||
this.AddItem(new Sandals(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new ShortPants(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new HalfApron(Utility.RandomDyedHue()));
|
||||
|
||||
Utility.AssignRandomHair(this);
|
||||
|
||||
Container pack = new Backpack();
|
||||
|
||||
pack.DropItem(new Gold(250, 300));
|
||||
|
||||
pack.Movable = false;
|
||||
|
||||
this.AddItem(pack);
|
||||
}
|
||||
|
||||
public Artist(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool ClickTitle
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Scripts/Mobiles/NPCs/Asandos.cs
Normal file
168
Scripts/Mobiles/NPCs/Asandos.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Engines.Quests
|
||||
{
|
||||
public class BakersDozenQuest : BaseQuest
|
||||
{
|
||||
public BakersDozenQuest()
|
||||
: base()
|
||||
{
|
||||
this.AddObjective(new ObtainObjective(typeof(CookieMix), "cookie mix", 5, 0x103F));
|
||||
|
||||
this.AddReward(new BaseReward(typeof(ChefsSatchel), 1074282)); // Craftsman's Satchel
|
||||
}
|
||||
|
||||
/* Baker's Dozen */
|
||||
public override object Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075478;
|
||||
}
|
||||
}
|
||||
/* You there! Do you know much about the ways of cooking? If you help me out, I'll show you a thing or two about
|
||||
how it's done. Bring me some cookie mix, about 5 batches will do it, and I will reward you. Although, I don't
|
||||
think you can buy it, you can make some in a snap! First get a rolling pin or frying pan or even a flour sifter.
|
||||
Then you mix one pinch of flour with some water and you've got some dough! Take that dough and add one dollop of
|
||||
honey and you've got sweet dough. add one more drop of honey and you've got cookie mix. See? Nothing to it! Now
|
||||
get to work! */
|
||||
public override object Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075479;
|
||||
}
|
||||
}
|
||||
/* Argh, I absolutely must have more of these 'cookies!' Come back if you change your mind. */
|
||||
public override object Refuse
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075480;
|
||||
}
|
||||
}
|
||||
/* You're not quite done yet. Get back to work! */
|
||||
public override object Uncomplete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1072271;
|
||||
}
|
||||
}
|
||||
/* Thank you! I haven't been this excited about food in months! */
|
||||
public override object Complete
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1075481;
|
||||
}
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class Asandos : MondainQuester
|
||||
{
|
||||
[Constructable]
|
||||
public Asandos()
|
||||
: base("Asandos", "the chef")
|
||||
{
|
||||
}
|
||||
|
||||
public Asandos(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override Type[] Quests
|
||||
{
|
||||
get
|
||||
{
|
||||
return new Type[]
|
||||
{
|
||||
typeof(BakersDozenQuest)
|
||||
};
|
||||
}
|
||||
}
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.CantWalk = true;
|
||||
this.Race = Race.Human;
|
||||
|
||||
this.Hue = 0x83FF;
|
||||
this.HairItemID = 0x2044;
|
||||
this.HairHue = 0x1;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Backpack());
|
||||
this.AddItem(new Boots(0x901));
|
||||
this.AddItem(new ShortPants());
|
||||
this.AddItem(new Shirt());
|
||||
this.AddItem(new Cap());
|
||||
this.AddItem(new HalfApron(0x28));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class ChefsSatchel : Backpack
|
||||
{
|
||||
[Constructable]
|
||||
public ChefsSatchel()
|
||||
: base()
|
||||
{
|
||||
this.Hue = BaseReward.SatchelHue();
|
||||
|
||||
this.AddItem(new SackFlour());
|
||||
this.AddItem(new Skillet());
|
||||
}
|
||||
|
||||
public ChefsSatchel(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Scripts/Mobiles/NPCs/Athialon.cs
Normal file
98
Scripts/Mobiles/NPCs/Athialon.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class Athialon : BaseVendor
|
||||
{
|
||||
private readonly List<SBInfo> m_SBInfos = new List<SBInfo>();
|
||||
[Constructable]
|
||||
public Athialon()
|
||||
: base("the expeditionist")
|
||||
{
|
||||
this.Name = "Athialon";
|
||||
}
|
||||
|
||||
public Athialon(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool CanTeach
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool IsInvulnerable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
protected override List<SBInfo> SBInfos
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SBInfos;
|
||||
}
|
||||
}
|
||||
public override void InitSBInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.InitStats(100, 100, 25);
|
||||
|
||||
this.Female = false;
|
||||
this.Race = Race.Elf;
|
||||
|
||||
this.Hue = 0x8382;
|
||||
this.HairItemID = 0x2FC0;
|
||||
this.HairHue = 0x35;
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots(0x901));
|
||||
this.AddItem(new DiamondMace());
|
||||
this.AddItem(new WoodlandBelt());
|
||||
|
||||
Item item;
|
||||
|
||||
item = new WoodlandLegs();
|
||||
item.Hue = 0x3B2;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new WoodlandChest();
|
||||
item.Hue = 0x3B2;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new WoodlandArms();
|
||||
item.Hue = 0x3B2;
|
||||
this.AddItem(item);
|
||||
|
||||
item = new WingedHelm();
|
||||
item.Hue = 0x3B2;
|
||||
this.AddItem(item);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write((int)0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
200
Scripts/Mobiles/NPCs/AttendantFortuneTeller.cs
Normal file
200
Scripts/Mobiles/NPCs/AttendantFortuneTeller.cs
Normal file
@@ -0,0 +1,200 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class AttendantFortuneTeller : PersonalAttendant
|
||||
{
|
||||
[Constructable]
|
||||
public AttendantFortuneTeller()
|
||||
: this(false)
|
||||
{
|
||||
}
|
||||
|
||||
[Constructable]
|
||||
public AttendantFortuneTeller(bool female)
|
||||
: base("the Fortune Teller")
|
||||
{
|
||||
this.Female = female;
|
||||
}
|
||||
|
||||
public AttendantFortuneTeller(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
{
|
||||
from.CloseGump(typeof(InternalGump));
|
||||
from.SendGump(new InternalGump(this));
|
||||
}
|
||||
else
|
||||
base.OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
list.Add(new AttendantUseEntry(this, 6245));
|
||||
|
||||
base.AddCustomContextEntries(from, list);
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.SetStr(50, 60);
|
||||
this.SetDex(20, 30);
|
||||
this.SetInt(100, 110);
|
||||
|
||||
this.Name = NameList.RandomName("female");
|
||||
this.Female = true;
|
||||
this.Race = Race.Human;
|
||||
this.Hue = this.Race.RandomSkinHue();
|
||||
|
||||
Utility.AssignRandomHair(this, Utility.RandomHairHue());
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Shoes(Utility.RandomPinkHue()));
|
||||
this.AddItem(new Shirt(Utility.RandomPinkHue()));
|
||||
this.AddItem(new SkullCap(Utility.RandomPinkHue()));
|
||||
|
||||
if (Utility.RandomBool())
|
||||
this.AddItem(new Kilt(Utility.RandomPinkHue()));
|
||||
else
|
||||
this.AddItem(new Skirt(Utility.RandomPinkHue()));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
|
||||
private class InternalGump : Gump
|
||||
{
|
||||
private readonly AttendantFortuneTeller m_Teller;
|
||||
public InternalGump(AttendantFortuneTeller teller)
|
||||
: base(200, 200)
|
||||
{
|
||||
this.m_Teller = teller;
|
||||
|
||||
this.AddPage(0);
|
||||
|
||||
this.AddBackground(0, 0, 291, 155, 0x13BE);
|
||||
this.AddImageTiled(5, 6, 280, 20, 0xA40);
|
||||
this.AddHtmlLocalized(9, 8, 280, 20, 1075994, 0x7FFF, false, false); // Fortune Teller
|
||||
this.AddImageTiled(5, 31, 280, 91, 0xA40);
|
||||
this.AddHtmlLocalized(9, 35, 280, 40, 1076025, 0x7FFF, false, false); // Ask your question
|
||||
this.AddImageTiled(9, 55, 270, 20, 0xDB0);
|
||||
this.AddImageTiled(10, 55, 270, 2, 0x23C5);
|
||||
this.AddImageTiled(9, 55, 2, 20, 0x23C3);
|
||||
this.AddImageTiled(9, 75, 270, 2, 0x23C5);
|
||||
this.AddImageTiled(279, 55, 2, 22, 0x23C3);
|
||||
|
||||
this.AddTextEntry(12, 56, 263, 17, 0xA28, 15, "");
|
||||
|
||||
this.AddButton(5, 129, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(40, 131, 100, 20, 1060051, 0x7FFF, false, false); // CANCEL
|
||||
|
||||
this.AddButton(190, 129, 0xFB7, 0xFB8, 1, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(225, 131, 100, 20, 1006044, 0x7FFF, false, false); // OK
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Teller == null || this.m_Teller.Deleted)
|
||||
return;
|
||||
|
||||
if (info.ButtonID == 1)
|
||||
{
|
||||
TextRelay text = info.GetTextEntry(15);
|
||||
|
||||
if (text != null && !String.IsNullOrEmpty(text.Text))
|
||||
{
|
||||
sender.Mobile.CloseGump(typeof(FortuneGump));
|
||||
sender.Mobile.SendGump(new FortuneGump(text.Text));
|
||||
}
|
||||
else
|
||||
sender.Mobile.SendGump(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FortuneGump : Gump
|
||||
{
|
||||
public FortuneGump(string text)
|
||||
: base(200, 200)
|
||||
{
|
||||
this.AddPage(0);
|
||||
|
||||
this.AddImage(0, 0, 0x7724);
|
||||
|
||||
int one, two, three;
|
||||
|
||||
one = Utility.RandomMinMax(1, 19);
|
||||
two = Utility.RandomMinMax(one + 1, 20);
|
||||
three = Utility.RandomMinMax(0, one - 1);
|
||||
|
||||
this.AddImageTiled(28, 140, 115, 180, 0x7725 + one);
|
||||
this.AddTooltip(this.GetTooltip(one));
|
||||
this.AddHtmlLocalized(28, 115, 125, 20, 1076079, 0x7FFF, false, false); // The Past
|
||||
this.AddImageTiled(171, 140, 115, 180, 0x7725 + two);
|
||||
this.AddTooltip(this.GetTooltip(two));
|
||||
this.AddHtmlLocalized(171, 115, 125, 20, 1076081, 0x7FFF, false, false); // The Question
|
||||
this.AddImageTiled(314, 140, 115, 180, 0x7725 + three);
|
||||
this.AddTooltip(this.GetTooltip(three));
|
||||
this.AddHtmlLocalized(314, 115, 125, 20, 1076080, 0x7FFF, false, false); // The Future
|
||||
|
||||
this.AddHtml(30, 32, 400, 25, text, true, false);
|
||||
}
|
||||
|
||||
private int GetTooltip(int number)
|
||||
{
|
||||
if (number > 9)
|
||||
return 1076015 + number - 10;
|
||||
|
||||
switch ( number )
|
||||
{
|
||||
case 0:
|
||||
return 1076063;
|
||||
case 1:
|
||||
return 1076060;
|
||||
case 2:
|
||||
return 1076061;
|
||||
case 3:
|
||||
return 1076057;
|
||||
case 4:
|
||||
return 1076062;
|
||||
case 5:
|
||||
return 1076059;
|
||||
case 6:
|
||||
return 1076058;
|
||||
case 7:
|
||||
return 1076065;
|
||||
case 8:
|
||||
return 1076064;
|
||||
case 9:
|
||||
return 1076066;
|
||||
}
|
||||
|
||||
return 1052009; // I have seen the error of my ways!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1011
Scripts/Mobiles/NPCs/AttendantGuide.cs
Normal file
1011
Scripts/Mobiles/NPCs/AttendantGuide.cs
Normal file
File diff suppressed because it is too large
Load Diff
701
Scripts/Mobiles/NPCs/AttendantHerald.cs
Normal file
701
Scripts/Mobiles/NPCs/AttendantHerald.cs
Normal file
@@ -0,0 +1,701 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Multis;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class AttendantHerald : PersonalAttendant
|
||||
{
|
||||
private static readonly HeraldEntry[] m_Announcements = new HeraldEntry[]
|
||||
{
|
||||
new HeraldEntry(1076044, "[OWNER TITLE]", "[OWNER NAME]"), // Attention, attention! All hail the arrival of the ~1_TITLE~ ~2_NAME~!
|
||||
new HeraldEntry(1076045, "[OWNER TITLE]", "[OWNER NAME]"), // Make way ye unwashed hordes! Clear the road! For ~1_TITLE~ ~2_NAME~ has business more important than yours!
|
||||
new HeraldEntry(1076046, "[OWNER TITLE]", "[OWNER NAME]"), // ~1_TITLE~ ~2_NAME~ approaches! Be ye prepared to kneel before their indomitable presence! And remember, tribute is to be only in gold!
|
||||
new HeraldEntry(1076047, "[OWNER TITLE]", "[OWNER NAME]"), // Throw down your capes and kerchiefs! Let the petals be strewn! For the ~1_TITLE~ ~2_NAME~ approacheth!
|
||||
new HeraldEntry(1076048, "[OWNER TITLE]", "[OWNER NAME]"), // ~1_TITLE~ ~2_NAME~ has arrived! Let the drinks flow! Let the festivities commence! And you there, with the pig, get that beast on a skewer!
|
||||
new HeraldEntry(1076049, "[OWNER SEX P]", "[OWNER OPPOSITE SEX P]", "[OWNER TITLE]", "[OWNER NAME]")// Let the ~1_SAME_SEX~ cower and the ~2_OPPOSITE_SEX~ swoon, for now approaches the ~3_TITLE~ ~4_NAME~.
|
||||
};
|
||||
private static readonly HeraldEntry[] m_Greetings = new HeraldEntry[]
|
||||
{
|
||||
new HeraldEntry(1076038, "[OWNER NAME]"), // Welcome to the home of ~1_OWNER_NAME~. Please keep your shoes off the furniture.
|
||||
new HeraldEntry(1076039, "[VISITOR TITLE]", "[VISITOR NAME]", "[OWNER SEX]"), // Announcing the arrival of the ~1_VISITOR_TITLE~ ~2_VISITOR_NAME~. The ~3_OWNER_SEX~ of the house bids you welcome.
|
||||
new HeraldEntry(1076040, "[OWNER SEX]","[VISITOR TITLE]", "[VISITOR NAME]"), // My ~1_OWNER_SEX~, you have a visitor! ~2_VISITOR_TITLE~ ~3_VISITOR_NAME~ is awaiting your presence.
|
||||
new HeraldEntry(1076041, "[OWNER TITLE]", "[OWNER NAME]"), // Welcome the the humble abode of ~1_OWNER_TITLE~ ~2_OWNER_NAME~, please remove your shoes, and have a seat where you may find one.
|
||||
new HeraldEntry(1076042, "[VISITOR TITLE]", "[VISITOR NAME]"), // Ahh, greetings to ~1_VISITOR_TITLE~ ~2_VISITOR_NAME~. Your coming here was foreseen, and I alone know of your purpose.
|
||||
new HeraldEntry(1076043), // *squints* Not you again! Fine, fine... whatever... come on in, I suppose. *sighs*
|
||||
new HeraldEntry(1076074, "[OWNER TITLE]", "[OWNER NAME]"), // Welcome to this humble marketplace. If you need any assistance ~1_OWNER_TITLE~ ~2_OWNER_NAME~ will be glad to help you.
|
||||
new HeraldEntry(1076075, "[OWNER TITLE]", "[OWNER NAME]"), // Come Friend! Enter ~1_OWNER_TITLE~ ~2_OWNER_NAME~'s wondrous shop of many things! If you can't find it here, I suggest you go somewhere else!
|
||||
new HeraldEntry(1076076, "[VISITOR NAME]")// *Looks ~1_VISITOR_NAME~ over with narrowed eyes, scowling, and points to the sign on the wall* "Reagents for spell casting only, Please do not eat!"
|
||||
};
|
||||
private HeraldEntry m_Announcement;
|
||||
private HeraldEntry m_Greeting;
|
||||
private DateTime m_NextYell;
|
||||
private BaseHouse m_House;
|
||||
private Point3D m_Location;
|
||||
public AttendantHerald()
|
||||
: base("the Herald")
|
||||
{
|
||||
this.m_Announcement = m_Announcements[0];
|
||||
this.m_Greeting = m_Greetings[0];
|
||||
|
||||
this.m_NextYell = DateTime.UtcNow;
|
||||
this.m_House = null;
|
||||
this.m_Location = Point3D.Zero;
|
||||
}
|
||||
|
||||
public AttendantHerald(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual TimeSpan YellDelay
|
||||
{
|
||||
get
|
||||
{
|
||||
return TimeSpan.FromSeconds(15);
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public HeraldEntry Announcement
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Announcement;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Announcement = value;
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public HeraldEntry Greeting
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Greeting;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Greeting = value;
|
||||
}
|
||||
}
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
{
|
||||
from.CloseGump(typeof(OptionsGump));
|
||||
from.SendGump(new OptionsGump(this));
|
||||
}
|
||||
else
|
||||
base.OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
{
|
||||
list.Add(new AttendantUseEntry(this, 6248));
|
||||
list.Add(new HeraldSetAnnouncementTextEntry(this));
|
||||
list.Add(new HeraldSetGreetingTextEntry(this));
|
||||
list.Add(new AttendantDismissEntry(this));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMovement(Mobile m, Point3D oldLocation)
|
||||
{
|
||||
base.OnMovement(m, oldLocation);
|
||||
|
||||
if (m != null && m.Player && !m.Hidden && m != this)
|
||||
{
|
||||
if (this.ControlOrder == OrderType.Follow && this.m_NextYell < DateTime.UtcNow && m != this.ControlMaster && this.m_Announcement != null)
|
||||
{
|
||||
this.m_Announcement.Say(this, m);
|
||||
this.m_NextYell = DateTime.UtcNow + this.YellDelay + TimeSpan.FromSeconds(Utility.RandomMinMax(-2, 2));
|
||||
}
|
||||
else if (this.ControlOrder == OrderType.Stay && this.m_Greeting != null)
|
||||
{
|
||||
if (this.m_Location != this.Location)
|
||||
{
|
||||
this.m_House = BaseHouse.FindHouseAt(this);
|
||||
this.m_Location = this.Location;
|
||||
}
|
||||
|
||||
if (this.m_House != null && !this.m_House.IsInside(oldLocation, 16) && this.m_House.IsInside(m))
|
||||
this.m_Greeting.Say(this, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool InGreetingMode(Mobile owner)
|
||||
{
|
||||
if (this.m_Location != this.Location)
|
||||
{
|
||||
this.m_House = BaseHouse.FindHouseAt(this);
|
||||
this.m_Location = this.Location;
|
||||
}
|
||||
|
||||
return (this.m_House != null && this.m_House.IsOwner(owner) && this.ControlOrder == OrderType.Stay);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
writer.Write(this.m_Announcement != null);
|
||||
|
||||
if (this.m_Announcement != null)
|
||||
this.m_Announcement.Serialize(writer);
|
||||
|
||||
writer.Write(this.m_Greeting != null);
|
||||
|
||||
if (this.m_Greeting != null)
|
||||
this.m_Greeting.Serialize(writer);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
this.m_Announcement = new HeraldEntry();
|
||||
this.m_Announcement.Deserialize(reader);
|
||||
}
|
||||
|
||||
if (reader.ReadBool())
|
||||
{
|
||||
this.m_Greeting = new HeraldEntry();
|
||||
this.m_Greeting.Deserialize(reader);
|
||||
}
|
||||
|
||||
this.m_Location = Point3D.Zero;
|
||||
}
|
||||
|
||||
public virtual void SetAnnouncementText(Mobile by)
|
||||
{
|
||||
by.SendGump(new SetTextGump(this, m_Announcements, true));
|
||||
}
|
||||
|
||||
public virtual void SetGreetingText(Mobile by)
|
||||
{
|
||||
by.SendGump(new SetTextGump(this, m_Greetings, false));
|
||||
}
|
||||
|
||||
[PropertyObject]
|
||||
public class HeraldEntry
|
||||
{
|
||||
private TextDefinition m_Message;
|
||||
private string[] m_Arguments;
|
||||
public HeraldEntry()
|
||||
: this(null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public HeraldEntry(TextDefinition message)
|
||||
: this(message, null)
|
||||
{
|
||||
}
|
||||
|
||||
public HeraldEntry(TextDefinition message, params string[] args)
|
||||
{
|
||||
this.m_Message = message;
|
||||
this.m_Arguments = args;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public TextDefinition Message
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Message;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Message = value;
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public string Arguments
|
||||
{
|
||||
get
|
||||
{
|
||||
string text = String.Empty;
|
||||
|
||||
foreach (string s in this.m_Arguments)
|
||||
text += '|' + s;
|
||||
|
||||
return text + '|';
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value != null)
|
||||
this.m_Arguments = value.Split('|');
|
||||
else
|
||||
this.m_Arguments = null;
|
||||
}
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.m_Message != null)
|
||||
return this.m_Message.ToString();
|
||||
|
||||
return base.ToString();
|
||||
}
|
||||
|
||||
public void Say(AttendantHerald herald, Mobile visitor)
|
||||
{
|
||||
if (this.m_Message.Number > 0)
|
||||
{
|
||||
herald.Say(this.m_Message.Number, this.ConstructNumber(herald, visitor));
|
||||
}
|
||||
else if (this.m_Message.String != null)
|
||||
{
|
||||
herald.Say(this.ConstructString(herald, visitor));
|
||||
}
|
||||
}
|
||||
|
||||
public GumpEntry Construct(AttendantHerald herald, int x, int y, int width, int height, int color)
|
||||
{
|
||||
if (this.m_Message.Number > 0)
|
||||
{
|
||||
string args = this.ConstructNumber(herald, null);
|
||||
|
||||
return new GumpHtmlLocalized(x, y, width, height, this.m_Message.Number, args, color, false, false);
|
||||
}
|
||||
else if (this.m_Message.String != null)
|
||||
{
|
||||
string message = String.Format("<BASEFONT COLOR=#{0:X6}>{1}</BASEFONT>", color, this.ConstructString(herald, null));
|
||||
|
||||
return new GumpHtml(x, y, width, height, message, false, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string ConstructNumber(AttendantHerald herald, Mobile visitor)
|
||||
{
|
||||
string args = String.Empty;
|
||||
|
||||
if (this.m_Arguments != null && this.m_Arguments.Length > 0)
|
||||
{
|
||||
args = this.Construct(herald, visitor, this.m_Arguments[0]);
|
||||
|
||||
for (int i = 1; i < this.m_Arguments.Length; i++)
|
||||
args = String.Format("{0}\t{1}", args, this.Construct(herald, visitor, this.m_Arguments[i]));
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
public string ConstructString(AttendantHerald herald, Mobile visitor)
|
||||
{
|
||||
string message = this.m_Message.String;
|
||||
|
||||
if (this.m_Arguments != null && this.m_Arguments.Length > 0)
|
||||
{
|
||||
string[] args = new string[this.m_Arguments.Length];
|
||||
|
||||
for (int i = 0; i < args.Length; i++)
|
||||
args[i] = this.Construct(herald, visitor, this.m_Arguments[i]);
|
||||
|
||||
message = String.Format(message, args);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
public string Construct(AttendantHerald herald, Mobile visitor, string argument)
|
||||
{
|
||||
if (herald == null || herald.Deleted || herald.ControlMaster == null)
|
||||
return String.Empty;
|
||||
|
||||
Mobile m = herald.ControlMaster;
|
||||
|
||||
switch ( argument )
|
||||
{
|
||||
case "[OWNER TITLE]":
|
||||
return "Mighty";
|
||||
case "[OWNER NAME]":
|
||||
return m.Name;
|
||||
case "[OWNER SEX]":
|
||||
return m.Female ? "lady" : "lord";
|
||||
case "[OWNER OPPOSITE SEX]":
|
||||
return m.Female ? "lord" : "lady";
|
||||
case "[OWNER SEX P]":
|
||||
return m.Female ? "ladies" : "lords";
|
||||
case "[OWNER OPPOSITE SEX P]":
|
||||
return m.Female ? "lords" : "ladies";
|
||||
case "[VISITOR TITLE]":
|
||||
return visitor != null ? "Mighty" : argument;
|
||||
case "[VISITOR NAME]":
|
||||
return visitor != null ? visitor.Name : argument;
|
||||
}
|
||||
|
||||
return String.Empty;
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.WriteEncodedInt(0); // version
|
||||
|
||||
if (this.m_Message.Number > 0)
|
||||
{
|
||||
writer.Write((byte)0x1);
|
||||
writer.Write(this.m_Message.Number);
|
||||
}
|
||||
else if (this.m_Message.String != null)
|
||||
{
|
||||
writer.Write((byte)0x2);
|
||||
writer.Write(this.m_Message.String);
|
||||
}
|
||||
else
|
||||
writer.Write((byte)0x0);
|
||||
|
||||
if (this.m_Arguments != null)
|
||||
{
|
||||
writer.WriteEncodedInt(this.m_Arguments.Length);
|
||||
|
||||
foreach (string s in this.m_Arguments)
|
||||
writer.Write(s);
|
||||
}
|
||||
else
|
||||
writer.WriteEncodedInt(0);
|
||||
}
|
||||
|
||||
public void Deserialize(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadEncodedInt();
|
||||
|
||||
byte type = reader.ReadByte();
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case 0x1:
|
||||
this.m_Message = reader.ReadInt();
|
||||
break;
|
||||
case 0x2:
|
||||
this.m_Message = reader.ReadString();
|
||||
break;
|
||||
}
|
||||
|
||||
this.m_Arguments = new string[reader.ReadEncodedInt()];
|
||||
|
||||
for (int i = 0; i < this.m_Arguments.Length; i++)
|
||||
this.m_Arguments[i] = reader.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
private class OptionsGump : Gump
|
||||
{
|
||||
private readonly AttendantHerald m_Herald;
|
||||
public OptionsGump(AttendantHerald herald)
|
||||
: base(200, 200)
|
||||
{
|
||||
this.m_Herald = herald;
|
||||
|
||||
this.AddBackground(0, 0, 273, 324, 0x13BE);
|
||||
this.AddImageTiled(10, 10, 253, 20, 0xA40);
|
||||
this.AddImageTiled(10, 40, 253, 244, 0xA40);
|
||||
this.AddImageTiled(10, 294, 253, 20, 0xA40);
|
||||
this.AddAlphaRegion(10, 10, 253, 304);
|
||||
this.AddButton(10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF, false, false); // CANCEL
|
||||
this.AddHtmlLocalized(14, 12, 273, 20, 1075996, 0x7FFF, false, false); // Herald
|
||||
|
||||
this.AddButton(15, 45, 0x845, 0x846, 3, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 43, 450, 20, 3006247, 0x7FFF, false, false); // Set Announcement Text
|
||||
|
||||
this.AddButton(15, 65, 0x845, 0x846, 4, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 63, 450, 20, 3006246, 0x7FFF, false, false); // Set Greeting Text
|
||||
|
||||
if (herald.ControlOrder == OrderType.Stay)
|
||||
{
|
||||
this.AddHtmlLocalized(45, 83, 450, 20, 1076138, 0x7D32, false, false); // Stay here and greet guests
|
||||
|
||||
this.AddButton(15, 105, 0x845, 0x846, 6, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 103, 450, 20, 1076139, 0x7FFF, false, false); // Follow me
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AddButton(15, 85, 0x845, 0x846, 5, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 83, 450, 20, 1076138, 0x7FFF, false, false); // Stay here and greet guests
|
||||
|
||||
this.AddHtmlLocalized(45, 103, 450, 20, 1076139, 0x7D32, false, false); // Follow me
|
||||
this.AddTooltip(1076141); // You can only issue this command when your herald is in greeting mode.
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Herald == null || this.m_Herald.Deleted)
|
||||
return;
|
||||
|
||||
Mobile m = sender.Mobile;
|
||||
|
||||
switch ( info.ButtonID )
|
||||
{
|
||||
case 3:
|
||||
this.m_Herald.SetAnnouncementText(m);
|
||||
break;
|
||||
case 4:
|
||||
this.m_Herald.SetGreetingText(m);
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
if (this.m_Herald.ControlOrder == OrderType.Follow)
|
||||
{
|
||||
BaseHouse house = BaseHouse.FindHouseAt(this.m_Herald);
|
||||
|
||||
if (house != null && house.IsOwner(m))
|
||||
{
|
||||
this.m_Herald.ControlOrder = OrderType.Stay;
|
||||
this.m_Herald.ControlTarget = null;
|
||||
}
|
||||
else
|
||||
m.SendLocalizedMessage(1076140); // You must be in a house you control to put your herald into greeting mode.
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
if (this.m_Herald.ControlOrder == OrderType.Stay)
|
||||
{
|
||||
this.m_Herald.ControlOrder = OrderType.Follow;
|
||||
this.m_Herald.ControlTarget = m;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SetTextGump : Gump
|
||||
{
|
||||
private readonly AttendantHerald m_Herald;
|
||||
private readonly HeraldEntry[] m_Entries;
|
||||
private readonly bool m_Announcement;
|
||||
public SetTextGump(AttendantHerald herald, HeraldEntry[] entries, bool announcement)
|
||||
: base(60, 36)
|
||||
{
|
||||
this.m_Herald = herald;
|
||||
this.m_Entries = entries;
|
||||
this.m_Announcement = announcement;
|
||||
|
||||
this.AddPage(0);
|
||||
|
||||
this.AddBackground(0, 0, 520, 324, 0x13BE);
|
||||
this.AddImageTiled(10, 10, 500, 20, 0xA40);
|
||||
this.AddImageTiled(10, 40, 500, 244, 0xA40);
|
||||
this.AddImageTiled(10, 294, 500, 20, 0xA40);
|
||||
this.AddAlphaRegion(10, 10, 500, 304);
|
||||
this.AddButton(10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 296, 450, 20, 1060051, 0x7FFF, false, false); // CANCEL
|
||||
this.AddHtmlLocalized(14, 12, 520, 20, 3006246 + (announcement ? 1 : 0), 0x7FFF, false, false); // Set Announcement/Greeting Text
|
||||
|
||||
for (int i = 0; i < entries.Length; i++)
|
||||
{
|
||||
if (i % 5 == 0)
|
||||
{
|
||||
int page = i / 5 + 1;
|
||||
|
||||
if (page > 1)
|
||||
{
|
||||
this.AddButton(435, 294, 0xFA5, 0xFA7, 0, GumpButtonType.Page, page);
|
||||
this.AddHtmlLocalized(475, 296, 60, 20, 1043353, 0x7FFF, false, false); // Next
|
||||
}
|
||||
|
||||
this.AddPage(page);
|
||||
|
||||
if (page > 1)
|
||||
{
|
||||
this.AddButton(360, 294, 0xFAE, 0xFB0, 0, GumpButtonType.Page, page - 1);
|
||||
this.AddHtmlLocalized(400, 296, 60, 20, 1011393, 0x7FFF, false, false); // Back
|
||||
}
|
||||
}
|
||||
|
||||
this.AddButton(19, 49 + (i % 5) * 48, 0x845, 0x846, 100 + i, GumpButtonType.Reply, 0);
|
||||
this.Add(entries[i].Construct(herald, 44, 47 + (i % 5) * 48, 460, 40, 0x7FFF));
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Herald == null || this.m_Herald.Deleted)
|
||||
return;
|
||||
|
||||
int index = info.ButtonID - 100;
|
||||
|
||||
if (index >= 0 && index < this.m_Entries.Length)
|
||||
{
|
||||
HeraldEntry entry = this.m_Entries[index];
|
||||
|
||||
if (this.m_Announcement)
|
||||
{
|
||||
this.m_Herald.Announcement = entry;
|
||||
sender.Mobile.SendLocalizedMessage(1076686); // Your herald's announcement has been changed.
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_Herald.Greeting = entry;
|
||||
sender.Mobile.SendLocalizedMessage(1076687); // Your herald's greeting has been changed.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AttendantMaleHerald : AttendantHerald
|
||||
{
|
||||
[Constructable]
|
||||
public AttendantMaleHerald()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public AttendantMaleHerald(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.SetStr(50, 60);
|
||||
this.SetDex(20, 30);
|
||||
this.SetInt(100, 110);
|
||||
|
||||
this.Name = NameList.RandomName("male");
|
||||
this.Female = false;
|
||||
this.Race = Race.Human;
|
||||
this.Hue = this.Race.RandomSkinHue();
|
||||
|
||||
this.HairItemID = this.Race.RandomHair(this.Female);
|
||||
this.HairHue = this.Race.RandomHairHue();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new FurBoots());
|
||||
this.AddItem(new LongPants(0x901));
|
||||
this.AddItem(new TricorneHat());
|
||||
this.AddItem(new FormalShirt(Utility.RandomBlueHue()));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AttendantFemaleHerald : AttendantHerald
|
||||
{
|
||||
[Constructable]
|
||||
public AttendantFemaleHerald()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public AttendantFemaleHerald(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.SetStr(50, 60);
|
||||
this.SetDex(20, 30);
|
||||
this.SetInt(100, 110);
|
||||
|
||||
this.Name = NameList.RandomName("female");
|
||||
this.Female = true;
|
||||
this.Race = Race.Human;
|
||||
this.Hue = this.Race.RandomSkinHue();
|
||||
|
||||
this.HairItemID = this.Race.RandomHair(this.Female);
|
||||
this.HairHue = this.Race.RandomHairHue();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
Lantern lantern = new Lantern();
|
||||
lantern.Ignite();
|
||||
|
||||
this.AddItem(lantern);
|
||||
this.AddItem(new Shoes(Utility.RandomNeutralHue()));
|
||||
this.AddItem(new Bonnet(Utility.RandomPinkHue()));
|
||||
this.AddItem(new PlainDress(Utility.RandomPinkHue()));
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
public class HeraldSetAnnouncementTextEntry : ContextMenuEntry
|
||||
{
|
||||
private readonly AttendantHerald m_Attendant;
|
||||
public HeraldSetAnnouncementTextEntry(AttendantHerald attendant)
|
||||
: base(6247)
|
||||
{
|
||||
this.m_Attendant = attendant;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if (this.m_Attendant == null || this.m_Attendant.Deleted)
|
||||
return;
|
||||
|
||||
this.m_Attendant.SetAnnouncementText(this.Owner.From);
|
||||
}
|
||||
}
|
||||
|
||||
public class HeraldSetGreetingTextEntry : ContextMenuEntry
|
||||
{
|
||||
private readonly AttendantHerald m_Attendant;
|
||||
public HeraldSetGreetingTextEntry(AttendantHerald attendant)
|
||||
: base(6246)
|
||||
{
|
||||
this.m_Attendant = attendant;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if (this.m_Attendant == null || this.m_Attendant.Deleted)
|
||||
return;
|
||||
|
||||
this.m_Attendant.SetGreetingText(this.Owner.From);
|
||||
}
|
||||
}
|
||||
}
|
||||
265
Scripts/Mobiles/NPCs/AttendantLuckyDealer.cs
Normal file
265
Scripts/Mobiles/NPCs/AttendantLuckyDealer.cs
Normal file
@@ -0,0 +1,265 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.ContextMenus;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class AttendantLuckyDealer : PersonalAttendant
|
||||
{
|
||||
private DateTime m_NextUse;
|
||||
private int m_Count;
|
||||
public AttendantLuckyDealer()
|
||||
: base("the Lucky Dealer")
|
||||
{
|
||||
}
|
||||
|
||||
public AttendantLuckyDealer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
{
|
||||
from.CloseGump(typeof(InternalGump));
|
||||
from.SendGump(new InternalGump(this));
|
||||
}
|
||||
else
|
||||
base.OnDoubleClick(from);
|
||||
}
|
||||
|
||||
public override void AddCustomContextEntries(Mobile from, List<ContextMenuEntry> list)
|
||||
{
|
||||
if (from.Alive && this.IsOwner(from))
|
||||
list.Add(new AttendantUseEntry(this, 6244));
|
||||
|
||||
base.AddCustomContextEntries(from, list);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
|
||||
private class InternalGump : Gump
|
||||
{
|
||||
private readonly AttendantLuckyDealer m_Dealer;
|
||||
public InternalGump(AttendantLuckyDealer dealer)
|
||||
: this(dealer, 1, 4)
|
||||
{
|
||||
}
|
||||
|
||||
public InternalGump(AttendantLuckyDealer dealer, int dice, int faces)
|
||||
: base(60, 36)
|
||||
{
|
||||
this.m_Dealer = dealer;
|
||||
|
||||
this.AddHtmlLocalized(14, 12, 273, 20, 1075995, 0x7FFF, false, false); // Lucky Dealer
|
||||
|
||||
this.AddPage(0);
|
||||
|
||||
this.AddBackground(0, 0, 273, 324, 0x13BE);
|
||||
this.AddImageTiled(10, 10, 253, 20, 0xA40);
|
||||
this.AddImageTiled(10, 40, 253, 244, 0xA40);
|
||||
this.AddImageTiled(10, 294, 253, 20, 0xA40);
|
||||
this.AddAlphaRegion(10, 10, 253, 304);
|
||||
this.AddButton(10, 294, 0xFB1, 0xFB2, 0, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(45, 294, 80, 20, 1060051, 0x7FFF, false, false); // CANCEL
|
||||
this.AddButton(130, 294, 0xFB7, 0xFB9, 1, GumpButtonType.Reply, 0);
|
||||
this.AddHtmlLocalized(165, 294, 80, 20, 1076002, 0x7FFF, false, false); // Roll
|
||||
|
||||
this.AddHtmlLocalized(14, 50, 120, 20, 1076000, 0x7FFF, false, false); // Number of dice
|
||||
this.AddGroup(0);
|
||||
this.AddRadio(14, 70, 0xD2, 0xD3, dice == 1, 1001);
|
||||
this.AddLabel(44, 70, 0x481, "1");
|
||||
this.AddRadio(14, 100, 0xD2, 0xD3, dice == 2, 1002);
|
||||
this.AddLabel(44, 100, 0x481, "2");
|
||||
this.AddRadio(14, 130, 0xD2, 0xD3, dice == 3, 1003);
|
||||
this.AddLabel(44, 130, 0x481, "3");
|
||||
this.AddRadio(14, 160, 0xD2, 0xD3, dice == 4, 1004);
|
||||
this.AddLabel(44, 160, 0x481, "4");
|
||||
|
||||
this.AddHtmlLocalized(130, 50, 120, 20, 1076001, 0x7FFF, false, false); // Number of faces
|
||||
this.AddGroup(1);
|
||||
this.AddRadio(130, 70, 0xD2, 0xD3, faces == 4, 4);
|
||||
this.AddLabel(160, 70, 0x481, "4");
|
||||
this.AddRadio(130, 100, 0xD2, 0xD3, faces == 6, 6);
|
||||
this.AddLabel(160, 100, 0x481, "6");
|
||||
this.AddRadio(130, 130, 0xD2, 0xD3, faces == 8, 8);
|
||||
this.AddLabel(160, 130, 0x481, "8");
|
||||
this.AddRadio(130, 160, 0xD2, 0xD3, faces == 10, 10);
|
||||
this.AddLabel(160, 160, 0x481, "10");
|
||||
this.AddRadio(130, 190, 0xD2, 0xD3, faces == 12, 12);
|
||||
this.AddLabel(160, 190, 0x481, "12");
|
||||
this.AddRadio(130, 220, 0xD2, 0xD3, faces == 20, 20);
|
||||
this.AddLabel(160, 220, 0x481, "20");
|
||||
this.AddRadio(130, 250, 0xD2, 0xD3, faces == 100, 100);
|
||||
this.AddLabel(160, 250, 0x481, "100");
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Dealer == null || this.m_Dealer.Deleted)
|
||||
return;
|
||||
|
||||
if (info.ButtonID == 1)
|
||||
{
|
||||
int dice = 1;
|
||||
int faces = 4;
|
||||
|
||||
if (info.Switches.Length == 2)
|
||||
{
|
||||
dice = info.Switches[0] - 1000;
|
||||
faces = info.Switches[1];
|
||||
}
|
||||
|
||||
if (this.m_Dealer.m_NextUse < DateTime.UtcNow)
|
||||
{
|
||||
if (dice > 0 && faces > 0)
|
||||
{
|
||||
int sum = 0;
|
||||
string text = String.Empty;
|
||||
|
||||
for (int i = 0; i < dice; i++)
|
||||
{
|
||||
int roll = Utility.Random(faces) + 1;
|
||||
text = String.Format("{0}{1}{2}", text, i > 0 ? " " : "", roll);
|
||||
sum += roll;
|
||||
}
|
||||
|
||||
this.m_Dealer.Say(1076071, String.Format("{0}\t{1}\t{2}\t{3}\t{4}", sender.Mobile.Name, dice, faces, text, sum)); // ~1_NAME~ rolls ~2_DICE~d~3_FACES~: ~4_ROLLS~ (Total: ~5_TOTAL~)
|
||||
}
|
||||
|
||||
if (this.m_Dealer.m_Count > 0 && DateTime.UtcNow - this.m_Dealer.m_NextUse < TimeSpan.FromSeconds(this.m_Dealer.m_Count))
|
||||
this.m_Dealer.m_NextUse = DateTime.UtcNow + TimeSpan.FromSeconds(3);
|
||||
|
||||
if (this.m_Dealer.m_Count++ == 5)
|
||||
{
|
||||
this.m_Dealer.m_NextUse = DateTime.UtcNow;
|
||||
this.m_Dealer.m_Count = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
sender.Mobile.SendLocalizedMessage(501789); // You must wait before trying again.
|
||||
|
||||
sender.Mobile.SendGump(new InternalGump(this.m_Dealer, dice, faces));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AttendantMaleLuckyDealer : AttendantLuckyDealer
|
||||
{
|
||||
[Constructable]
|
||||
public AttendantMaleLuckyDealer()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public AttendantMaleLuckyDealer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.SetStr(50, 60);
|
||||
this.SetDex(20, 30);
|
||||
this.SetInt(100, 110);
|
||||
|
||||
this.Name = NameList.RandomName("male");
|
||||
this.Female = false;
|
||||
this.Race = Race.Human;
|
||||
this.Hue = this.Race.RandomSkinHue();
|
||||
|
||||
this.HairItemID = this.Race.RandomHair(this.Female);
|
||||
this.HairHue = this.Race.RandomHairHue();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new Boots());
|
||||
this.AddItem(new ShortPants());
|
||||
this.AddItem(new JesterHat());
|
||||
this.AddItem(new JesterSuit());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
|
||||
public class AttendantFemaleLuckyDealer : AttendantLuckyDealer
|
||||
{
|
||||
[Constructable]
|
||||
public AttendantFemaleLuckyDealer()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
public AttendantFemaleLuckyDealer(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InitBody()
|
||||
{
|
||||
this.SetStr(50, 60);
|
||||
this.SetDex(20, 30);
|
||||
this.SetInt(100, 110);
|
||||
|
||||
this.Name = NameList.RandomName("female");
|
||||
this.Female = true;
|
||||
this.Race = Race.Elf;
|
||||
this.Hue = this.Race.RandomSkinHue();
|
||||
|
||||
this.HairItemID = this.Race.RandomHair(this.Female);
|
||||
this.HairHue = this.Race.RandomHairHue();
|
||||
}
|
||||
|
||||
public override void InitOutfit()
|
||||
{
|
||||
this.AddItem(new ElvenBoots());
|
||||
this.AddItem(new ElvenPants());
|
||||
this.AddItem(new ElvenShirt());
|
||||
this.AddItem(new JesterHat());
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.WriteEncodedInt(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadEncodedInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user