Overwrite
Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
44
Scripts/Abilities/ArmorIgnore.cs
Normal file
44
Scripts/Abilities/ArmorIgnore.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This special move allows the skilled warrior to bypass his target's physical resistance, for one shot only.
|
||||
/// The Armor Ignore shot does slightly less damage than normal.
|
||||
/// Against a heavily armored opponent, this ability is a big win, but when used against a very lightly armored foe, it might be better to use a standard strike!
|
||||
/// </summary>
|
||||
public class ArmorIgnore : WeaponAbility
|
||||
{
|
||||
public ArmorIgnore()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0.9;
|
||||
}
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060076); // Your attack penetrates their armor!
|
||||
defender.SendLocalizedMessage(1060077); // The blow penetrated your armor!
|
||||
|
||||
defender.PlaySound(0x56);
|
||||
defender.FixedParticles(0x3728, 200, 25, 9942, EffectLayer.Waist);
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Scripts/Abilities/ArmorPierce.cs
Normal file
93
Scripts/Abilities/ArmorPierce.cs
Normal file
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Strike your opponent with great force, partially bypassing their armor and inflicting greater damage. Requires either Bushido or Ninjitsu skill
|
||||
/// </summary>
|
||||
public class ArmorPierce : WeaponAbility
|
||||
{
|
||||
public static Dictionary<Mobile, Timer> _Table = new Dictionary<Mobile, Timer>();
|
||||
|
||||
public ArmorPierce()
|
||||
{
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.HS ? 1.0 : 1.5;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RequiresSE
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1063350); // You pierce your opponent's armor!
|
||||
|
||||
defender.SendLocalizedMessage(1153764); // Your armor has been pierced!
|
||||
defender.SendLocalizedMessage(1063351); // Your attacker pierced your armor!
|
||||
|
||||
if (Core.HS)
|
||||
{
|
||||
if (_Table.ContainsKey(defender))
|
||||
{
|
||||
if (attacker.Weapon is BaseRanged)
|
||||
return;
|
||||
|
||||
_Table[defender].Stop();
|
||||
}
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.ArmorPierce, 1028860, 1154367, TimeSpan.FromSeconds(3), defender, "10"));
|
||||
_Table[defender] = Timer.DelayCall<Mobile>(TimeSpan.FromSeconds(3), RemoveEffects, defender);
|
||||
}
|
||||
|
||||
defender.PlaySound(0x28E);
|
||||
defender.FixedParticles(0x3728, 1, 26, 0x26D6, 0, 0, EffectLayer.Waist);
|
||||
}
|
||||
|
||||
public static void RemoveEffects(Mobile m)
|
||||
{
|
||||
if (IsUnderEffects(m))
|
||||
{
|
||||
m.SendLocalizedMessage(1153904); // Your armor has returned to normal.
|
||||
_Table.Remove(m);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsUnderEffects(Mobile m)
|
||||
{
|
||||
if(m == null)
|
||||
return false;
|
||||
|
||||
return _Table.ContainsKey(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Scripts/Abilities/BaseSummoned.cs
Normal file
89
Scripts/Abilities/BaseSummoned.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
// Created by Peoharen for the Mobile Abilities Package.
|
||||
using System;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
[CorpseName("a corpse")]
|
||||
public class BaseSummoned : BaseCreature
|
||||
{
|
||||
private DateTime m_DecayTime;
|
||||
public BaseSummoned(AIType aitype, FightMode fightmode, int spot, int meleerange, double passivespeed, double activespeed)
|
||||
: base(aitype, fightmode, spot, meleerange, passivespeed, activespeed)
|
||||
{
|
||||
this.m_DecayTime = DateTime.UtcNow + this.m_Delay;
|
||||
}
|
||||
|
||||
public BaseSummoned(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool AlwaysAttackable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool DeleteCorpseOnDeath
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override double DispelDifficulty
|
||||
{
|
||||
get
|
||||
{
|
||||
return 117.5;
|
||||
}
|
||||
}
|
||||
public override double DispelFocus
|
||||
{
|
||||
get
|
||||
{
|
||||
return 45.0;
|
||||
}
|
||||
}
|
||||
public override bool IsDispellable
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public virtual TimeSpan m_Delay
|
||||
{
|
||||
get
|
||||
{
|
||||
return TimeSpan.FromMinutes(2.0);
|
||||
}
|
||||
}
|
||||
public override void OnThink()
|
||||
{
|
||||
if (DateTime.UtcNow > this.m_DecayTime)
|
||||
{
|
||||
this.FixedParticles(14120, 10, 15, 5012, EffectLayer.Waist);
|
||||
this.PlaySound(510);
|
||||
this.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
this.m_DecayTime = DateTime.UtcNow + TimeSpan.FromMinutes(1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Scripts/Abilities/BattleLust.cs
Normal file
107
Scripts/Abilities/BattleLust.cs
Normal file
@@ -0,0 +1,107 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class BattleLust
|
||||
{
|
||||
private static readonly Dictionary<Mobile, BattleLustTimer> m_Table = new Dictionary<Mobile, BattleLustTimer>();
|
||||
public static bool UnderBattleLust(Mobile m)
|
||||
{
|
||||
return m_Table.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static int GetBonus(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!m_Table.ContainsKey(attacker))
|
||||
return 0;
|
||||
|
||||
int bonus = m_Table[attacker].Bonus * attacker.Aggressed.Count;
|
||||
|
||||
if (defender is PlayerMobile && bonus > 45)
|
||||
bonus = 45;
|
||||
else if (bonus > 90)
|
||||
bonus = 90;
|
||||
|
||||
return bonus;
|
||||
}
|
||||
|
||||
public static void IncreaseBattleLust(Mobile m, int damage)
|
||||
{
|
||||
if (damage < 30)
|
||||
return;
|
||||
else if (AosWeaponAttributes.GetValue(m, AosWeaponAttribute.BattleLust) == 0)
|
||||
return;
|
||||
else if (m_Table.ContainsKey(m))
|
||||
{
|
||||
if (m_Table[m].CanGain)
|
||||
{
|
||||
if (m_Table[m].Bonus < 16)
|
||||
m_Table[m].Bonus++;
|
||||
|
||||
m_Table[m].CanGain = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BattleLustTimer blt = new BattleLustTimer(m, 1);
|
||||
blt.Start();
|
||||
m_Table.Add(m, blt);
|
||||
m.SendLocalizedMessage(1113748); // The damage you received fuels your battle fury.
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DecreaseBattleLust(Mobile m)
|
||||
{
|
||||
if (m_Table.ContainsKey(m))
|
||||
{
|
||||
m_Table[m].Bonus--;
|
||||
|
||||
if (m_Table[m].Bonus <= 0)
|
||||
{
|
||||
m_Table.Remove(m);
|
||||
|
||||
// No Message?
|
||||
//m.SendLocalizedMessage( 0 ); //
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public class BattleLustTimer : Timer
|
||||
{
|
||||
public int Bonus;
|
||||
public bool CanGain;
|
||||
private readonly Mobile m_Mobile;
|
||||
private int m_Count;
|
||||
public BattleLustTimer(Mobile m, int bonus)
|
||||
: base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0))
|
||||
{
|
||||
this.m_Mobile = m;
|
||||
this.Bonus = bonus;
|
||||
this.m_Count = 1;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
this.m_Count %= 3;
|
||||
|
||||
if (this.m_Count == 0)
|
||||
{
|
||||
if (!DecreaseBattleLust(this.m_Mobile))
|
||||
this.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.CanGain = true;
|
||||
}
|
||||
|
||||
this.m_Count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
149
Scripts/Abilities/Bladeweave.cs
Normal file
149
Scripts/Abilities/Bladeweave.cs
Normal file
@@ -0,0 +1,149 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class Bladeweave : WeaponAbility
|
||||
{
|
||||
private class BladeWeaveRedirect
|
||||
{
|
||||
public WeaponAbility NewAbility;
|
||||
public int ClilocEntry;
|
||||
|
||||
public BladeWeaveRedirect(WeaponAbility ability, int cliloc)
|
||||
{
|
||||
NewAbility = ability;
|
||||
ClilocEntry = cliloc;
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, BladeWeaveRedirect> m_NewAttack = new Dictionary<Mobile, BladeWeaveRedirect>();
|
||||
|
||||
public static bool BladeWeaving(Mobile attacker, out WeaponAbility a)
|
||||
{
|
||||
BladeWeaveRedirect bwr;
|
||||
bool success = m_NewAttack.TryGetValue(attacker, out bwr);
|
||||
if (success)
|
||||
a = bwr.NewAbility;
|
||||
else
|
||||
a = null;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public Bladeweave()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 30; } }
|
||||
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, false))
|
||||
return false;
|
||||
|
||||
int ran = -1;
|
||||
|
||||
if (attacker is BaseCreature && PetTrainingHelper.CheckSecondarySkill((BaseCreature)attacker, SkillName.Bushido))
|
||||
{
|
||||
ran = Utility.Random(9);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool canfeint = attacker.Skills[WeaponAbility.Feint.GetSecondarySkill(attacker)].Value >= WeaponAbility.Feint.GetRequiredSecondarySkill(attacker);
|
||||
bool canblock = attacker.Skills[WeaponAbility.Block.GetSecondarySkill(attacker)].Value >= WeaponAbility.Block.GetRequiredSecondarySkill(attacker);
|
||||
|
||||
if (canfeint && canblock)
|
||||
{
|
||||
ran = Utility.Random(9);
|
||||
}
|
||||
else if (canblock)
|
||||
{
|
||||
ran = Utility.Random(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
ran = Utility.RandomList(0, 1, 2, 3, 4, 5, 6, 8);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ran)
|
||||
{
|
||||
case 0:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.ArmorIgnore, 1028838);
|
||||
break;
|
||||
case 1:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.BleedAttack, 1028839);
|
||||
break;
|
||||
case 2:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.ConcussionBlow, 1028840);
|
||||
break;
|
||||
case 3:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.CrushingBlow, 1028841);
|
||||
break;
|
||||
case 4:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.DoubleStrike, 1028844);
|
||||
break;
|
||||
case 5:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.MortalStrike, 1028846);
|
||||
break;
|
||||
case 6:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.ParalyzingBlow, 1028848);
|
||||
break;
|
||||
case 7:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.Block, 1028853);
|
||||
break;
|
||||
case 8:
|
||||
m_NewAttack[attacker] = new BladeWeaveRedirect(WeaponAbility.Feint, 1028857);
|
||||
break;
|
||||
default:
|
||||
// should never happen
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return ((BladeWeaveRedirect)m_NewAttack[attacker]).NewAbility.OnBeforeSwing(attacker, defender);
|
||||
}
|
||||
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
BladeWeaveRedirect bwr;
|
||||
if (m_NewAttack.TryGetValue(attacker, out bwr))
|
||||
return bwr.NewAbility.OnBeforeDamage(attacker, defender);
|
||||
else
|
||||
return base.OnBeforeDamage(attacker, defender);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (CheckMana(attacker, false))
|
||||
{
|
||||
BladeWeaveRedirect bwr;
|
||||
if (m_NewAttack.TryGetValue(attacker, out bwr))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1072841, "#" + bwr.ClilocEntry.ToString());
|
||||
bwr.NewAbility.OnHit(attacker, defender, damage);
|
||||
}
|
||||
else
|
||||
base.OnHit(attacker, defender, damage);
|
||||
|
||||
m_NewAttack.Remove(attacker);
|
||||
ClearCurrentAbility(attacker);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
BladeWeaveRedirect bwr;
|
||||
if (m_NewAttack.TryGetValue(attacker, out bwr))
|
||||
bwr.NewAbility.OnMiss(attacker, defender);
|
||||
else
|
||||
base.OnMiss(attacker, defender);
|
||||
|
||||
m_NewAttack.Remove(attacker);
|
||||
}
|
||||
}
|
||||
}
|
||||
183
Scripts/Abilities/BleedAttack.cs
Normal file
183
Scripts/Abilities/BleedAttack.cs
Normal file
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Necromancy;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Make your opponent bleed profusely with this wicked use of your weapon.
|
||||
/// When successful, the target will bleed for several seconds, taking damage as time passes for up to ten seconds.
|
||||
/// The rate of damage slows down as time passes, and the blood loss can be completely staunched with the use of bandages.
|
||||
/// </summary>
|
||||
public class BleedAttack : WeaponAbility
|
||||
{
|
||||
private static readonly Dictionary<Mobile, BleedTimer> m_BleedTable = new Dictionary<Mobile, BleedTimer>();
|
||||
|
||||
public BleedAttack()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsBleeding(Mobile m)
|
||||
{
|
||||
return m_BleedTable.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void BeginBleed(Mobile m, Mobile from, bool splintering = false)
|
||||
{
|
||||
BleedTimer timer = null;
|
||||
|
||||
if (m_BleedTable.ContainsKey(m))
|
||||
{
|
||||
if (splintering)
|
||||
{
|
||||
timer = m_BleedTable[m];
|
||||
timer.Stop();
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Bleed, 1075829, 1075830, TimeSpan.FromSeconds(10), m, String.Format("{0}\t{1}\t{2}", "1", "10", "2")));
|
||||
|
||||
timer = new BleedTimer(from, m, CheckBloodDrink(from));
|
||||
m_BleedTable[m] = timer;
|
||||
timer.Start();
|
||||
|
||||
from.SendLocalizedMessage(1060159); // Your target is bleeding!
|
||||
m.SendLocalizedMessage(1060160); // You are bleeding!
|
||||
|
||||
if (m is PlayerMobile)
|
||||
{
|
||||
m.LocalOverheadMessage(MessageType.Regular, 0x21, 1060757); // You are bleeding profusely
|
||||
m.NonlocalOverheadMessage(MessageType.Regular, 0x21, 1060758, m.Name); // ~1_NAME~ is bleeding profusely
|
||||
}
|
||||
|
||||
m.PlaySound(0x133);
|
||||
m.FixedParticles(0x377A, 244, 25, 9950, 31, 0, EffectLayer.Waist);
|
||||
}
|
||||
|
||||
public static void DoBleed(Mobile m, Mobile from, int damage, bool blooddrinker)
|
||||
{
|
||||
if (m.Alive && !m.IsDeadBondedPet)
|
||||
{
|
||||
if (!m.Player)
|
||||
damage *= 2;
|
||||
|
||||
m.PlaySound(0x133);
|
||||
AOS.Damage(m, from, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);
|
||||
|
||||
if (blooddrinker && from.Hits < from.HitsMax)
|
||||
{
|
||||
from.SendLocalizedMessage(1113606); //The blood drinker effect heals you.
|
||||
from.Heal(damage);
|
||||
}
|
||||
|
||||
Blood blood = new Blood();
|
||||
blood.ItemID = Utility.Random(0x122A, 5);
|
||||
blood.MoveToWorld(m.Location, m.Map);
|
||||
}
|
||||
else
|
||||
{
|
||||
EndBleed(m, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EndBleed(Mobile m, bool message)
|
||||
{
|
||||
Timer t = null;
|
||||
|
||||
if (m_BleedTable.ContainsKey(m))
|
||||
{
|
||||
t = m_BleedTable[m];
|
||||
m_BleedTable.Remove(m);
|
||||
}
|
||||
|
||||
if (t == null)
|
||||
return;
|
||||
|
||||
t.Stop();
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Bleed);
|
||||
|
||||
if (message)
|
||||
m.SendLocalizedMessage(1060167); // The bleeding wounds have healed, you are no longer bleeding!
|
||||
}
|
||||
|
||||
public static bool CheckBloodDrink(Mobile attacker)
|
||||
{
|
||||
return attacker.Weapon is BaseWeapon && ((BaseWeapon)attacker.Weapon).WeaponAttributes.BloodDrinker > 0;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
// Necromancers under Lich or Wraith Form are immune to Bleed Attacks.
|
||||
TransformContext context = TransformationSpellHelper.GetContext(defender);
|
||||
|
||||
if ((context != null && (context.Type == typeof(LichFormSpell) || context.Type == typeof(WraithFormSpell))) ||
|
||||
(defender is BaseCreature && ((BaseCreature)defender).BleedImmune) || Server.Spells.Mysticism.StoneFormSpell.CheckImmunity(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1062052); // Your target is not affected by the bleed attack!
|
||||
return;
|
||||
}
|
||||
|
||||
BeginBleed(defender, attacker);
|
||||
}
|
||||
|
||||
private class BleedTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly Mobile m_Mobile;
|
||||
private int m_Count;
|
||||
private int m_MaxCount;
|
||||
private readonly bool m_BloodDrinker;
|
||||
|
||||
public BleedTimer(Mobile from, Mobile m, bool blooddrinker)
|
||||
: base(TimeSpan.FromSeconds(2.0), TimeSpan.FromSeconds(2.0))
|
||||
{
|
||||
m_From = from;
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
m_BloodDrinker = blooddrinker;
|
||||
|
||||
m_MaxCount = Spells.SkillMasteries.ResilienceSpell.UnderEffects(m) ? 3 : 5;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!m_Mobile.Alive || m_Mobile.Deleted)
|
||||
{
|
||||
EndBleed(m_Mobile, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
int damage = 0;
|
||||
|
||||
if (!Server.Spells.SkillMasteries.WhiteTigerFormSpell.HasBleedMod(m_From, out damage))
|
||||
damage = Math.Max(1, Utility.RandomMinMax(5 - m_Count, (5 - m_Count) * 2));
|
||||
|
||||
DoBleed(m_Mobile, m_From, damage, m_BloodDrinker);
|
||||
|
||||
if (++m_Count == m_MaxCount)
|
||||
EndBleed(m_Mobile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
155
Scripts/Abilities/Block.cs
Normal file
155
Scripts/Abilities/Block.cs
Normal file
@@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises your defenses for a short time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
///
|
||||
// spell/melee
|
||||
// 0 parry - 70/80
|
||||
// 100 parry - 40/65
|
||||
// 120 parry - 20/55
|
||||
// .6875
|
||||
|
||||
public class Block : WeaponAbility
|
||||
{
|
||||
private static Dictionary<Mobile, BlockInfo> _Table;
|
||||
|
||||
public Block()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 20; } }
|
||||
|
||||
public override int AccuracyBonus { get { return -15; } }
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public static bool IsBlocking(Mobile m)
|
||||
{
|
||||
return _Table != null && _Table.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static int GetBonus(Mobile targ)
|
||||
{
|
||||
if (targ == null || _Table == null)
|
||||
return 0;
|
||||
|
||||
if (_Table.ContainsKey(targ))
|
||||
return _Table[targ]._DCIBonus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetSpellReduction(Mobile m)
|
||||
{
|
||||
if (m == null || _Table == null)
|
||||
return 0;
|
||||
|
||||
if (_Table.ContainsKey(m))
|
||||
{
|
||||
return _Table[m]._SpellReduction;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int GetMeleeReduction(Mobile m)
|
||||
{
|
||||
if (m == null || _Table == null)
|
||||
return 0;
|
||||
|
||||
if (_Table.ContainsKey(m))
|
||||
{
|
||||
return _Table[m]._MeleeReduction;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void BeginBlock(Mobile m, int dciBonus, int spellblock, int meleeblock)
|
||||
{
|
||||
EndBlock(m);
|
||||
|
||||
if (_Table == null)
|
||||
_Table = new Dictionary<Mobile, BlockInfo>();
|
||||
|
||||
BlockInfo info = new BlockInfo(dciBonus, spellblock, meleeblock);
|
||||
_Table[m] = info;
|
||||
|
||||
string args = String.Format("{0}\t{1}\t{2}\t{3}\t{4}", dciBonus, spellblock, meleeblock, "15", "30");
|
||||
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.Block, 1151291, 1151292, TimeSpan.FromSeconds(Core.TOL ? 6 : 3), m, args));
|
||||
// Next incoming damage reduced.<br>Defense Chance Increase: +~1_val~%<br>Incoming Spell Damage: -~2_val~%<br>Incoming Attack Damage: -~3_val~%<br>Hit Chance Penalty: ~4_val~%<br>Damage Penalty: ~5_val~%
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(Core.TOL ? 6 : 3), () =>
|
||||
{
|
||||
if(IsBlocking(m))
|
||||
EndBlock(m);
|
||||
});
|
||||
}
|
||||
|
||||
public static void EndBlock(Mobile m)
|
||||
{
|
||||
if (_Table != null && _Table.ContainsKey(m))
|
||||
{
|
||||
_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.Block);
|
||||
|
||||
m.SendLocalizedMessage(1150286); // You no longer try to block the next attack.
|
||||
|
||||
if (_Table.Count == 0)
|
||||
_Table = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1063345); // You block an attack!
|
||||
defender.SendLocalizedMessage(1063346); // Your attack was blocked!
|
||||
|
||||
attacker.FixedParticles(0x37C4, 1, 16, 0x251D, 0x39D, 0x3, EffectLayer.RightHand);
|
||||
|
||||
int parry = (int)attacker.Skills[SkillName.Parry].Value;
|
||||
|
||||
bool creature = attacker is BaseCreature;
|
||||
double skill = creature ? attacker.Skills[SkillName.Bushido].Value :
|
||||
Math.Max(attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value);
|
||||
|
||||
int dcibonus = (int)(10.0 * ((skill - 50.0) / 70.0 + 5));
|
||||
int spellblock = parry <= 70 ? 70 : parry <= 100 ? 40 : 20;
|
||||
int meleeblock = parry <= 70 ? 80 : parry <= 100 ? 65 : 55;
|
||||
|
||||
BeginBlock(attacker, dcibonus, spellblock, meleeblock);
|
||||
|
||||
if(creature)
|
||||
PetTrainingHelper.OnWeaponAbilityUsed((BaseCreature)attacker, SkillName.Bushido);
|
||||
}
|
||||
|
||||
private class BlockInfo
|
||||
{
|
||||
public readonly int _DCIBonus;
|
||||
public readonly int _SpellReduction;
|
||||
public readonly int _MeleeReduction;
|
||||
|
||||
public BlockInfo(int bonus, int spellred, int meleered)
|
||||
{
|
||||
_DCIBonus = bonus;
|
||||
_SpellReduction = spellred;
|
||||
_MeleeReduction = meleered;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
Scripts/Abilities/ColdWind.cs
Normal file
103
Scripts/Abilities/ColdWind.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using Server.Network;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Currently on EA, this is only available for Creatures
|
||||
/// </summary>
|
||||
public class ColdWind : WeaponAbility
|
||||
{
|
||||
private static readonly Dictionary<Mobile, ExpireTimer> m_Table = new Dictionary<Mobile, ExpireTimer>();
|
||||
|
||||
public ColdWind()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.5;
|
||||
}
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if (attacker.Map == null || attacker.Map == Map.Internal)
|
||||
return;
|
||||
|
||||
ExpireTimer timer = null;
|
||||
|
||||
if (m_Table.ContainsKey(defender))
|
||||
timer = m_Table[defender];
|
||||
|
||||
if (timer != null)
|
||||
{
|
||||
timer.DoExpire();
|
||||
defender.SendLocalizedMessage(1070831); // The freezing wind continues to blow!
|
||||
}
|
||||
else
|
||||
defender.SendLocalizedMessage(1070832); // An icy wind surrounds you, freezing your lungs as you breathe!
|
||||
|
||||
timer = new ExpireTimer(defender, attacker);
|
||||
timer.Start();
|
||||
m_Table[defender] = timer;
|
||||
}
|
||||
|
||||
private class ExpireTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
private readonly Mobile m_From;
|
||||
private int m_Count;
|
||||
|
||||
public ExpireTimer(Mobile m, Mobile from)
|
||||
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0))
|
||||
{
|
||||
m_Mobile = m;
|
||||
m_From = from;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
public void DoExpire()
|
||||
{
|
||||
Stop();
|
||||
m_Table.Remove(m_Mobile);
|
||||
}
|
||||
|
||||
public void DrainLife()
|
||||
{
|
||||
if (m_Mobile.Alive)
|
||||
{
|
||||
AOS.Damage(m_Mobile, m_From, 14, 0, 0, 100, 0, 0);
|
||||
Effects.SendPacket(m_Mobile.Location, m_Mobile.Map, new ParticleEffect(EffectType.FixedFrom, m_Mobile.Serial, Serial.Zero, 0x374A, m_Mobile.Location, m_Mobile.Location, 1, 15, false, false, 97, 0, 4, 9502, 1, m_Mobile.Serial, 163, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
DoExpire();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
DrainLife();
|
||||
|
||||
if (++m_Count >= 5)
|
||||
{
|
||||
DoExpire();
|
||||
m_Mobile.SendLocalizedMessage(1070830); // The icy wind dissipates.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Abilities/ConcussionBlow.cs
Normal file
57
Scripts/Abilities/ConcussionBlow.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This devastating strike is most effective against those who are in good health and whose reserves of mana are low, or vice versa.
|
||||
/// </summary>
|
||||
public class ConcussionBlow : WeaponAbility
|
||||
{
|
||||
public ConcussionBlow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return false;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060165); // You have delivered a concussion!
|
||||
defender.SendLocalizedMessage(1060166); // You feel disoriented!
|
||||
|
||||
defender.PlaySound(0x213);
|
||||
defender.FixedParticles(0x377A, 1, 32, 9949, 1153, 0, EffectLayer.Head);
|
||||
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 10), defender.Map), new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0x36FE, 1, 0, false, false, 1133, 3, 9501, 1, 0, EffectLayer.Waist, 0x100);
|
||||
|
||||
int damage = 10; // Base damage is 10.
|
||||
|
||||
if (defender.HitsMax > 0)
|
||||
{
|
||||
double hitsPercent = ((double)defender.Hits / (double)defender.HitsMax) * 100.0;
|
||||
|
||||
double manaPercent = 0;
|
||||
|
||||
if (defender.ManaMax > 0)
|
||||
manaPercent = ((double)defender.Mana / (double)defender.ManaMax) * 100.0;
|
||||
|
||||
damage += Math.Min((int)(Math.Abs(hitsPercent - manaPercent) / 4), 20);
|
||||
}
|
||||
|
||||
// Total damage is 10 + (0~20) = 10~30, physical, non-resistable.
|
||||
|
||||
defender.Damage(damage, attacker);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Scripts/Abilities/CrushingBlow.cs
Normal file
44
Scripts/Abilities/CrushingBlow.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Also known as the Haymaker, this attack dramatically increases the damage done by a weapon reaching its mark.
|
||||
/// </summary>
|
||||
public class CrushingBlow : WeaponAbility
|
||||
{
|
||||
public CrushingBlow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.5;
|
||||
}
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060090); // You have delivered a crushing blow!
|
||||
defender.SendLocalizedMessage(1060091); // You take extra damage from the crushing attack!
|
||||
|
||||
defender.PlaySound(0x1E1);
|
||||
defender.FixedParticles(0, 1, 0, 9946, EffectLayer.Head);
|
||||
|
||||
Effects.SendMovingParticles(new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 50), defender.Map), new Entity(Serial.Zero, new Point3D(defender.X, defender.Y, defender.Z + 20), defender.Map), 0xFB4, 1, 0, false, false, 0, 3, 9501, 1, 0, EffectLayer.Head, 0x100);
|
||||
}
|
||||
}
|
||||
}
|
||||
100
Scripts/Abilities/DefenseMastery.cs
Normal file
100
Scripts/Abilities/DefenseMastery.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Raises your physical resistance for a short time while lowering your ability to inflict damage. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DefenseMastery : WeaponAbility
|
||||
{
|
||||
private static readonly Hashtable m_Table = new Hashtable();
|
||||
public DefenseMastery()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public static bool GetMalus(Mobile targ, ref int damageMalus)
|
||||
{
|
||||
DefenseMasteryInfo info = m_Table[targ] as DefenseMasteryInfo;
|
||||
|
||||
if (info == null)
|
||||
return false;
|
||||
|
||||
damageMalus = info.m_DamageMalus;
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1063353); // You perform a masterful defense!
|
||||
|
||||
attacker.FixedParticles(0x375A, 1, 17, 0x7F2, 0x3E8, 0x3, EffectLayer.Waist);
|
||||
|
||||
int modifier = (int)(30.0 * ((Math.Max(attacker.Skills[SkillName.Bushido].Value, attacker.Skills[SkillName.Ninjitsu].Value) - 50.0) / 70.0));
|
||||
|
||||
DefenseMasteryInfo info = m_Table[attacker] as DefenseMasteryInfo;
|
||||
|
||||
if (info != null)
|
||||
EndDefense((object)info);
|
||||
|
||||
ResistanceMod mod = new ResistanceMod(ResistanceType.Physical, 50 + modifier);
|
||||
attacker.AddResistanceMod(mod);
|
||||
|
||||
info = new DefenseMasteryInfo(attacker, 80 - modifier, mod);
|
||||
info.m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(3.0), new TimerStateCallback(EndDefense), info);
|
||||
|
||||
m_Table[attacker] = info;
|
||||
|
||||
attacker.Delta(MobileDelta.WeaponDamage);
|
||||
}
|
||||
|
||||
private static void EndDefense(object state)
|
||||
{
|
||||
DefenseMasteryInfo info = (DefenseMasteryInfo)state;
|
||||
|
||||
if (info.m_Mod != null)
|
||||
info.m_From.RemoveResistanceMod(info.m_Mod);
|
||||
|
||||
if (info.m_Timer != null)
|
||||
info.m_Timer.Stop();
|
||||
|
||||
// No message is sent to the player.
|
||||
|
||||
m_Table.Remove(info.m_From);
|
||||
|
||||
info.m_From.Delta(MobileDelta.WeaponDamage);
|
||||
}
|
||||
|
||||
private class DefenseMasteryInfo
|
||||
{
|
||||
public readonly Mobile m_From;
|
||||
public readonly int m_DamageMalus;
|
||||
public readonly ResistanceMod m_Mod;
|
||||
public Timer m_Timer;
|
||||
public DefenseMasteryInfo(Mobile from, int damageMalus, ResistanceMod mod)
|
||||
{
|
||||
m_From = from;
|
||||
m_DamageMalus = damageMalus;
|
||||
m_Mod = mod;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Scripts/Abilities/Disarm.cs
Normal file
121
Scripts/Abilities/Disarm.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This attack allows you to disarm your foe.
|
||||
/// Now in Age of Shadows, a successful Disarm leaves the victim unable to re-arm another weapon for several seconds.
|
||||
/// </summary>
|
||||
public class Disarm : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0);
|
||||
public Disarm()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RequiresSecondarySkill(Mobile from)
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return false;
|
||||
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
if (IsImmune(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1111827); // Your opponent is gripping their weapon too tightly to be disarmed.
|
||||
defender.SendLocalizedMessage(1111828); // You will not be caught off guard by another disarm attack for some time.
|
||||
return;
|
||||
}
|
||||
|
||||
Item toDisarm = defender.FindItemOnLayer(Layer.OneHanded);
|
||||
|
||||
if (toDisarm == null || !toDisarm.Movable)
|
||||
toDisarm = defender.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
Container pack = defender.Backpack;
|
||||
|
||||
if (pack == null || (toDisarm != null && !toDisarm.Movable))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent.
|
||||
}
|
||||
else if (toDisarm == null || toDisarm is BaseShield || toDisarm is Spellbook && !Core.ML)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060849); // Your target is already unarmed!
|
||||
}
|
||||
else if (this.CheckMana(attacker, true))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060092); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage(1060093); // Your weapon has been disarmed!
|
||||
|
||||
defender.PlaySound(0x3B9);
|
||||
defender.FixedParticles(0x37BE, 232, 25, 9948, EffectLayer.LeftHand);
|
||||
|
||||
pack.DropItem(toDisarm);
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo( BuffIcon.NoRearm, 1075637, BlockEquipDuration, defender));
|
||||
|
||||
BaseWeapon.BlockEquip(defender, BlockEquipDuration);
|
||||
|
||||
if (defender is BaseCreature && _AutoRearms.Any(t => t == defender.GetType()))
|
||||
{
|
||||
Timer.DelayCall(BlockEquipDuration + TimeSpan.FromSeconds(Utility.RandomMinMax(3, 10)), () =>
|
||||
{
|
||||
if (toDisarm != null && !toDisarm.Deleted && toDisarm.IsChildOf(defender.Backpack))
|
||||
defender.EquipItem(toDisarm);
|
||||
});
|
||||
}
|
||||
|
||||
if(Core.SA)
|
||||
AddImmunity(defender, Core.TOL && attacker.Weapon is Fists ? TimeSpan.FromSeconds(10) : TimeSpan.FromSeconds(15));
|
||||
}
|
||||
}
|
||||
|
||||
private Type[] _AutoRearms =
|
||||
{
|
||||
typeof(BritannianInfantry)
|
||||
};
|
||||
|
||||
public static List<Mobile> _Immunity;
|
||||
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
return _Immunity != null && _Immunity.Contains(m);
|
||||
}
|
||||
|
||||
public static void AddImmunity(Mobile m, TimeSpan duration)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
_Immunity = new List<Mobile>();
|
||||
|
||||
_Immunity.Add(m);
|
||||
|
||||
Timer.DelayCall<Mobile>(duration, mob =>
|
||||
{
|
||||
if (_Immunity != null && _Immunity.Contains(mob))
|
||||
_Immunity.Remove(mob);
|
||||
}, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
141
Scripts/Abilities/Dismount.cs
Normal file
141
Scripts/Abilities/Dismount.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Perfect for the foot-soldier, the Dismount special attack can unseat a mounted opponent.
|
||||
/// The fighter using this ability must be on his own two feet and not in the saddle of a steed
|
||||
/// (with one exception: players may use a lance to dismount other players while mounted).
|
||||
/// If it works, the target will be knocked off his own mount and will take some extra damage from the fall!
|
||||
/// </summary>
|
||||
public class Dismount : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan DefenderRemountDelay = TimeSpan.FromSeconds(10.0);// TODO: Taken from bola script, needs to be verified
|
||||
public static readonly TimeSpan AttackerRemountDelay = TimeSpan.FromSeconds(3.0);
|
||||
public Dismount()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.TOL ? 25 : 20;
|
||||
}
|
||||
}
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (!base.Validate(from))
|
||||
return false;
|
||||
|
||||
if ( (from.Mounted || from.Flying) && !(from.Weapon is Lance) && !(from.Weapon is GargishLance) )
|
||||
{
|
||||
from.SendLocalizedMessage(1061283); // You cannot perform that attack while mounted or flying!
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
if (defender is ChaosDragoon || defender is ChaosDragoonElite)
|
||||
return;
|
||||
|
||||
if (CheckMountedNoLance(attacker, defender)) // TODO: Should there be a message here?
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
IMount mount = defender.Mount;
|
||||
|
||||
if (mount == null && !defender.Flying && (!Core.ML || !Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender)))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060848); // This attack only works on mounted or flying targets
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.CheckMana(attacker, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (Core.ML && attacker is LesserHiryu && 0.8 >= Utility.RandomDouble())
|
||||
{
|
||||
return; //Lesser Hiryu have an 80% chance of missing this attack
|
||||
}
|
||||
|
||||
defender.PlaySound(0x140);
|
||||
defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist);
|
||||
|
||||
int delay = Core.TOL && attacker.Weapon is BaseRanged ? 8 : 10;
|
||||
|
||||
DoDismount(attacker, defender, mount, delay);
|
||||
|
||||
if (!attacker.Mounted)
|
||||
{
|
||||
AOS.Damage(defender, attacker, Utility.RandomMinMax(15, 25), 100, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DoDismount(Mobile attacker, Mobile defender, IMount mount, int delay, BlockMountType type = BlockMountType.Dazed)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060082); // The force of your attack has dislodged them from their mount!
|
||||
|
||||
if (defender is PlayerMobile)
|
||||
{
|
||||
if (Core.ML && Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender))
|
||||
{
|
||||
defender.SendLocalizedMessage(1114066, attacker.Name); // ~1_NAME~ knocked you out of animal form!
|
||||
}
|
||||
else if (defender.Flying)
|
||||
{
|
||||
defender.SendLocalizedMessage(1113590, attacker.Name); // You have been grounded by ~1_NAME~!
|
||||
}
|
||||
else if (defender.Mounted)
|
||||
{
|
||||
defender.SendLocalizedMessage(1060083); // You fall off of your mount and take damage!
|
||||
}
|
||||
|
||||
((PlayerMobile)defender).SetMountBlock(type, TimeSpan.FromSeconds(delay), true);
|
||||
}
|
||||
else if (mount != null)
|
||||
{
|
||||
mount.Rider = null;
|
||||
}
|
||||
|
||||
if (attacker is PlayerMobile)
|
||||
{
|
||||
((PlayerMobile)attacker).SetMountBlock(BlockMountType.DismountRecovery, TimeSpan.FromSeconds(Core.TOL && attacker.Weapon is BaseRanged ? 8 : 10), false);
|
||||
}
|
||||
else if (Core.ML && attacker is BaseCreature)
|
||||
{
|
||||
BaseCreature bc = attacker as BaseCreature;
|
||||
|
||||
if (bc.ControlMaster is PlayerMobile)
|
||||
{
|
||||
PlayerMobile pm = bc.ControlMaster as PlayerMobile;
|
||||
|
||||
pm.SetMountBlock(BlockMountType.DismountRecovery, TimeSpan.FromSeconds(delay), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckMountedNoLance(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!attacker.Mounted && !attacker.Flying)
|
||||
return false;
|
||||
|
||||
if ((attacker.Weapon is Lance || attacker.Weapon is GargishLance) && (defender.Weapon is Lance || defender.Weapon is GargishLance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Scripts/Abilities/Disrobe.cs
Normal file
53
Scripts/Abilities/Disrobe.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This attack allows you to disrobe your foe.
|
||||
/// </summary>
|
||||
public class Disrobe : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan BlockEquipDuration = TimeSpan.FromSeconds(5.0);
|
||||
public Disrobe()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}// Not Sure what amount of mana a creature uses.
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
Item toDisrobe = defender.FindItemOnLayer(Layer.InnerTorso);
|
||||
|
||||
if (toDisrobe == null || !toDisrobe.Movable)
|
||||
toDisrobe = defender.FindItemOnLayer(Layer.OuterTorso);
|
||||
|
||||
Container pack = defender.Backpack;
|
||||
|
||||
if (pack == null || toDisrobe == null || !toDisrobe.Movable)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1004001); // You cannot disarm your opponent.
|
||||
}
|
||||
else if (this.CheckMana(attacker, true))
|
||||
{
|
||||
//attacker.SendLocalizedMessage( 1060092 ); // You disarm their weapon!
|
||||
defender.SendLocalizedMessage(1062002); // You can no longer wear your ~1_ARMOR~
|
||||
|
||||
defender.PlaySound(0x3B9);
|
||||
//defender.FixedParticles( 0x37BE, 232, 25, 9948, EffectLayer.InnerTorso );
|
||||
|
||||
pack.DropItem(toDisrobe);
|
||||
|
||||
BaseWeapon.BlockEquip(defender, BlockEquipDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Scripts/Abilities/DoubleShot.cs
Normal file
81
Scripts/Abilities/DoubleShot.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Send two arrows flying at your opponent if you're mounted. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class DoubleShot : WeaponAbility
|
||||
{
|
||||
public DoubleShot()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.TOL ? 30 : 35;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
BaseWeapon wep = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (wep != null)
|
||||
wep.ProcessingMultipleHits = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
Use(attacker, defender);
|
||||
}
|
||||
|
||||
public override void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
Use(attacker, defender);
|
||||
}
|
||||
|
||||
public override bool Validate(Mobile from)
|
||||
{
|
||||
if (base.Validate(from))
|
||||
{
|
||||
if (from.Mounted)
|
||||
return true;
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1070770); // You can only execute this attack while mounted!
|
||||
ClearCurrentAbility(from);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Use(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true) || attacker.Weapon == null) //sanity
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1063348); // You launch two shots at once!
|
||||
defender.SendLocalizedMessage(1063349); // You're attacked with a barrage of shots!
|
||||
|
||||
defender.FixedParticles(0x37B9, 1, 19, 0x251D, EffectLayer.Waist);
|
||||
|
||||
attacker.Weapon.OnSwing(attacker, defender);
|
||||
|
||||
if (attacker.Weapon is BaseWeapon)
|
||||
((BaseWeapon)attacker.Weapon).ProcessingMultipleHits = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Scripts/Abilities/DoubleStrike.cs
Normal file
68
Scripts/Abilities/DoubleStrike.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// The highly skilled warrior can use this special attack to make two quick swings in succession.
|
||||
/// Landing both blows would be devastating!
|
||||
/// </summary>
|
||||
public class DoubleStrike : WeaponAbility
|
||||
{
|
||||
public override int BaseMana { get { return 30; } }
|
||||
public override double DamageScalar { get { return 0.9; } }
|
||||
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
BaseWeapon wep = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (wep != null)
|
||||
wep.InDoubleStrike = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If no combatant, wrong map, one of us is a ghost, or cannot see, or deleted, then stop combat
|
||||
if (defender.Deleted || attacker.Deleted || defender.Map != attacker.Map || !defender.Alive ||
|
||||
!attacker.Alive || !attacker.CanSee(defender))
|
||||
{
|
||||
weapon.InDoubleStrike = false;
|
||||
attacker.Combatant = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!attacker.InRange(defender, weapon.MaxRange))
|
||||
{
|
||||
weapon.InDoubleStrike = false;
|
||||
return;
|
||||
}
|
||||
|
||||
attacker.SendLocalizedMessage(1060084); // You attack with lightning speed!
|
||||
defender.SendLocalizedMessage(1060085); // Your attacker strikes with lightning speed!
|
||||
|
||||
defender.PlaySound(0x3BB);
|
||||
defender.FixedEffect(0x37B9, 244, 25);
|
||||
|
||||
if (attacker.InLOS(defender))
|
||||
{
|
||||
attacker.RevealingAction();
|
||||
attacker.NextCombatTime = Core.TickCount + (int)weapon.OnSwing(attacker, defender).TotalMilliseconds;
|
||||
}
|
||||
|
||||
weapon.InDoubleStrike = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
137
Scripts/Abilities/DualWield.cs
Normal file
137
Scripts/Abilities/DualWield.cs
Normal file
@@ -0,0 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Attack faster as you swing with both weapons.
|
||||
/// </summary>
|
||||
public class DualWield : WeaponAbility
|
||||
{
|
||||
private static readonly Dictionary<Mobile, DualWieldTimer> m_Registry = new Dictionary<Mobile, DualWieldTimer>();
|
||||
|
||||
public DualWield()
|
||||
{
|
||||
}
|
||||
|
||||
public static Dictionary<Mobile, DualWieldTimer> Registry { get { return m_Registry; } }
|
||||
public override int BaseMana { get { return 20; } }
|
||||
|
||||
public static readonly TimeSpan Duration = TimeSpan.FromSeconds(8);
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
if (HasRegistry(attacker))
|
||||
{
|
||||
var timer = m_Registry[attacker];
|
||||
|
||||
if (timer.DualHitChance < .75)
|
||||
{
|
||||
timer.Expires += TimeSpan.FromSeconds(2);
|
||||
timer.DualHitChance += .25;
|
||||
|
||||
BuffInfo.RemoveBuff(attacker, BuffIcon.DualWield);
|
||||
BuffInfo.AddBuff(attacker, new BuffInfo(BuffIcon.DualWield, 1151294, 1151293, timer.Expires - DateTime.UtcNow, attacker, (timer.DualHitChance * 100).ToString()));
|
||||
|
||||
attacker.SendLocalizedMessage(timer.DualHitChance == .75 ? 1150283 : 1150282); // Dual wield level increased to peak! : Dual wield level increased!
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
attacker.SendLocalizedMessage(1150281); // You begin trying to strike with both your weapons at once.
|
||||
attacker.SendLocalizedMessage(1150284, true, Duration.TotalSeconds.ToString()); // Remaining Duration (seconds):
|
||||
|
||||
DualWieldTimer t = new DualWieldTimer(attacker, .25);
|
||||
BuffInfo.AddBuff(attacker, new BuffInfo(BuffIcon.DualWield, 1151294, 1151293, Duration, attacker, "25"));
|
||||
|
||||
Registry[attacker] = t;
|
||||
|
||||
attacker.FixedParticles(0x3779, 1, 15, 0x7F6, 0x3E8, 3, EffectLayer.LeftHand);
|
||||
Effects.PlaySound(attacker.Location, attacker.Map, 0x524);
|
||||
}
|
||||
|
||||
public static bool HasRegistry(Mobile attacker)
|
||||
{
|
||||
return m_Registry.ContainsKey(attacker);
|
||||
}
|
||||
|
||||
public static void RemoveFromRegistry(Mobile from)
|
||||
{
|
||||
if (m_Registry.ContainsKey(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1150285); // You no longer try to strike with both weapons at the same time.
|
||||
|
||||
m_Registry[from].Stop();
|
||||
m_Registry.Remove(from);
|
||||
|
||||
if(from.Weapon is BaseWeapon)
|
||||
((BaseWeapon)from.Weapon).ProcessingMultipleHits = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from BaseWeapon, on successful hit
|
||||
/// </summary>
|
||||
/// <param name="from"></param>
|
||||
public static void DoHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (HasRegistry(attacker) && attacker.Weapon is BaseWeapon && m_Registry[attacker].DualHitChance > Utility.RandomDouble())
|
||||
{
|
||||
BaseWeapon wep = (BaseWeapon)attacker.Weapon;
|
||||
|
||||
if (!m_Registry[attacker].SecondHit)
|
||||
{
|
||||
wep.ProcessingMultipleHits = true;
|
||||
m_Registry[attacker].SecondHit = true;
|
||||
wep.OnHit(attacker, defender, .6);
|
||||
m_Registry[attacker].SecondHit = false;
|
||||
}
|
||||
else if (wep.ProcessingMultipleHits)
|
||||
{
|
||||
wep.EndDualWield = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DualWieldTimer : Timer
|
||||
{
|
||||
public Mobile Owner { get; set; }
|
||||
public double DualHitChance { get; set; }
|
||||
public DateTime Expires { get; set; }
|
||||
public bool SecondHit { get; set; }
|
||||
|
||||
private readonly TimeSpan Duration = TimeSpan.FromSeconds(8);
|
||||
|
||||
public DualWieldTimer(Mobile owner, double dualHitChance)
|
||||
: base(TimeSpan.FromMilliseconds(250), TimeSpan.FromMilliseconds(250))
|
||||
{
|
||||
Owner = owner;
|
||||
DualHitChance = dualHitChance;
|
||||
|
||||
Expires = DateTime.UtcNow + Duration;
|
||||
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (DateTime.UtcNow > Expires)
|
||||
{
|
||||
RemoveFromRegistry(Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
319
Scripts/Abilities/Enhancement.cs
Normal file
319
Scripts/Abilities/Enhancement.cs
Normal file
@@ -0,0 +1,319 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class EnhancementAttributes
|
||||
{
|
||||
public string Title { get; set; }
|
||||
|
||||
public AosAttributes Attributes { get; private set; }
|
||||
public AosWeaponAttributes WeaponAttributes { get; private set; }
|
||||
public AosArmorAttributes ArmorAttributes { get; private set; }
|
||||
public SAAbsorptionAttributes AbsorptionAttributes { get; private set; }
|
||||
public ExtendedWeaponAttributes ExtendedWeaponAttributes { get; private set; }
|
||||
|
||||
public EnhancementAttributes(string title)
|
||||
{
|
||||
this.Title = title;
|
||||
this.Attributes = new AosAttributes(null);
|
||||
this.WeaponAttributes = new AosWeaponAttributes(null);
|
||||
this.ArmorAttributes = new AosArmorAttributes(null);
|
||||
this.AbsorptionAttributes = new SAAbsorptionAttributes(null);
|
||||
this.ExtendedWeaponAttributes = new ExtendedWeaponAttributes(null);
|
||||
}
|
||||
}
|
||||
|
||||
public class Enhancement
|
||||
{
|
||||
public static Dictionary<Mobile, List<EnhancementAttributes>> EnhancementList = new Dictionary<Mobile, List<EnhancementAttributes>>();
|
||||
|
||||
public static bool AddMobile(Mobile m)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
{
|
||||
EnhancementList.Add(m, new List<EnhancementAttributes>());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the mobile and/or attributes from the dictionary
|
||||
/// </summary>
|
||||
/// <param name="m"></param>
|
||||
/// <param name="title">null or default value will remove the entire entry. Add the title arg to remove only that element from the list.</param>
|
||||
/// <returns></returns>
|
||||
public static bool RemoveMobile(Mobile m, string title = null)
|
||||
{
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
if (title != null)
|
||||
{
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null && EnhancementList[m].Contains(match))
|
||||
{
|
||||
if(match.Attributes.BonusStr > 0)
|
||||
m.RemoveStatMod("MagicalEnhancementStr");
|
||||
|
||||
if (match.Attributes.BonusDex > 0)
|
||||
m.RemoveStatMod("MagicalEnhancementDex");
|
||||
|
||||
if (match.Attributes.BonusInt > 0)
|
||||
m.RemoveStatMod("MagicalEnhancementInt");
|
||||
|
||||
EnhancementList[m].Remove(match);
|
||||
}
|
||||
}
|
||||
|
||||
if(EnhancementList[m].Count == 0 || title == null)
|
||||
EnhancementList.Remove(m);
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
|
||||
m.Items.ForEach(i => i.InvalidateProperties());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, AosAttribute att)
|
||||
{
|
||||
if (m == null)
|
||||
return 0;
|
||||
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
int value = 0;
|
||||
EnhancementList[m].ForEach(attrs => value += attrs.Attributes[att]);
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetValue(Mobile m, AosAttribute att, int value, string title)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
AddMobile(m);
|
||||
|
||||
if (att == AosAttribute.BonusStr)
|
||||
{
|
||||
m.RemoveStatMod("MagicalEnhancementStr");
|
||||
m.AddStatMod(new StatMod(StatType.Str, "MagicalEnhancementStr", value, TimeSpan.Zero));
|
||||
}
|
||||
else if (att == AosAttribute.BonusDex)
|
||||
{
|
||||
m.RemoveStatMod("MagicalEnhancementDex");
|
||||
m.AddStatMod(new StatMod(StatType.Dex, "MagicalEnhancementDex", value, TimeSpan.Zero));
|
||||
}
|
||||
else if (att == AosAttribute.BonusInt)
|
||||
{
|
||||
m.RemoveStatMod("MagicalEnhancementInt");
|
||||
m.AddStatMod(new StatMod(StatType.Int, "MagicalEnhancementInt", value, TimeSpan.Zero));
|
||||
}
|
||||
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
match.Attributes[att] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = new EnhancementAttributes(title);
|
||||
match.Attributes[att] = value;
|
||||
|
||||
EnhancementList[m].Add(match);
|
||||
}
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, AosWeaponAttribute att)
|
||||
{
|
||||
if (m == null)
|
||||
return 0;
|
||||
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
int value = 0;
|
||||
EnhancementList[m].ForEach(attrs => value += attrs.WeaponAttributes[att]);
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetValue(Mobile m, AosWeaponAttribute att, int value, string title)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
AddMobile(m);
|
||||
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
match.WeaponAttributes[att] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = new EnhancementAttributes(title);
|
||||
match.WeaponAttributes[att] = value;
|
||||
|
||||
EnhancementList[m].Add(match);
|
||||
}
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, AosArmorAttribute att)
|
||||
{
|
||||
if (m == null)
|
||||
return 0;
|
||||
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
int value = 0;
|
||||
EnhancementList[m].ForEach(attrs => value += attrs.ArmorAttributes[att]);
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetValue(Mobile m, AosArmorAttribute att, int value, string title)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
AddMobile(m);
|
||||
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
match.ArmorAttributes[att] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = new EnhancementAttributes(title);
|
||||
match.ArmorAttributes[att] = value;
|
||||
|
||||
EnhancementList[m].Add(match);
|
||||
}
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, SAAbsorptionAttribute att)
|
||||
{
|
||||
if (m == null)
|
||||
return 0;
|
||||
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
int value = 0;
|
||||
EnhancementList[m].ForEach(attrs => value += attrs.AbsorptionAttributes[att]);
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetValue(Mobile m, SAAbsorptionAttribute att, int value, string title)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
AddMobile(m);
|
||||
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
match.AbsorptionAttributes[att] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = new EnhancementAttributes(title);
|
||||
match.AbsorptionAttributes[att] = value;
|
||||
|
||||
EnhancementList[m].Add(match);
|
||||
}
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
}
|
||||
|
||||
public static int GetValue(Mobile m, ExtendedWeaponAttribute att)
|
||||
{
|
||||
if (m == null)
|
||||
return 0;
|
||||
|
||||
if (EnhancementList.ContainsKey(m))
|
||||
{
|
||||
int value = 0;
|
||||
EnhancementList[m].ForEach(attrs => value += attrs.ExtendedWeaponAttributes[att]);
|
||||
return value;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void SetValue(Mobile m, ExtendedWeaponAttribute att, int value, string title)
|
||||
{
|
||||
if (!EnhancementList.ContainsKey(m))
|
||||
AddMobile(m);
|
||||
|
||||
EnhancementAttributes match = EnhancementList[m].FirstOrDefault(attrs => attrs.Title == title);
|
||||
|
||||
if (match != null)
|
||||
{
|
||||
match.ExtendedWeaponAttributes[att] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
match = new EnhancementAttributes(title);
|
||||
match.ExtendedWeaponAttributes[att] = value;
|
||||
|
||||
EnhancementList[m].Add(match);
|
||||
}
|
||||
|
||||
m.CheckStatTimers();
|
||||
m.UpdateResistances();
|
||||
m.Delta(MobileDelta.Stat | MobileDelta.WeaponDamage | MobileDelta.Hits | MobileDelta.Stam | MobileDelta.Mana);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
AOS.cs
|
||||
MagicalEnhancements.GetValue( m, attribute );
|
||||
Usage of setting total (intended use)
|
||||
MagicalEnhancements.SetValue( m, AosAttribute.Luck, 50 );
|
||||
Example of a timed stackable Enhancement (supports to an extent)
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public void Luckboon()
|
||||
{
|
||||
MagicalEnhancements.AddMobile( m );
|
||||
MagicalEnhancements.EnhancementList[m].Attributes.Luck += 200;
|
||||
Timer.DelayCall( TimeSpan.FromSeconds( 30 ), new TimerCallback( Expire ) );
|
||||
}
|
||||
|
||||
private void Expire()
|
||||
{
|
||||
if ( m_Mobile != null && MagicalEnhancements.EnhancementList.ContainsKey( m ) )
|
||||
MagicalEnhancements.EnhancementList[m].Attributes.Luck -= 200;
|
||||
}
|
||||
*/
|
||||
122
Scripts/Abilities/EnhancementTimer.cs
Normal file
122
Scripts/Abilities/EnhancementTimer.cs
Normal file
@@ -0,0 +1,122 @@
|
||||
// Created by Peoharen
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class EnhancementTimer : Timer
|
||||
{
|
||||
private readonly ArrayList AL = new ArrayList();
|
||||
private readonly Mobile m_Mobile;
|
||||
private readonly string m_Title;
|
||||
private int m_Duration;
|
||||
|
||||
public EnhancementTimer(Mobile m, int duration, string title, params object[] args)
|
||||
: base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
if (args.Length < 1 || (args.Length % 2) != 0)
|
||||
throw new Exception("EnhancementTimer: args.length must be an even number greater than 0");
|
||||
|
||||
Enhancement.AddMobile(m);
|
||||
this.m_Mobile = m;
|
||||
this.m_Title = title;
|
||||
this.m_Duration = duration;
|
||||
|
||||
AosAttribute att;
|
||||
AosWeaponAttribute weapon;
|
||||
AosArmorAttribute armor;
|
||||
SAAbsorptionAttribute absorb;
|
||||
int number = 0;
|
||||
|
||||
for (int i = 0; i < args.Length - 1; i += 2)
|
||||
{
|
||||
if (!(args[i + 1] is int))
|
||||
throw new Exception("EnhancementTimer: The second value must be an integer");
|
||||
|
||||
number = (int)args[i + 1];
|
||||
|
||||
if (args[i] is AosAttribute)
|
||||
{
|
||||
att = (AosAttribute)args[i];
|
||||
Enhancement.SetValue(m, att, (Enhancement.GetValue(m, att) + number), this.m_Title);
|
||||
this.AL.Add(att);
|
||||
this.AL.Add(number);
|
||||
}
|
||||
else if (args[i] is AosWeaponAttribute)
|
||||
{
|
||||
weapon = (AosWeaponAttribute)args[i];
|
||||
Enhancement.SetValue(m, weapon, (Enhancement.GetValue(m, weapon) + number), this.m_Title);
|
||||
this.AL.Add(weapon);
|
||||
this.AL.Add(number);
|
||||
}
|
||||
else if (args[i] is AosArmorAttribute)
|
||||
{
|
||||
armor = (AosArmorAttribute)args[i];
|
||||
Enhancement.SetValue(m, armor, (Enhancement.GetValue(m, armor) + number), this.m_Title);
|
||||
this.AL.Add(armor);
|
||||
this.AL.Add(number);
|
||||
}
|
||||
else if (args[i] is SAAbsorptionAttribute)
|
||||
{
|
||||
absorb = (SAAbsorptionAttribute)args[i];
|
||||
Enhancement.SetValue(m, absorb, (Enhancement.GetValue(m, absorb) + number), this.m_Title);
|
||||
this.AL.Add(absorb);
|
||||
this.AL.Add(number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
if (Enhancement.EnhancementList.ContainsKey(this.m_Mobile))
|
||||
{
|
||||
AosAttribute att;
|
||||
AosWeaponAttribute weapon;
|
||||
AosArmorAttribute armor;
|
||||
SAAbsorptionAttribute absorb;
|
||||
int number = 0;
|
||||
|
||||
for (int i = 0; i < this.AL.Count - 1; i += 2)
|
||||
{
|
||||
number = (int)this.AL[i + 1];
|
||||
|
||||
if (this.AL[i] is AosAttribute)
|
||||
{
|
||||
att = (AosAttribute)this.AL[i];
|
||||
Enhancement.SetValue(this.m_Mobile, att, (Enhancement.GetValue(this.m_Mobile, att) - number), this.m_Title);
|
||||
}
|
||||
else if (this.AL[i] is AosWeaponAttribute)
|
||||
{
|
||||
weapon = (AosWeaponAttribute)this.AL[i];
|
||||
Enhancement.SetValue(this.m_Mobile, weapon, (Enhancement.GetValue(this.m_Mobile, weapon) - number), this.m_Title);
|
||||
}
|
||||
else if (this.AL[i] is AosArmorAttribute)
|
||||
{
|
||||
armor = (AosArmorAttribute)this.AL[i];
|
||||
Enhancement.SetValue(this.m_Mobile, armor, (Enhancement.GetValue(this.m_Mobile, armor) - number), this.m_Title);
|
||||
}
|
||||
else if (this.AL[i] is SAAbsorptionAttribute)
|
||||
{
|
||||
absorb = (SAAbsorptionAttribute)this.AL[i];
|
||||
Enhancement.SetValue(this.m_Mobile, absorb, (Enhancement.GetValue(this.m_Mobile, absorb) - number), this.m_Title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.Stop();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
this.m_Duration--;
|
||||
|
||||
if (this.m_Mobile == null)
|
||||
this.Stop();
|
||||
|
||||
if (this.m_Duration < 0)
|
||||
{
|
||||
this.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
91
Scripts/Abilities/Feint.cs
Normal file
91
Scripts/Abilities/Feint.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Gain a defensive advantage over your primary opponent for a short time.
|
||||
/// </summary>
|
||||
public class Feint : WeaponAbility
|
||||
{
|
||||
private static Dictionary<Mobile, FeintTimer> m_Registry = new Dictionary<Mobile, FeintTimer>();
|
||||
public static Dictionary<Mobile, FeintTimer> Registry { get { return m_Registry; } }
|
||||
|
||||
public Feint()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 30; } }
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public override void OnHit( Mobile attacker, Mobile defender, int damage )
|
||||
{
|
||||
if( !Validate( attacker ) || !CheckMana( attacker, true ) )
|
||||
return;
|
||||
|
||||
if( Registry.ContainsKey( attacker ) )
|
||||
{
|
||||
if (m_Registry[attacker] != null)
|
||||
m_Registry[attacker].Stop();
|
||||
|
||||
Registry.Remove(attacker);
|
||||
}
|
||||
|
||||
bool creature = attacker is BaseCreature;
|
||||
ClearCurrentAbility( attacker );
|
||||
|
||||
attacker.SendLocalizedMessage( 1063360 ); // You baffle your target with a feint!
|
||||
defender.SendLocalizedMessage( 1063361 ); // You were deceived by an attacker's feint!
|
||||
|
||||
attacker.FixedParticles( 0x3728, 1, 13, 0x7F3, 0x962, 0, EffectLayer.Waist );
|
||||
attacker.PlaySound(0x525);
|
||||
|
||||
double skill = creature ? attacker.Skills[SkillName.Bushido].Value :
|
||||
Math.Max(attacker.Skills[SkillName.Ninjitsu].Value, attacker.Skills[SkillName.Bushido].Value);
|
||||
|
||||
int bonus = (int)(20.0 + 3.0 * (skill - 50.0) / 7.0);
|
||||
|
||||
FeintTimer t = new FeintTimer( attacker, defender, bonus ); //20-50 % decrease
|
||||
|
||||
t.Start();
|
||||
m_Registry[attacker] = t;
|
||||
|
||||
string args = String.Format("{0}\t{1}", defender.Name, bonus);
|
||||
BuffInfo.AddBuff(attacker, new BuffInfo(BuffIcon.Feint, 1151308, 1151307, TimeSpan.FromSeconds(6), attacker, args));
|
||||
|
||||
if (creature)
|
||||
PetTrainingHelper.OnWeaponAbilityUsed((BaseCreature)attacker, SkillName.Bushido);
|
||||
}
|
||||
|
||||
public class FeintTimer : Timer
|
||||
{
|
||||
private Mobile m_Owner;
|
||||
private Mobile m_Enemy;
|
||||
private int m_DamageReduction;
|
||||
|
||||
public Mobile Owner { get { return m_Owner; } }
|
||||
public Mobile Enemy { get { return m_Enemy; } }
|
||||
|
||||
public int DamageReduction { get { return m_DamageReduction; } }
|
||||
|
||||
public FeintTimer(Mobile owner, Mobile enemy, int DamageReduction)
|
||||
: base(TimeSpan.FromSeconds(6.0))
|
||||
{
|
||||
m_Owner = owner;
|
||||
m_Enemy = enemy;
|
||||
m_DamageReduction = DamageReduction;
|
||||
Priority = TimerPriority.FiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
Registry.Remove(m_Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
Scripts/Abilities/Focus.cs
Normal file
119
Scripts/Abilities/Focus.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using Server.Mobiles;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class Focus
|
||||
{
|
||||
private static Dictionary<Mobile, FocusInfo> m_Table = new Dictionary<Mobile, FocusInfo>();
|
||||
private static int DefaultDamageBonus = -40;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.Login += OnLogin;
|
||||
}
|
||||
|
||||
public class FocusInfo
|
||||
{
|
||||
public Mobile Target { get; set; }
|
||||
public int DamageBonus { get; set; }
|
||||
|
||||
public FocusInfo(Mobile defender, int bonus)
|
||||
{
|
||||
Target = defender;
|
||||
DamageBonus = bonus;
|
||||
}
|
||||
}
|
||||
|
||||
public Focus()
|
||||
{
|
||||
}
|
||||
|
||||
public static void OnLogin(LoginEventArgs e)
|
||||
{
|
||||
var pm = e.Mobile as PlayerMobile;
|
||||
|
||||
if (pm != null)
|
||||
{
|
||||
UpdateBuff(pm);
|
||||
}
|
||||
}
|
||||
|
||||
public static void UpdateBuff(Mobile from, Mobile target = null)
|
||||
{
|
||||
var item = from.FindItemOnLayer(Layer.TwoHanded);
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
item = from.FindItemOnLayer(Layer.OneHanded);
|
||||
}
|
||||
|
||||
if (item == null)
|
||||
{
|
||||
if (m_Table.ContainsKey(from))
|
||||
{
|
||||
m_Table.Remove(from);
|
||||
BuffInfo.RemoveBuff(from, BuffIcon.RageFocusingBuff);
|
||||
}
|
||||
}
|
||||
else if (item is BaseWeapon && ((BaseWeapon)item).ExtendedWeaponAttributes.Focus > 0)
|
||||
{
|
||||
if (m_Table.ContainsKey(from))
|
||||
{
|
||||
FocusInfo info = m_Table[from];
|
||||
|
||||
BuffInfo.AddBuff(from, new BuffInfo(BuffIcon.RageFocusingBuff, 1151393, 1151394,
|
||||
String.Format("{0}\t{1}", info.Target == null ? "NONE" : info.Target.Name, info.DamageBonus)));
|
||||
}
|
||||
|
||||
m_Table[from] = new FocusInfo(target, DefaultDamageBonus);
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBonus(Mobile from, Mobile target)
|
||||
{
|
||||
if (m_Table.ContainsKey(from))
|
||||
{
|
||||
FocusInfo info = m_Table[from];
|
||||
|
||||
if (info.Target == target)
|
||||
{
|
||||
return info.DamageBonus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void OnHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (m_Table.ContainsKey(attacker))
|
||||
{
|
||||
FocusInfo info = m_Table[attacker];
|
||||
|
||||
if (info.Target == null)
|
||||
{
|
||||
info.DamageBonus -= 10;
|
||||
}
|
||||
else if (info.Target == defender)
|
||||
{
|
||||
if (info.DamageBonus < -40)
|
||||
info.DamageBonus += 10;
|
||||
else
|
||||
info.DamageBonus += 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info.DamageBonus >= -50)
|
||||
info.DamageBonus = DefaultDamageBonus;
|
||||
}
|
||||
|
||||
if (info.Target != defender)
|
||||
info.Target = defender;
|
||||
|
||||
UpdateBuff(attacker, defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
168
Scripts/Abilities/ForceArrow.cs
Normal file
168
Scripts/Abilities/ForceArrow.cs
Normal file
@@ -0,0 +1,168 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class ForceArrow : WeaponAbility
|
||||
{
|
||||
public ForceArrow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 20; } }
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1074381); // You fire an arrow of pure force.
|
||||
defender.SendLocalizedMessage(1074382); // You are struck by a force arrow!
|
||||
|
||||
if (.4 > Utility.RandomDouble())
|
||||
{
|
||||
defender.Combatant = null;
|
||||
defender.Warmode = false;
|
||||
}
|
||||
|
||||
ForceArrowInfo info = GetInfo(attacker, defender);
|
||||
|
||||
if (info == null)
|
||||
BeginForceArrow(attacker, defender);
|
||||
else
|
||||
{
|
||||
if (info.Timer != null && info.Timer.Running)
|
||||
{
|
||||
info.Timer.IncreaseExpiration();
|
||||
|
||||
BuffInfo.RemoveBuff(defender, BuffIcon.ForceArrow);
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.ForceArrow, 1151285, 1151286, info.DefenseChanceMalus.ToString()));
|
||||
}
|
||||
}
|
||||
|
||||
Spell spell = defender.Spell as Spell;
|
||||
|
||||
if (spell != null && spell.IsCasting)
|
||||
spell.Disturb(DisturbType.Hurt, false, true);
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, List<ForceArrowInfo>> m_Table = new Dictionary<Mobile, List<ForceArrowInfo>>();
|
||||
|
||||
public static void BeginForceArrow(Mobile attacker, Mobile defender)
|
||||
{
|
||||
ForceArrowInfo info = new ForceArrowInfo(attacker, defender);
|
||||
info.Timer = new ForceArrowTimer(info);
|
||||
|
||||
if (!m_Table.ContainsKey(attacker))
|
||||
m_Table[attacker] = new List<ForceArrowInfo>();
|
||||
|
||||
m_Table[attacker].Add(info);
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.ForceArrow, 1151285, 1151286, info.DefenseChanceMalus.ToString()));
|
||||
}
|
||||
|
||||
public static void EndForceArrow(ForceArrowInfo info)
|
||||
{
|
||||
if (info == null)
|
||||
return;
|
||||
|
||||
Mobile attacker = info.Attacker;
|
||||
|
||||
if (m_Table.ContainsKey(attacker) && m_Table[attacker].Contains(info))
|
||||
{
|
||||
m_Table[attacker].Remove(info);
|
||||
|
||||
if (m_Table[attacker].Count == 0)
|
||||
m_Table.Remove(attacker);
|
||||
}
|
||||
|
||||
BuffInfo.RemoveBuff(info.Defender, BuffIcon.ForceArrow);
|
||||
}
|
||||
|
||||
public static bool HasForceArrow(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!m_Table.ContainsKey(attacker))
|
||||
return false;
|
||||
|
||||
foreach (ForceArrowInfo info in m_Table[attacker])
|
||||
{
|
||||
if (info.Defender == defender)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ForceArrowInfo GetInfo(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!m_Table.ContainsKey(attacker))
|
||||
return null;
|
||||
|
||||
foreach (ForceArrowInfo info in m_Table[attacker])
|
||||
{
|
||||
if (info.Defender == defender)
|
||||
return info;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public class ForceArrowInfo
|
||||
{
|
||||
private Mobile m_Attacker;
|
||||
private Mobile m_Defender;
|
||||
private ForceArrowTimer m_Timer;
|
||||
private int m_DefenseChanceMalus;
|
||||
|
||||
public Mobile Attacker { get { return m_Attacker; } }
|
||||
public Mobile Defender { get { return m_Defender; } }
|
||||
public ForceArrowTimer Timer { get { return m_Timer; } set { m_Timer = value; } }
|
||||
public int DefenseChanceMalus { get { return m_DefenseChanceMalus; } set { m_DefenseChanceMalus = value; } }
|
||||
|
||||
public ForceArrowInfo(Mobile attacker, Mobile defender)
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
m_DefenseChanceMalus = 10;
|
||||
}
|
||||
}
|
||||
|
||||
public class ForceArrowTimer : Timer
|
||||
{
|
||||
private ForceArrowInfo m_Info;
|
||||
private DateTime m_Expires;
|
||||
|
||||
public ForceArrowTimer(ForceArrowInfo info)
|
||||
: base(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
m_Info = info;
|
||||
Priority = TimerPriority.OneSecond;
|
||||
|
||||
m_Expires = DateTime.UtcNow + TimeSpan.FromSeconds(10);
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Expires < DateTime.UtcNow)
|
||||
{
|
||||
Stop();
|
||||
EndForceArrow(m_Info);
|
||||
}
|
||||
}
|
||||
|
||||
public void IncreaseExpiration()
|
||||
{
|
||||
m_Expires = m_Expires + TimeSpan.FromSeconds(2);
|
||||
|
||||
m_Info.DefenseChanceMalus += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
133
Scripts/Abilities/ForceofNature.cs
Normal file
133
Scripts/Abilities/ForceofNature.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using Server;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class ForceOfNature : WeaponAbility
|
||||
{
|
||||
public ForceOfNature()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 35; } }
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1074374); // You attack your enemy with the force of nature!
|
||||
defender.SendLocalizedMessage(1074375); // You are assaulted with great force!
|
||||
|
||||
defender.PlaySound(0x22F);
|
||||
defender.FixedParticles(0x36CB, 1, 9, 9911, 67, 5, EffectLayer.Head);
|
||||
defender.FixedParticles(0x374A, 1, 17, 9502, 1108, 4, (EffectLayer)255);
|
||||
|
||||
if (m_Table.ContainsKey(attacker))
|
||||
Remove(attacker);
|
||||
|
||||
ForceOfNatureTimer t = new ForceOfNatureTimer(attacker, defender);
|
||||
t.Start();
|
||||
|
||||
m_Table[attacker] = t;
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, ForceOfNatureTimer> m_Table = new Dictionary<Mobile, ForceOfNatureTimer>();
|
||||
|
||||
public static bool Remove(Mobile m)
|
||||
{
|
||||
ForceOfNatureTimer t;
|
||||
|
||||
m_Table.TryGetValue(m, out t);
|
||||
|
||||
if (t == null)
|
||||
return false;
|
||||
|
||||
t.Stop();
|
||||
m_Table.Remove(m);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void OnHit(Mobile from, Mobile target)
|
||||
{
|
||||
if (m_Table.ContainsKey(from))
|
||||
{
|
||||
ForceOfNatureTimer t = m_Table[from];
|
||||
|
||||
t.Hits++;
|
||||
t.LastHit = DateTime.Now;
|
||||
|
||||
if (t.Hits % 12 == 0)
|
||||
{
|
||||
int duration = target.Skills[SkillName.MagicResist].Value >= 90.0 ? 1 : 2;
|
||||
target.Paralyze(TimeSpan.FromSeconds(duration));
|
||||
t.Hits = 0;
|
||||
|
||||
from.SendLocalizedMessage(1004013); // You successfully stun your opponent!
|
||||
target.SendLocalizedMessage(1004014); // You have been stunned!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetBonus(Mobile from, Mobile target)
|
||||
{
|
||||
if (m_Table.ContainsKey(from))
|
||||
{
|
||||
ForceOfNatureTimer t = m_Table[from];
|
||||
|
||||
if (t.Target == target)
|
||||
{
|
||||
int bonus = Math.Max(50, from.Str - 50);
|
||||
if (bonus > 100) bonus = 100;
|
||||
return bonus;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private class ForceOfNatureTimer : Timer
|
||||
{
|
||||
private Mobile m_Target, m_From;
|
||||
|
||||
private DateTime m_LastHit;
|
||||
private int m_Tick, m_Hits;
|
||||
|
||||
public Mobile Target { get { return m_Target; } }
|
||||
public Mobile From { get { return m_From; } }
|
||||
public int Hits { get { return m_Hits; } set { m_Hits = value; } }
|
||||
public DateTime LastHit { get { return m_LastHit; } set { m_LastHit = value; } }
|
||||
|
||||
public ForceOfNatureTimer(Mobile from, Mobile target)
|
||||
: base(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
m_Target = target;
|
||||
m_From = from;
|
||||
m_Tick = 0;
|
||||
m_Hits = 1;
|
||||
m_LastHit = DateTime.Now;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
m_Tick++;
|
||||
|
||||
if (!m_From.Alive || !m_Target.Alive || m_Target.Map != m_From.Map || m_Target.GetDistanceToSqrt(m_From.Location) > 10 || m_LastHit + TimeSpan.FromSeconds(20) < DateTime.Now || m_Tick > 36)
|
||||
{
|
||||
Server.Items.ForceOfNature.Remove(m_From);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_Tick == 1)
|
||||
{
|
||||
int damage = Utility.RandomMinMax(15, 35);
|
||||
|
||||
AOS.Damage(m_Target, m_From, damage, false, 0, 0, 0, 0, 0, 0, 100, false, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
146
Scripts/Abilities/FrenziedWhirlwind.cs
Normal file
146
Scripts/Abilities/FrenziedWhirlwind.cs
Normal file
@@ -0,0 +1,146 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server;
|
||||
using Server.Spells;
|
||||
using Server.Engines.PartySystem;
|
||||
using Server.Network;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A quick attack to all enemies in range of your weapon that causes damage over time. Requires Bushido or Ninjitsu skill.
|
||||
/// </summary>
|
||||
public class FrenziedWhirlwind : WeaponAbility
|
||||
{
|
||||
public FrenziedWhirlwind()
|
||||
{
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 30; } }
|
||||
|
||||
private static Dictionary<Mobile, Timer> m_Registry = new Dictionary<Mobile, Timer>();
|
||||
public static Dictionary<Mobile, Timer> Registry { get { return m_Registry; } }
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker)) //Mana check after check that there are targets
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
Map map = attacker.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
var targets = SpellHelper.AcquireIndirectTargets(attacker, attacker.Location, attacker.Map, 2).OfType<Mobile>().ToList();
|
||||
|
||||
if (targets.Count > 0)
|
||||
{
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
attacker.FixedEffect(0x3728, 10, 15);
|
||||
attacker.PlaySound(0x2A1);
|
||||
|
||||
if (m_Registry.ContainsKey(attacker))
|
||||
{
|
||||
RemoveFromRegistry(attacker);
|
||||
}
|
||||
|
||||
m_Registry[attacker] = new InternalTimer(attacker, targets);
|
||||
|
||||
foreach (var pm in targets.OfType<PlayerMobile>())
|
||||
{
|
||||
BuffInfo.AddBuff(pm, new BuffInfo(BuffIcon.SplinteringEffect, 1153804, 1028852, TimeSpan.FromSeconds(2.0), pm));
|
||||
}
|
||||
|
||||
if (defender is PlayerMobile && attacker is PlayerMobile)
|
||||
{
|
||||
defender.SendSpeedControl(SpeedControlType.WalkSpeed);
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.SplinteringEffect, 1153804, 1152144, TimeSpan.FromSeconds(2.0), defender));
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(2), mob => mob.SendSpeedControl(SpeedControlType.Disable), defender);
|
||||
}
|
||||
|
||||
if (attacker is BaseCreature)
|
||||
PetTrainingHelper.OnWeaponAbilityUsed((BaseCreature)attacker, SkillName.Ninjitsu);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RemoveFromRegistry(Mobile from)
|
||||
{
|
||||
if (m_Registry.ContainsKey(from))
|
||||
{
|
||||
m_Registry[from].Stop();
|
||||
m_Registry.Remove(from);
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private Mobile m_Attacker;
|
||||
private List<Mobile> m_List;
|
||||
private long m_Start;
|
||||
|
||||
public InternalTimer(Mobile attacker, List<Mobile> list)
|
||||
: base(TimeSpan.FromMilliseconds(500), TimeSpan.FromMilliseconds(500))
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_List = list;
|
||||
|
||||
m_Start = Core.TickCount;
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
DoHit();
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Attacker.Alive)
|
||||
DoHit();
|
||||
|
||||
if (!m_Attacker.Alive || m_Start + 2000 < Core.TickCount)
|
||||
{
|
||||
ColUtility.Free(m_List);
|
||||
Server.Items.FrenziedWhirlwind.RemoveFromRegistry(m_Attacker);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoHit()
|
||||
{
|
||||
if (m_List == null)
|
||||
return;
|
||||
|
||||
foreach (Mobile m in m_List)
|
||||
{
|
||||
if (m_Attacker.InRange(m.Location, 2) && m.Alive && m.Map == m_Attacker.Map)
|
||||
{
|
||||
m_Attacker.FixedEffect(0x3728, 10, 15);
|
||||
m_Attacker.PlaySound(0x2A1);
|
||||
|
||||
int skill = m_Attacker is BaseCreature ? (int)m_Attacker.Skills[SkillName.Ninjitsu].Value :
|
||||
(int)Math.Max(m_Attacker.Skills[SkillName.Bushido].Value, m_Attacker.Skills[SkillName.Ninjitsu].Value);
|
||||
|
||||
var baseMin = (int)Math.Max(5, (skill / 50) * 5);
|
||||
AOS.Damage(m, m_Attacker, Utility.RandomMinMax(baseMin, (baseMin * 3) + 2), 100, 0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Scripts/Abilities/InfectiousStrike.cs
Normal file
123
Scripts/Abilities/InfectiousStrike.cs
Normal file
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This special move represents a significant change to the use of poisons in Age of Shadows.
|
||||
/// Now, only certain weapon types — those that have Infectious Strike as an available special move — will be able to be poisoned.
|
||||
/// Targets will no longer be poisoned at random when hit by poisoned weapons.
|
||||
/// Instead, the wielder must use this ability to deliver the venom.
|
||||
/// While no skill in Poisoning is directly required to use this ability, being knowledgeable in the application and use of toxins
|
||||
/// will allow a character to use Infectious Strike at reduced mana cost and with a chance to inflict more deadly poison on his victim.
|
||||
/// With this change, weapons will no longer be corroded by poison.
|
||||
/// Level 5 poison will be possible when using this special move.
|
||||
/// </summary>
|
||||
public class InfectiousStrike : WeaponAbility
|
||||
{
|
||||
public InfectiousStrike()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool RequiresSecondarySkill(Mobile from)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return SkillName.Poisoning;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
Poison p = weapon.Poison;
|
||||
|
||||
if (p == null || weapon.PoisonCharges <= 0)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061141); // Your weapon must have a dose of poison to perform an infectious strike!
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
// Skill Masteries
|
||||
int noChargeChance = Server.Spells.SkillMasteries.MasteryInfo.NonPoisonConsumeChance(attacker);
|
||||
|
||||
if (noChargeChance == 0 || noChargeChance < Utility.Random(100))
|
||||
--weapon.PoisonCharges;
|
||||
else
|
||||
attacker.SendLocalizedMessage(1156095); // Your mastery of poisoning allows you to use your poison charge without consuming it.
|
||||
|
||||
// Infectious strike special move now uses poisoning skill to help determine potency
|
||||
int maxLevel = 0;
|
||||
if (p == Poison.DarkGlow)
|
||||
{
|
||||
maxLevel = 10 + (attacker.Skills[SkillName.Poisoning].Fixed / 333);
|
||||
if (maxLevel > 13)
|
||||
maxLevel = 13;
|
||||
}
|
||||
else if (p == Poison.Parasitic)
|
||||
{
|
||||
maxLevel = 14 + (attacker.Skills[SkillName.Poisoning].Fixed / 250);
|
||||
if (maxLevel > 18)
|
||||
maxLevel = 18;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxLevel = attacker.Skills[SkillName.Poisoning].Fixed / 200;
|
||||
if (maxLevel > 5)
|
||||
maxLevel = 5;
|
||||
}
|
||||
|
||||
if (maxLevel < 0)
|
||||
maxLevel = 0;
|
||||
if (p.Level > maxLevel) // If they don't have enough Poisoning Skill for the potion strength, lower it.
|
||||
p = Poison.GetPoison(maxLevel);
|
||||
|
||||
if ((attacker.Skills[SkillName.Poisoning].Value / 100.0) > Utility.RandomDouble())
|
||||
{
|
||||
if (p !=null && p.Level + 1 <= maxLevel)
|
||||
{
|
||||
int level = p.Level + 1;
|
||||
Poison newPoison = Poison.GetPoison(level);
|
||||
|
||||
if (newPoison != null)
|
||||
{
|
||||
p = newPoison;
|
||||
|
||||
attacker.SendLocalizedMessage(1060080); // Your precise strike has increased the level of the poison by 1
|
||||
defender.SendLocalizedMessage(1060081); // The poison seems extra effective!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
defender.PlaySound(0xDD);
|
||||
defender.FixedParticles(0x3728, 244, 25, 9941, 1266, 0, EffectLayer.Waist);
|
||||
|
||||
if (defender.ApplyPoison(attacker, p) != ApplyPoisonResult.Immune)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1008096, true, defender.Name); // You have poisoned your target :
|
||||
defender.SendLocalizedMessage(1008097, false, attacker.Name); // : poisoned you!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Scripts/Abilities/InfusedThrow.cs
Normal file
45
Scripts/Abilities/InfusedThrow.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
// The projectile will be infused with energy by the attacker causing it to do more damage and stun or dismount the target.
|
||||
// The player infuses their throwing projectile with mystical power.
|
||||
// The infused projectile will dismount the target if possible; otherwise it will temporarily stun the target.
|
||||
// The target will be hit with chaos damage regardless of whether they were dismounted or paralyzed.
|
||||
public class InfusedThrow : WeaponAbility
|
||||
{
|
||||
public override int BaseMana { get { return 25; } }
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1149563); //The infused projectile strikes a target!
|
||||
defender.SendLocalizedMessage(1149564); //You are struck by the infused projectile and take damage!
|
||||
|
||||
AOS.Damage(defender, attacker, 15, false, 0, 0, 0, 0, 0, 100, 0, false);
|
||||
|
||||
IMount mount = defender.Mount;
|
||||
|
||||
if ((defender.Mounted || defender.Flying || Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender)) && !attacker.Mounted && !attacker.Flying && !(defender is ChaosDragoon) && !(defender is ChaosDragoonElite))
|
||||
{
|
||||
defender.PlaySound(0x140);
|
||||
defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist);
|
||||
|
||||
Server.Items.Dismount.DoDismount(attacker, defender, mount, 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.PlaySound(0x204);
|
||||
|
||||
TimeSpan duration = defender.Player ? TimeSpan.FromSeconds(3.0) : TimeSpan.FromSeconds(6.0);
|
||||
defender.Paralyze(duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Scripts/Abilities/LightningArrow.cs
Normal file
88
Scripts/Abilities/LightningArrow.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class LightningArrow : WeaponAbility
|
||||
{
|
||||
public LightningArrow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ConsumeAmmo
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
Map map = attacker.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
if (!this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
List<Mobile> targets = new List<Mobile>();
|
||||
IPooledEnumerable eable = defender.GetMobilesInRange(5);
|
||||
|
||||
foreach(Mobile m in eable)
|
||||
{
|
||||
if (m != defender && m != attacker && SpellHelper.ValidIndirectTarget(attacker, m))
|
||||
{
|
||||
if (m == null || m.Deleted || m.Map != attacker.Map || !m.Alive || !attacker.CanSee(m) || !attacker.CanBeHarmful(m))
|
||||
continue;
|
||||
|
||||
if (!attacker.InRange(m, weapon.MaxRange) || !attacker.InLOS(m))
|
||||
continue;
|
||||
|
||||
targets.Add(m);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
defender.BoltEffect(0);
|
||||
|
||||
if (targets.Count > 0)
|
||||
{
|
||||
while (targets.Count > 2)
|
||||
{
|
||||
targets.Remove(targets[Utility.Random(targets.Count)]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < targets.Count; ++i)
|
||||
{
|
||||
Mobile m = targets[i];
|
||||
|
||||
m.BoltEffect(0);
|
||||
|
||||
AOS.Damage(m, attacker, Utility.RandomMinMax(29, 40), 0, 0, 0, 0, 100);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(targets);
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Scripts/Abilities/MortalStrike.cs
Normal file
127
Scripts/Abilities/MortalStrike.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// The assassin's friend.
|
||||
/// A successful Mortal Strike will render its victim unable to heal any damage for several seconds.
|
||||
/// Use a gruesome follow-up to finish off your foe.
|
||||
/// </summary>
|
||||
public class MortalStrike : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan PlayerDuration = TimeSpan.FromSeconds(6.0);
|
||||
public static readonly TimeSpan NPCDuration = TimeSpan.FromSeconds(12.0);
|
||||
|
||||
private static readonly Dictionary<Mobile, Timer> m_Table = new Dictionary<Mobile, Timer>();
|
||||
private static readonly List<Mobile> m_EffectReduction = new List<Mobile>();
|
||||
|
||||
public MortalStrike()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
public static bool IsWounded(Mobile m)
|
||||
{
|
||||
return m_Table.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void BeginWound(Mobile m, TimeSpan duration)
|
||||
{
|
||||
Timer t;
|
||||
|
||||
if (m_Table.ContainsKey(m))
|
||||
{
|
||||
EndWound(m, true);
|
||||
}
|
||||
|
||||
if (Core.HS && m_EffectReduction.Contains(m))
|
||||
{
|
||||
double d = duration.TotalSeconds;
|
||||
duration = TimeSpan.FromSeconds(d / 2);
|
||||
}
|
||||
|
||||
t = new InternalTimer(m, duration);
|
||||
m_Table[m] = t;
|
||||
|
||||
t.Start();
|
||||
|
||||
m.YellowHealthbar = true;
|
||||
BuffInfo.AddBuff(m, new BuffInfo(BuffIcon.MortalStrike, 1075810, 1075811, duration, m));
|
||||
}
|
||||
|
||||
public static void EndWound(Mobile m, bool natural = false)
|
||||
{
|
||||
if (!IsWounded(m))
|
||||
return;
|
||||
|
||||
Timer t = m_Table[m];
|
||||
|
||||
if (t != null)
|
||||
t.Stop();
|
||||
|
||||
m_Table.Remove(m);
|
||||
|
||||
BuffInfo.RemoveBuff(m, BuffIcon.MortalStrike);
|
||||
|
||||
m.YellowHealthbar = false;
|
||||
m.SendLocalizedMessage(1060208); // You are no longer mortally wounded.
|
||||
|
||||
if (Core.HS && natural && !m_EffectReduction.Contains(m))
|
||||
{
|
||||
m_EffectReduction.Add(m);
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(8), () =>
|
||||
{
|
||||
if (m_EffectReduction.Contains(m))
|
||||
m_EffectReduction.Remove(m);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060086); // You deliver a mortal wound!
|
||||
defender.SendLocalizedMessage(1060087); // You have been mortally wounded!
|
||||
|
||||
defender.PlaySound(0x1E1);
|
||||
defender.FixedParticles(0x37B9, 244, 25, 9944, 31, 0, EffectLayer.Waist);
|
||||
|
||||
// Do not reset timer if one is already in place.
|
||||
if (Core.HS || !IsWounded(defender))
|
||||
{
|
||||
if (Spells.SkillMasteries.ResilienceSpell.UnderEffects(defender)) //Halves time
|
||||
BeginWound(defender, defender.Player ? TimeSpan.FromSeconds(3.0) : TimeSpan.FromSeconds(6));
|
||||
else
|
||||
BeginWound(defender, defender.Player ? PlayerDuration : NPCDuration);
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
public InternalTimer(Mobile m, TimeSpan duration)
|
||||
: base(duration)
|
||||
{
|
||||
m_Mobile = m;
|
||||
Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndWound(m_Mobile, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Scripts/Abilities/MovingShot.cs
Normal file
57
Scripts/Abilities/MovingShot.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Available on some crossbows, this special move allows archers to fire while on the move.
|
||||
/// This shot is somewhat less accurate than normal, but the ability to fire while running is a clear advantage.
|
||||
/// </summary>
|
||||
public class MovingShot : WeaponAbility
|
||||
{
|
||||
public MovingShot()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override int AccuracyBonus
|
||||
{
|
||||
get
|
||||
{
|
||||
return Core.TOL ? -35 : -25;
|
||||
}
|
||||
}
|
||||
public override bool ValidatesDuringHit
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
return (this.Validate(attacker) && this.CheckMana(attacker, true));
|
||||
}
|
||||
|
||||
public override void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060089); // You fail to execute your special move
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
//Validates in OnSwing for accuracy scalar
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060216); // Your shot was successful
|
||||
}
|
||||
}
|
||||
}
|
||||
83
Scripts/Abilities/MysticArc.cs
Normal file
83
Scripts/Abilities/MysticArc.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
// The thrown projectile will arc to a second target after hitting the primary target. Chaos energy will burst from the projectile at each target.
|
||||
// This will only hit targets that are in combat with the user.
|
||||
public class MysticArc : WeaponAbility
|
||||
{
|
||||
private readonly int m_Damage = 15;
|
||||
private Mobile m_Target;
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.CheckMana(attacker, true) && defender != null)
|
||||
return;
|
||||
|
||||
BaseThrown weapon = attacker.Weapon as BaseThrown;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
List<Mobile> targets = new List<Mobile>();
|
||||
IPooledEnumerable eable = attacker.GetMobilesInRange(weapon.MaxRange);
|
||||
|
||||
foreach (Mobile m in eable)
|
||||
{
|
||||
if (m == defender)
|
||||
continue;
|
||||
|
||||
if (m.Combatant != attacker)
|
||||
continue;
|
||||
|
||||
targets.Add(m);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
if (targets.Count > 0)
|
||||
this.m_Target = targets[Utility.Random(targets.Count)];
|
||||
|
||||
AOS.Damage(defender, attacker, this.m_Damage, 0, 0, 0, 0, 0, 100);
|
||||
|
||||
if (this.m_Target != null)
|
||||
{
|
||||
defender.MovingEffect(this.m_Target, weapon.ItemID, 18, 1, false, false);
|
||||
Timer.DelayCall(TimeSpan.FromMilliseconds(333.0), new TimerCallback(ThrowAgain));
|
||||
this.m_Mobile = attacker;
|
||||
}
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
}
|
||||
|
||||
public void ThrowAgain()
|
||||
{
|
||||
if (this.m_Target != null && this.m_Mobile != null)
|
||||
{
|
||||
BaseThrown weapon = this.m_Mobile.Weapon as BaseThrown;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
if (WeaponAbility.GetCurrentAbility(this.m_Mobile) is MysticArc)
|
||||
ClearCurrentAbility(this.m_Mobile);
|
||||
|
||||
if (weapon.CheckHit(this.m_Mobile, this.m_Target))
|
||||
{
|
||||
weapon.OnHit(this.m_Mobile, this.m_Target, 0.0);
|
||||
AOS.Damage(this.m_Target, this.m_Mobile, this.m_Damage, 0, 0, 0, 0, 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
99
Scripts/Abilities/NerveStrike.cs
Normal file
99
Scripts/Abilities/NerveStrike.cs
Normal file
@@ -0,0 +1,99 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Does damage and paralyses your opponent for a short time.
|
||||
/// </summary>
|
||||
public class NerveStrike : WeaponAbility
|
||||
{
|
||||
public NerveStrike()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (this.GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1070768, "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (!Core.ML && defender.Frozen)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061923); // The target is already frozen.
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
bool immune = Server.Items.ParalyzingBlow.IsImmune(defender);
|
||||
bool doEffects = false;
|
||||
|
||||
if (Core.ML)
|
||||
{
|
||||
AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + Utility.Random(10)), true, 100, 0, 0, 0, 0); //0-25
|
||||
|
||||
if (!immune && ((150.0 / 7.0 + (4.0 * attacker.Skills[SkillName.Bushido].Value) / 7.0) / 100.0) > Utility.RandomDouble())
|
||||
{
|
||||
defender.Paralyze(TimeSpan.FromSeconds(2.0));
|
||||
doEffects = true;
|
||||
}
|
||||
|
||||
if(attacker is BaseCreature)
|
||||
PetTrainingHelper.OnWeaponAbilityUsed((BaseCreature)attacker, SkillName.Bushido);
|
||||
}
|
||||
else
|
||||
{
|
||||
AOS.Damage(defender, attacker, (int)(15.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 10), true, 100, 0, 0, 0, 0); //10-25
|
||||
|
||||
if(!immune)
|
||||
{
|
||||
defender.Freeze(TimeSpan.FromSeconds(2.0));
|
||||
doEffects = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!immune)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1063356); // You cripple your target with a nerve strike!
|
||||
defender.SendLocalizedMessage(1063357); // Your attacker dealt a crippling nerve strike!
|
||||
}
|
||||
else
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
}
|
||||
|
||||
if (doEffects)
|
||||
{
|
||||
attacker.PlaySound(0x204);
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.FixedParticles(0x37C4, 1, 8, 0x13AF, 0, 0, EffectLayer.Waist);
|
||||
}
|
||||
|
||||
Server.Items.ParalyzingBlow.BeginImmunity(defender, Server.Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
127
Scripts/Abilities/ParalyzingBlow.cs
Normal file
127
Scripts/Abilities/ParalyzingBlow.cs
Normal file
@@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A successful Paralyzing Blow will leave the target stunned, unable to move, attack, or cast spells, for a few seconds.
|
||||
/// </summary>
|
||||
public class ParalyzingBlow : WeaponAbility
|
||||
{
|
||||
public static readonly TimeSpan PlayerFreezeDuration = TimeSpan.FromSeconds(3.0);
|
||||
public static readonly TimeSpan NPCFreezeDuration = TimeSpan.FromSeconds(6.0);
|
||||
public static readonly TimeSpan FreezeDelayDuration = TimeSpan.FromSeconds(8.0);
|
||||
// No longer active in pub21:
|
||||
private static readonly Hashtable m_Table = new Hashtable();
|
||||
public ParalyzingBlow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 30;
|
||||
}
|
||||
}
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
return m_Table.Contains(m);
|
||||
}
|
||||
|
||||
public static void BeginImmunity(Mobile m, TimeSpan duration)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
if (t != null)
|
||||
t.Stop();
|
||||
|
||||
t = new InternalTimer(m, duration);
|
||||
m_Table[m] = t;
|
||||
|
||||
t.Start();
|
||||
}
|
||||
|
||||
public static void EndImmunity(Mobile m)
|
||||
{
|
||||
Timer t = (Timer)m_Table[m];
|
||||
|
||||
if (t != null)
|
||||
t.Stop();
|
||||
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
|
||||
public override bool RequiresSecondarySkill(Mobile from)
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return true;
|
||||
|
||||
return weapon.Skill != SkillName.Wrestling;
|
||||
}
|
||||
|
||||
public override bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if(defender == null)
|
||||
return false;
|
||||
|
||||
if (defender.Paralyzed)
|
||||
{
|
||||
if (attacker != null)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1061923); // The target is already frozen.
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
if (IsImmune(defender)) //Intentionally going after Mana consumption
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
return;
|
||||
}
|
||||
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
defender.PlaySound(0x204);
|
||||
|
||||
attacker.SendLocalizedMessage(1060163); // You deliver a paralyzing blow!
|
||||
defender.SendLocalizedMessage(1060164); // The attack has temporarily paralyzed you!
|
||||
|
||||
TimeSpan duration = defender.Player ? PlayerFreezeDuration : NPCFreezeDuration;
|
||||
|
||||
// Treat it as paralyze not as freeze, effect must be removed when damaged.
|
||||
defender.Paralyze(duration);
|
||||
|
||||
BeginImmunity(defender, duration + FreezeDelayDuration);
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
public InternalTimer(Mobile m, TimeSpan duration)
|
||||
: base(duration)
|
||||
{
|
||||
this.m_Mobile = m;
|
||||
this.Priority = TimerPriority.TwoFiftyMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
EndImmunity(this.m_Mobile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Scripts/Abilities/PsychicAttack.cs
Normal file
88
Scripts/Abilities/PsychicAttack.cs
Normal file
@@ -0,0 +1,88 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class PsychicAttack : WeaponAbility
|
||||
{
|
||||
public PsychicAttack()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana { get { return 30; } }
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!Validate(attacker) || !CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1074383); // Your shot sends forth a wave of psychic energy.
|
||||
defender.SendLocalizedMessage(1074384); // Your mind is attacked by psychic force!
|
||||
|
||||
defender.FixedParticles(0x3789, 10, 25, 5032, EffectLayer.Head);
|
||||
defender.PlaySound(0x1F8);
|
||||
|
||||
if (m_Registry.ContainsKey(defender))
|
||||
{
|
||||
if (!m_Registry[defender].DoneIncrease)
|
||||
{
|
||||
m_Registry[defender].SpellDamageMalus *= 2;
|
||||
m_Registry[defender].ManaCostMalus *= 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
m_Registry[defender] = new PsychicAttackTimer(defender);
|
||||
|
||||
BuffInfo.RemoveBuff(defender, BuffIcon.PsychicAttack);
|
||||
|
||||
string args = String.Format("{0}\t{1}", m_Registry[defender].SpellDamageMalus, m_Registry[defender].ManaCostMalus);
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.PsychicAttack, 1151296, 1151297, args));
|
||||
}
|
||||
|
||||
private static Dictionary<Mobile, PsychicAttackTimer> m_Registry = new Dictionary<Mobile, PsychicAttackTimer>();
|
||||
public static Dictionary<Mobile, PsychicAttackTimer> Registry { get { return m_Registry; } }
|
||||
|
||||
public static void RemoveEffects(Mobile defender)
|
||||
{
|
||||
if (defender == null)
|
||||
return;
|
||||
|
||||
BuffInfo.RemoveBuff(defender, BuffIcon.PsychicAttack);
|
||||
|
||||
if (m_Registry.ContainsKey(defender))
|
||||
m_Registry.Remove(defender);
|
||||
|
||||
defender.SendLocalizedMessage(1150292); // You recover from the effects of the psychic attack.
|
||||
}
|
||||
|
||||
public class PsychicAttackTimer : Timer
|
||||
{
|
||||
private Mobile m_Defender;
|
||||
private int m_SpellDamageMalus;
|
||||
private int m_ManaCostMalus;
|
||||
private bool m_DoneIncrease;
|
||||
|
||||
public int SpellDamageMalus { get { return m_SpellDamageMalus; } set { m_SpellDamageMalus = value; m_DoneIncrease = true; } }
|
||||
public int ManaCostMalus { get { return m_ManaCostMalus; } set { m_ManaCostMalus = value; m_DoneIncrease = true; } }
|
||||
public bool DoneIncrease { get { return m_DoneIncrease; } }
|
||||
|
||||
public PsychicAttackTimer(Mobile defender)
|
||||
: base(TimeSpan.FromSeconds(10))
|
||||
{
|
||||
m_Defender = defender;
|
||||
m_SpellDamageMalus = 15;
|
||||
m_ManaCostMalus = 15;
|
||||
m_DoneIncrease = false;
|
||||
Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
RemoveEffects(m_Defender);
|
||||
Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
101
Scripts/Abilities/RidingSwipe.cs
Normal file
101
Scripts/Abilities/RidingSwipe.cs
Normal file
@@ -0,0 +1,101 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// If you are on foot, dismounts your opponent and damage the ethereal's rider or the
|
||||
/// living mount(which must be healed before ridden again). If you are mounted, damages
|
||||
/// and stuns the mounted opponent.
|
||||
/// </summary>
|
||||
public class RidingSwipe : WeaponAbility
|
||||
{
|
||||
public RidingSwipe()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
public override bool RequiresSE
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (this.GetSkill(from, SkillName.Bushido) < 50.0)
|
||||
{
|
||||
from.SendLocalizedMessage(1070768, "50"); // You need ~1_SKILL_REQUIREMENT~ Bushido skill to perform that attack!
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CheckSkills(from);
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!defender.Mounted && !defender.Flying && (!Core.ML || !Server.Spells.Ninjitsu.AnimalForm.UnderTransformation(defender)))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060848); // This attack only works on mounted targets
|
||||
ClearCurrentAbility(attacker);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
int amount = 10 + (int)(10.0 * (attacker.Skills[SkillName.Bushido].Value - 50.0) / 70.0 + 5);
|
||||
|
||||
if (!attacker.Mounted)
|
||||
{
|
||||
BlockMountType type = BlockMountType.RidingSwipe;
|
||||
IMount mount = defender.Mount;
|
||||
|
||||
if (Core.SA)
|
||||
{
|
||||
if (defender.Flying)
|
||||
{
|
||||
type = BlockMountType.RidingSwipeFlying;
|
||||
}
|
||||
else if (mount is EtherealMount)
|
||||
{
|
||||
type = BlockMountType.RidingSwipeEthereal;
|
||||
}
|
||||
}
|
||||
|
||||
Server.Items.Dismount.DoDismount(attacker, defender, mount, 10, type);
|
||||
|
||||
if(mount is Mobile)
|
||||
AOS.Damage((Mobile)mount, attacker, amount, 100, 0, 0, 0, 0);
|
||||
|
||||
defender.PlaySound(0x140);
|
||||
defender.FixedParticles(0x3728, 10, 15, 9955, EffectLayer.Waist);
|
||||
}
|
||||
else
|
||||
{
|
||||
AOS.Damage(defender, attacker, amount, 100, 0, 0, 0, 0);
|
||||
|
||||
if (Server.Items.ParalyzingBlow.IsImmune(defender)) //Does it still do damage?
|
||||
{
|
||||
attacker.SendLocalizedMessage(1070804); // Your target resists paralysis.
|
||||
defender.SendLocalizedMessage(1070813); // You resist paralysis.
|
||||
}
|
||||
else
|
||||
{
|
||||
defender.Paralyze(TimeSpan.FromSeconds(3.0));
|
||||
Server.Items.ParalyzingBlow.BeginImmunity(defender, Server.Items.ParalyzingBlow.FreezeDelayDuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
768
Scripts/Abilities/SAPropEffects.cs
Normal file
768
Scripts/Abilities/SAPropEffects.cs
Normal file
@@ -0,0 +1,768 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Server;
|
||||
using Server.Mobiles;
|
||||
using Server.Spells;
|
||||
using Server.Spells.Ninjitsu;
|
||||
using Server.Network;
|
||||
using Server.Spells.SkillMasteries;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public enum EffectsType
|
||||
{
|
||||
BattleLust,
|
||||
SoulCharge,
|
||||
DamageEater,
|
||||
Splintering,
|
||||
Searing,
|
||||
Bane,
|
||||
BoneBreaker,
|
||||
Swarm,
|
||||
Sparks,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used for complex weapon/armor properties introduced in Stagyian Abyss
|
||||
/// </summary>
|
||||
public class PropertyEffect
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
private Mobile m_Victim;
|
||||
private Item m_Owner;
|
||||
private EffectsType m_Effect;
|
||||
private TimeSpan m_Duration;
|
||||
private TimeSpan m_TickDuration;
|
||||
private Timer m_Timer;
|
||||
|
||||
public Mobile Mobile { get { return m_Mobile; } }
|
||||
public Mobile Victim { get { return m_Victim; } }
|
||||
public Item Owner { get { return m_Owner; } }
|
||||
public EffectsType Effect { get { return m_Effect; } }
|
||||
public TimeSpan Duration { get { return m_Duration; } }
|
||||
public TimeSpan TickDuration { get { return m_TickDuration; } }
|
||||
public Timer Timer { get { return m_Timer; } }
|
||||
|
||||
private static List<PropertyEffect> m_Effects = new List<PropertyEffect>();
|
||||
public static List<PropertyEffect> Effects { get { return m_Effects; } }
|
||||
|
||||
public PropertyEffect(Mobile from, Mobile victim, Item owner, EffectsType effect, TimeSpan duration, TimeSpan tickduration)
|
||||
{
|
||||
m_Mobile = from;
|
||||
m_Victim = victim;
|
||||
m_Owner = owner;
|
||||
m_Effect = effect;
|
||||
m_Duration = duration;
|
||||
m_TickDuration = tickduration;
|
||||
|
||||
m_Effects.Add(this);
|
||||
|
||||
if (m_TickDuration > TimeSpan.MinValue)
|
||||
StartTimer();
|
||||
}
|
||||
|
||||
public virtual void RemoveEffects()
|
||||
{
|
||||
StopTimer();
|
||||
|
||||
if(m_Effects.Contains(this))
|
||||
m_Effects.Remove(this);
|
||||
}
|
||||
|
||||
public void StartTimer()
|
||||
{
|
||||
if (m_Timer == null)
|
||||
{
|
||||
m_Timer = new InternalTimer(this);
|
||||
m_Timer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
public void StopTimer()
|
||||
{
|
||||
if (m_Timer != null)
|
||||
{
|
||||
m_Timer.Stop();
|
||||
m_Timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsEquipped()
|
||||
{
|
||||
if (m_Owner == null)
|
||||
return false;
|
||||
|
||||
return m_Mobile.FindItemOnLayer(m_Owner.Layer) == m_Owner;
|
||||
}
|
||||
|
||||
public virtual void OnTick()
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnDamaged(int damage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnDamage(int damage, int phys, int fire, int cold, int poison, int energy, int direct)
|
||||
{
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private PropertyEffect m_Effect;
|
||||
private DateTime m_Expires;
|
||||
|
||||
public InternalTimer(PropertyEffect effect)
|
||||
: base(effect.TickDuration, effect.TickDuration)
|
||||
{
|
||||
m_Effect = effect;
|
||||
|
||||
if (effect != null && effect.Duration > TimeSpan.MinValue)
|
||||
m_Expires = DateTime.UtcNow + effect.Duration;
|
||||
else
|
||||
m_Expires = DateTime.MinValue;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (m_Effect.Mobile == null || (m_Effect.Mobile.Deleted || !m_Effect.Mobile.Alive || m_Effect.Mobile.IsDeadBondedPet))
|
||||
{
|
||||
m_Effect.RemoveEffects();
|
||||
}
|
||||
else if (m_Effect.Victim != null && (m_Effect.Victim.Deleted || !m_Effect.Victim.Alive || m_Effect.Mobile.IsDeadBondedPet))
|
||||
{
|
||||
m_Effect.RemoveEffects();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Effect.OnTick();
|
||||
|
||||
if (m_Expires > DateTime.MinValue && m_Expires <= DateTime.UtcNow)
|
||||
{
|
||||
m_Effect.RemoveEffects();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsUnderEffects(Mobile from, EffectsType effect)
|
||||
{
|
||||
foreach (PropertyEffect e in m_Effects)
|
||||
{
|
||||
if (e.Mobile == from && e.Effect == effect)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static T GetContext<T>(Mobile from, EffectsType type) where T : PropertyEffect
|
||||
{
|
||||
return m_Effects.FirstOrDefault(e => e.Mobile == from && e.Effect == type) as T;
|
||||
}
|
||||
|
||||
public static T GetContext<T>(Mobile from, Mobile victim, EffectsType type) where T : PropertyEffect
|
||||
{
|
||||
return m_Effects.FirstOrDefault(e => e.Mobile == from && e.Victim == victim && e.Effect == type) as T;
|
||||
}
|
||||
|
||||
public static IEnumerable<T> GetContexts<T>(Mobile victim, EffectsType type) where T : PropertyEffect
|
||||
{
|
||||
foreach (PropertyEffect effect in m_Effects.OfType<T>().Where(e => e.Victim == victim))
|
||||
{
|
||||
yield return effect as T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class SoulChargeContext : PropertyEffect
|
||||
{
|
||||
private bool m_Active;
|
||||
|
||||
public SoulChargeContext(Mobile from, Item item)
|
||||
: base(from, null, item, EffectsType.SoulCharge, TimeSpan.FromSeconds(40), TimeSpan.FromSeconds(40))
|
||||
{
|
||||
m_Active = true;
|
||||
}
|
||||
|
||||
public override void OnDamaged(int damage)
|
||||
{
|
||||
if (m_Active && IsEquipped() && this.Mobile != null)
|
||||
{
|
||||
double mod = BaseFishPie.IsUnderEffects(this.Mobile, FishPieEffect.SoulCharge) ? .50 : .30;
|
||||
this.Mobile.Mana += (int)Math.Min(this.Mobile.ManaMax, damage * mod);
|
||||
m_Active = false;
|
||||
|
||||
Server.Effects.SendTargetParticles(this.Mobile, 0x375A, 0x1, 0xA, 0x71, 0x2, 0x1AE9, (EffectLayer)0, 0);
|
||||
|
||||
this.Mobile.SendLocalizedMessage(1113636); //The soul charge effect converts some of the damage you received into mana.
|
||||
}
|
||||
}
|
||||
|
||||
public static void CheckHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
BaseShield shield = defender.FindItemOnLayer(Layer.TwoHanded) as BaseShield;
|
||||
|
||||
if (shield != null && shield.ArmorAttributes.SoulCharge > 0 && shield.ArmorAttributes.SoulCharge > Utility.Random(100))
|
||||
{
|
||||
SoulChargeContext sc = PropertyEffect.GetContext<SoulChargeContext>(defender, EffectsType.SoulCharge);
|
||||
|
||||
if (sc == null)
|
||||
sc = new SoulChargeContext(defender, shield);
|
||||
|
||||
sc.OnDamaged(damage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DamageType
|
||||
{
|
||||
Kinetic,
|
||||
Fire,
|
||||
Cold,
|
||||
Poison,
|
||||
Energy,
|
||||
AllTypes
|
||||
}
|
||||
|
||||
public class DamageEaterContext : PropertyEffect
|
||||
{
|
||||
private int m_Charges;
|
||||
|
||||
public DamageEaterContext(Mobile mobile)
|
||||
: base(mobile, null, null, EffectsType.DamageEater, TimeSpan.MinValue, TimeSpan.FromSeconds(10))
|
||||
{
|
||||
m_Charges = 0;
|
||||
}
|
||||
|
||||
public override void OnDamage(int damage, int phys, int fire, int cold, int poison, int energy, int direct)
|
||||
{
|
||||
if (m_Charges >= 20)
|
||||
return;
|
||||
|
||||
double pd = 0; double fd = 0;
|
||||
double cd = 0; double pod = 0;
|
||||
double ed = 0; double dd = 0;
|
||||
|
||||
double k = (double)GetValue(DamageType.Kinetic, this.Mobile) / 100;
|
||||
double f = (double)GetValue(DamageType.Fire, this.Mobile) / 100;
|
||||
double c = (double)GetValue(DamageType.Cold, this.Mobile) / 100;
|
||||
double p = (double)GetValue(DamageType.Poison, this.Mobile) / 100;
|
||||
double e = (double)GetValue(DamageType.Energy, this.Mobile) / 100;
|
||||
double a = (double)GetValue(DamageType.AllTypes, this.Mobile) / 100;
|
||||
|
||||
if (phys > 0 && (k > 0 || a > 0))
|
||||
{
|
||||
pd = damage * ((double)phys / 100);
|
||||
|
||||
if (k >= a)
|
||||
DelayHeal(Math.Min(pd * k, pd * .3));
|
||||
else
|
||||
DelayHeal(Math.Min(pd * a, pd * .18));
|
||||
|
||||
m_Charges++;
|
||||
}
|
||||
|
||||
if (fire > 0 && (f > 0 || a > 0))
|
||||
{
|
||||
fd = damage * ((double)fire / 100);
|
||||
|
||||
if (f >= a)
|
||||
DelayHeal(Math.Min(fd * f, fd * .3));
|
||||
else
|
||||
DelayHeal(Math.Min(fd * a, fd * .18));
|
||||
|
||||
m_Charges++;
|
||||
}
|
||||
|
||||
if (cold > 0 && (c > 0 || a > 0))
|
||||
{
|
||||
cd = damage * ((double)cold / 100);
|
||||
|
||||
if (c >= a)
|
||||
DelayHeal(Math.Min(cd * c, cd * .3));
|
||||
else
|
||||
DelayHeal(Math.Min(cd * a, cd * .18));
|
||||
|
||||
m_Charges++;
|
||||
}
|
||||
|
||||
if (poison > 0 && (p > 0 || a > 0))
|
||||
{
|
||||
pod = damage * ((double)poison / 100);
|
||||
|
||||
if (p >= a)
|
||||
DelayHeal(Math.Min(pod * p, pod * .3));
|
||||
else
|
||||
DelayHeal(Math.Min(pod * a, pod * .18));
|
||||
|
||||
m_Charges++;
|
||||
}
|
||||
|
||||
if (energy > 0 && (e > 0 || a > 0))
|
||||
{
|
||||
ed = damage * ((double)energy / 100);
|
||||
|
||||
if (e >= a)
|
||||
DelayHeal(Math.Min(ed * e, ed * .3));
|
||||
else
|
||||
DelayHeal(Math.Min(ed * a, ed * .18));
|
||||
|
||||
m_Charges++;
|
||||
}
|
||||
|
||||
if (direct > 0 && a > 0)
|
||||
{
|
||||
dd = damage * ((double)direct / 100);
|
||||
|
||||
DelayHeal(Math.Min(dd * a, dd * .18));
|
||||
m_Charges++;
|
||||
}
|
||||
}
|
||||
|
||||
public void DelayHeal(double toHeal)
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(3), new TimerStateCallback(DoHeal), toHeal);
|
||||
}
|
||||
|
||||
public void DoHeal(object obj)
|
||||
{
|
||||
double dam = (double)obj;
|
||||
|
||||
if (dam < 0)
|
||||
return;
|
||||
|
||||
Mobile.Heal((int)dam, Mobile, false);
|
||||
Mobile.SendLocalizedMessage(1113617); // Some of the damage you received has been converted to heal you.
|
||||
Server.Effects.SendPacket(Mobile.Location, Mobile.Map, new ParticleEffect(EffectType.FixedFrom, Mobile.Serial, Serial.Zero, 0x375A, Mobile.Location, Mobile.Location, 1, 10, false, false, 33, 0, 2, 6889, 1, Mobile.Serial, 45, 0));
|
||||
m_Charges--;
|
||||
}
|
||||
|
||||
public override void OnTick()
|
||||
{
|
||||
if (m_Charges <= 0)
|
||||
RemoveEffects();
|
||||
}
|
||||
|
||||
public static bool HasValue(Mobile from)
|
||||
{
|
||||
if (GetValue(DamageType.Kinetic, from) > 0)
|
||||
return true;
|
||||
if (GetValue(DamageType.Fire, from) > 0)
|
||||
return true;
|
||||
if (GetValue(DamageType.Cold, from) > 0)
|
||||
return true;
|
||||
if (GetValue(DamageType.Poison, from) > 0)
|
||||
return true;
|
||||
if (GetValue(DamageType.Energy, from) > 0)
|
||||
return true;
|
||||
if (GetValue(DamageType.AllTypes, from) > 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int GetValue(DamageType type, Mobile from)
|
||||
{
|
||||
if (from == null)
|
||||
return 0;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case DamageType.Kinetic: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterKinetic);
|
||||
case DamageType.Fire: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterFire);
|
||||
case DamageType.Cold: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterCold);
|
||||
case DamageType.Poison: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterPoison);
|
||||
case DamageType.Energy: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterEnergy);
|
||||
case DamageType.AllTypes: return (int)SAAbsorptionAttributes.GetValue(from, SAAbsorptionAttribute.EaterDamage);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void CheckDamage(Mobile from, int damage, int phys, int fire, int cold, int pois, int ergy, int direct)
|
||||
{
|
||||
DamageEaterContext context = PropertyEffect.GetContext<DamageEaterContext>(from, EffectsType.DamageEater);
|
||||
|
||||
if (context == null && HasValue(from))
|
||||
context = new DamageEaterContext(from);
|
||||
|
||||
if (context != null)
|
||||
context.OnDamage(damage, phys, fire, cold, pois, ergy, direct);
|
||||
}
|
||||
}
|
||||
|
||||
public class SplinteringWeaponContext : PropertyEffect
|
||||
{
|
||||
public static List<Mobile> BleedImmune { get; set; } = new List<Mobile>();
|
||||
|
||||
public SplinteringWeaponContext(Mobile from, Mobile defender, Item weapon)
|
||||
: base(from, defender, weapon, EffectsType.Splintering, TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(4))
|
||||
{
|
||||
StartForceWalk(defender);
|
||||
|
||||
if (Core.EJ)
|
||||
{
|
||||
if (!(defender is PlayerMobile) || !IsBleedImmune(defender))
|
||||
{
|
||||
BleedAttack.BeginBleed(defender, from, true);
|
||||
AddBleedImmunity(defender);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BleedAttack.BeginBleed(defender, from, true);
|
||||
}
|
||||
|
||||
defender.SendLocalizedMessage(1112486); // A shard of the brittle weapon has become lodged in you!
|
||||
from.SendLocalizedMessage(1113077); // A shard of your blade breaks off and sticks in your opponent!
|
||||
|
||||
Server.Effects.PlaySound(defender.Location, defender.Map, 0x1DF);
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.SplinteringEffect, 1154670, 1152144, TimeSpan.FromSeconds(10), defender));
|
||||
}
|
||||
|
||||
public override void OnTick()
|
||||
{
|
||||
base.OnTick();
|
||||
|
||||
BuffInfo.RemoveBuff(Victim, BuffIcon.SplinteringEffect);
|
||||
}
|
||||
|
||||
public void StartForceWalk(Mobile m)
|
||||
{
|
||||
if (m.NetState != null && m.AccessLevel < AccessLevel.GameMaster)
|
||||
m.SendSpeedControl(SpeedControlType.WalkSpeed);
|
||||
}
|
||||
|
||||
public void EndForceWalk(Mobile m)
|
||||
{
|
||||
m.SendSpeedControl(SpeedControlType.Disable);
|
||||
}
|
||||
|
||||
public override void RemoveEffects()
|
||||
{
|
||||
EndForceWalk(Victim);
|
||||
Victim.SendLocalizedMessage(1112487); // The shard is successfully removed.
|
||||
|
||||
base.RemoveEffects();
|
||||
}
|
||||
|
||||
public static bool CheckHit(Mobile attacker, Mobile defender, WeaponAbility ability, Item weapon)
|
||||
{
|
||||
if (defender == null || (Core.EJ && (ability == WeaponAbility.Disarm || ability == WeaponAbility.InfectiousStrike || SkillMasterySpell.HasSpell(attacker, typeof(SkillMasterySpell)))))
|
||||
return false;
|
||||
|
||||
SplinteringWeaponContext context = PropertyEffect.GetContext<SplinteringWeaponContext>(attacker, defender, EffectsType.Splintering);
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
new SplinteringWeaponContext(attacker, defender, weapon);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsBleedImmune(Mobile m)
|
||||
{
|
||||
return BleedImmune.Contains(m);
|
||||
}
|
||||
|
||||
public static void AddBleedImmunity(Mobile m)
|
||||
{
|
||||
if (!(m is PlayerMobile) || BleedImmune.Contains(m))
|
||||
return;
|
||||
|
||||
BleedImmune.Add(m);
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(16), () => BleedImmune.Remove(m));
|
||||
}
|
||||
}
|
||||
|
||||
public class SearingWeaponContext : PropertyEffect
|
||||
{
|
||||
public static int Damage { get { return Utility.RandomMinMax(10, 15); } }
|
||||
|
||||
public SearingWeaponContext(Mobile from, Mobile defender)
|
||||
: base(from, defender, null, EffectsType.Searing, TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(4))
|
||||
{
|
||||
from.SendLocalizedMessage(1151177); //The searing attack cauterizes the wound on impact.
|
||||
}
|
||||
|
||||
public static void CheckHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
SearingWeaponContext context = PropertyEffect.GetContext<SearingWeaponContext>(attacker, defender, EffectsType.Searing);
|
||||
|
||||
if (context == null)
|
||||
new SearingWeaponContext(attacker, defender);
|
||||
}
|
||||
|
||||
public static bool HasContext(Mobile defender)
|
||||
{
|
||||
return PropertyEffect.GetContext<SearingWeaponContext>(defender, EffectsType.Searing) != null;
|
||||
}
|
||||
}
|
||||
|
||||
public class BoneBreakerContext : PropertyEffect
|
||||
{
|
||||
public static Dictionary<Mobile, DateTime> _Immunity;
|
||||
|
||||
public BoneBreakerContext(Mobile attacker, Mobile defender, Item weapon)
|
||||
: base(attacker, defender, weapon, EffectsType.BoneBreaker, TimeSpan.FromSeconds(4), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnTick()
|
||||
{
|
||||
int toReduce = Victim.StamMax / 10;
|
||||
|
||||
if (Victim.Stam - toReduce >= 3)
|
||||
Victim.Stam -= toReduce;
|
||||
else
|
||||
Victim.Stam = Math.Max(1, Victim.Stam - 1);
|
||||
}
|
||||
|
||||
public override void RemoveEffects()
|
||||
{
|
||||
base.RemoveEffects();
|
||||
|
||||
AddImmunity(Victim);
|
||||
}
|
||||
|
||||
public static int CheckHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
int mana = (int)(30.0 * ((double)(AosAttributes.GetValue(attacker, AosAttribute.LowerManaCost) + BaseArmor.GetInherentLowerManaCost(attacker)) / 100.0));
|
||||
int damage = 0;
|
||||
|
||||
if (attacker.Mana >= mana)
|
||||
{
|
||||
attacker.Mana -= mana;
|
||||
damage += 50;
|
||||
|
||||
defender.SendLocalizedMessage(1157317); // The attack shatters your bones!
|
||||
}
|
||||
|
||||
if (IsImmune(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1157316); // Your target is currently immune to bone breaking!
|
||||
return damage;
|
||||
}
|
||||
|
||||
if (20 > Utility.Random(100))
|
||||
{
|
||||
BoneBreakerContext context = PropertyEffect.GetContext<BoneBreakerContext>(attacker, defender, EffectsType.BoneBreaker);
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
new BoneBreakerContext(attacker, defender, null);
|
||||
defender.SendLocalizedMessage(1157363); // Your bones are broken! Stamina drain over time!
|
||||
|
||||
defender.PlaySound(0x204);
|
||||
defender.FixedEffect(0x376A, 9, 32);
|
||||
|
||||
defender.FixedEffect(0x3779, 10, 20, 1365, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
return false;
|
||||
|
||||
List<Mobile> list = new List<Mobile>(_Immunity.Keys);
|
||||
|
||||
foreach (Mobile mob in list)
|
||||
{
|
||||
if (_Immunity[mob] < DateTime.UtcNow)
|
||||
_Immunity.Remove(mob);
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
|
||||
return _Immunity.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void AddImmunity(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
_Immunity = new Dictionary<Mobile, DateTime>();
|
||||
|
||||
_Immunity[m] = DateTime.UtcNow + TimeSpan.FromSeconds(60);
|
||||
}
|
||||
}
|
||||
|
||||
public class SwarmContext : PropertyEffect
|
||||
{
|
||||
public static Dictionary<Mobile, DateTime> _Immunity;
|
||||
|
||||
private int _ID;
|
||||
|
||||
public SwarmContext(Mobile attacker, Mobile defender, Item weapon)
|
||||
: base(attacker, defender, weapon, EffectsType.Swarm, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(5))
|
||||
{
|
||||
_ID = Utility.RandomMinMax(2331, 2339);
|
||||
|
||||
DoEffects();
|
||||
}
|
||||
|
||||
public static void CheckHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (IsImmune(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1157322); // Your target is currently immune to swarm!
|
||||
return;
|
||||
}
|
||||
|
||||
SwarmContext context = PropertyEffect.GetContext<SwarmContext>(attacker, defender, EffectsType.Swarm);
|
||||
|
||||
if (context != null)
|
||||
{
|
||||
context.RemoveEffects();
|
||||
}
|
||||
|
||||
context = new SwarmContext(attacker, defender, null);
|
||||
|
||||
defender.NonlocalOverheadMessage(MessageType.Regular, 0x5C, 1114447, defender.Name); // * ~1_NAME~ is stung by a swarm of insects *
|
||||
defender.LocalOverheadMessage(MessageType.Regular, 0x5C, 1071905); // * The swarm of insects bites and stings your flesh! *
|
||||
}
|
||||
|
||||
public override void OnTick()
|
||||
{
|
||||
if (Victim == null || !Victim.Alive)
|
||||
{
|
||||
RemoveEffects();
|
||||
return;
|
||||
}
|
||||
|
||||
if (Victim.FindItemOnLayer(Layer.OneHanded) is Torch)
|
||||
{
|
||||
if (Victim.NetState != null)
|
||||
Victim.LocalOverheadMessage(MessageType.Regular, 0x61, 1071925); // * The open flame begins to scatter the swarm of insects! *
|
||||
}
|
||||
else
|
||||
{
|
||||
DoEffects();
|
||||
}
|
||||
}
|
||||
|
||||
private void DoEffects()
|
||||
{
|
||||
AOS.Damage(Victim, Mobile, 10, 0, 0, 0, 0, 0, 0, 100);
|
||||
Victim.SendLocalizedMessage(1157362); // Biting insects are attacking you!
|
||||
Server.Effects.SendTargetEffect(Victim, _ID, 40);
|
||||
|
||||
Victim.PlaySound(0x00E);
|
||||
Victim.PlaySound(0x1BC);
|
||||
}
|
||||
|
||||
public override void RemoveEffects()
|
||||
{
|
||||
base.RemoveEffects();
|
||||
|
||||
//AddImmunity(Victim);
|
||||
}
|
||||
|
||||
public static void CheckRemove(Mobile victim)
|
||||
{
|
||||
ColUtility.ForEach(PropertyEffect.GetContexts<SwarmContext>(victim, EffectsType.Swarm), context =>
|
||||
{
|
||||
context.RemoveEffects();
|
||||
});
|
||||
}
|
||||
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
return false;
|
||||
|
||||
List<Mobile> list = new List<Mobile>(_Immunity.Keys);
|
||||
|
||||
foreach (Mobile mob in list)
|
||||
{
|
||||
if (_Immunity[mob] < DateTime.UtcNow)
|
||||
_Immunity.Remove(mob);
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
|
||||
return _Immunity.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void AddImmunity(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
_Immunity = new Dictionary<Mobile, DateTime>();
|
||||
|
||||
_Immunity[m] = DateTime.UtcNow + TimeSpan.FromSeconds(60);
|
||||
}
|
||||
}
|
||||
|
||||
public class SparksContext : PropertyEffect
|
||||
{
|
||||
public static Dictionary<Mobile, DateTime> _Immunity;
|
||||
|
||||
public SparksContext(Mobile attacker, Mobile defender, Item weapon)
|
||||
: base(attacker, defender, weapon, EffectsType.Sparks, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(1))
|
||||
{
|
||||
}
|
||||
|
||||
public static void CheckHit(Mobile attacker, Mobile defender)
|
||||
{
|
||||
if (IsImmune(defender))
|
||||
{
|
||||
attacker.SendLocalizedMessage(1157324); // Your target is currently immune to sparks!
|
||||
return;
|
||||
}
|
||||
|
||||
SparksContext context = PropertyEffect.GetContext<SparksContext>(attacker, defender, EffectsType.Sparks);
|
||||
|
||||
if (context == null)
|
||||
{
|
||||
context = new SparksContext(attacker, defender, null);
|
||||
|
||||
attacker.PlaySound(0x20A);
|
||||
defender.FixedParticles(0x3818, 1, 11, 0x13A8, 0, 0, EffectLayer.Waist);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnTick()
|
||||
{
|
||||
AOS.Damage(Victim, Mobile, Utility.RandomMinMax(20, 40), 0, 0, 0, 0, 100);
|
||||
}
|
||||
|
||||
public override void RemoveEffects()
|
||||
{
|
||||
base.RemoveEffects();
|
||||
|
||||
//AddImmunity(Victim);
|
||||
}
|
||||
|
||||
public static bool IsImmune(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
return false;
|
||||
|
||||
List<Mobile> list = new List<Mobile>(_Immunity.Keys);
|
||||
|
||||
foreach (Mobile mob in list)
|
||||
{
|
||||
if (_Immunity[mob] < DateTime.UtcNow)
|
||||
_Immunity.Remove(mob);
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
|
||||
return _Immunity.ContainsKey(m);
|
||||
}
|
||||
|
||||
public static void AddImmunity(Mobile m)
|
||||
{
|
||||
if (_Immunity == null)
|
||||
_Immunity = new Dictionary<Mobile, DateTime>();
|
||||
|
||||
_Immunity[m] = DateTime.UtcNow + TimeSpan.FromSeconds(60);
|
||||
}
|
||||
}
|
||||
}
|
||||
80
Scripts/Abilities/SerpentArrow.cs
Normal file
80
Scripts/Abilities/SerpentArrow.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SerpentArrow : WeaponAbility
|
||||
{
|
||||
public SerpentArrow()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 25;
|
||||
}
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return SkillName.Poisoning;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
defender.SendLocalizedMessage(1112369); // You have been poisoned by a lethal arrow!
|
||||
|
||||
int level;
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
if (attacker.InRange(defender, 2))
|
||||
{
|
||||
int total = (attacker.Skills.Poisoning.Fixed) / 2;
|
||||
|
||||
if (total >= 1000)
|
||||
level = 3;
|
||||
else if (total > 850)
|
||||
level = 2;
|
||||
else if (total > 650)
|
||||
level = 1;
|
||||
else
|
||||
level = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
level = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
double total = attacker.Skills[SkillName.Poisoning].Value;
|
||||
|
||||
double dist = attacker.GetDistanceToSqrt(defender);
|
||||
|
||||
if (dist >= 3.0)
|
||||
total -= (dist - 3.0) * 10.0;
|
||||
|
||||
if (total >= 200.0 && 1 > Utility.Random(10))
|
||||
level = 3;
|
||||
else if (total > (Core.AOS ? 170.1 : 170.0))
|
||||
level = 2;
|
||||
else if (total > (Core.AOS ? 130.1 : 130.0))
|
||||
level = 1;
|
||||
else
|
||||
level = 0;
|
||||
}
|
||||
|
||||
defender.ApplyPoison(attacker, Poison.GetPoison(level));
|
||||
|
||||
defender.FixedParticles(0x374A, 10, 15, 5021, EffectLayer.Waist);
|
||||
defender.PlaySound(0x474);
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Scripts/Abilities/ShadowStrike.cs
Normal file
70
Scripts/Abilities/ShadowStrike.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// This powerful ability requires secondary skills to activate.
|
||||
/// Successful use of Shadowstrike deals extra damage to the target <20> and renders the attacker invisible!
|
||||
/// Only those who are adept at the art of stealth will be able to use this ability.
|
||||
/// </summary>
|
||||
public class ShadowStrike : WeaponAbility
|
||||
{
|
||||
public ShadowStrike()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.25;
|
||||
}
|
||||
}
|
||||
public override bool RequiresSecondarySkill(Mobile from)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool CheckSkills(Mobile from)
|
||||
{
|
||||
if (!base.CheckSkills(from))
|
||||
return false;
|
||||
|
||||
Skill skill = from.Skills[SkillName.Stealth];
|
||||
|
||||
if (skill != null && skill.Value >= 80.0)
|
||||
return true;
|
||||
|
||||
from.SendLocalizedMessage(1060183); // You lack the required stealth to perform that attack
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1060078); // You strike and hide in the shadows!
|
||||
defender.SendLocalizedMessage(1060079); // You are dazed by the attack and your attacker vanishes!
|
||||
|
||||
Effects.SendLocationParticles(EffectItem.Create(attacker.Location, attacker.Map, EffectItem.DefaultDuration), 0x376A, 8, 12, 9943);
|
||||
attacker.PlaySound(0x482);
|
||||
|
||||
defender.FixedEffect(0x37BE, 20, 25);
|
||||
|
||||
attacker.Combatant = null;
|
||||
attacker.Warmode = false;
|
||||
attacker.Hidden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
Scripts/Abilities/SlayerEntry.cs
Normal file
136
Scripts/Abilities/SlayerEntry.cs
Normal file
@@ -0,0 +1,136 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SlayerEntry
|
||||
{
|
||||
private static readonly int[] m_AosTitles = new int[]
|
||||
{
|
||||
1060479, // undead slayer
|
||||
1060470, // orc slayer
|
||||
1060480, // troll slayer
|
||||
1060468, // ogre slayer
|
||||
1060472, // repond slayer
|
||||
1060462, // dragon slayer
|
||||
1060478, // terathan slayer
|
||||
1060475, // snake slayer
|
||||
1060467, // lizardman slayer
|
||||
1060473, // reptile slayer
|
||||
1060460, // demon slayer
|
||||
1060466, // gargoyle slayer
|
||||
1017396, // Balron Damnation
|
||||
1060461, // demon slayer
|
||||
1060469, // ophidian slayer
|
||||
1060477, // spider slayer
|
||||
1060474, // scorpion slayer
|
||||
1060458, // arachnid slayer
|
||||
1060465, // fire elemental slayer
|
||||
1060481, // water elemental slayer
|
||||
1060457, // air elemental slayer
|
||||
1060471, // poison elemental slayer
|
||||
1060463, // earth elemental slayer
|
||||
1060459, // blood elemental slayer
|
||||
1060476, // snow elemental slayer
|
||||
1060464, // elemental slayer
|
||||
1070855, // fey slayer
|
||||
1156240, // dinosaur slayer
|
||||
1156241, // myrmidex slayer
|
||||
1156126, // Eodon Slayer
|
||||
1156347 // Eodon Tribe Slayer
|
||||
};
|
||||
private static readonly int[] m_OldTitles = new int[]
|
||||
{
|
||||
1017384, // Silver
|
||||
1017385, // Orc Slaying
|
||||
1017386, // Troll Slaughter
|
||||
1017387, // Ogre Thrashing
|
||||
1017388, // Repond
|
||||
1017389, // Dragon Slaying
|
||||
1017390, // Terathan
|
||||
1017391, // Snake's Bane
|
||||
1017392, // Lizardman Slaughter
|
||||
1017393, // Reptilian Death
|
||||
1017394, // Daemon Dismissal
|
||||
1017395, // Gargoyle's Foe
|
||||
1017396, // Balron Damnation
|
||||
1017397, // Exorcism
|
||||
1017398, // Ophidian
|
||||
1017399, // Spider's Death
|
||||
1017400, // Scorpion's Bane
|
||||
1017401, // Arachnid Doom
|
||||
1017402, // Flame Dousing
|
||||
1017403, // Water Dissipation
|
||||
1017404, // Vacuum
|
||||
1017405, // Elemental Health
|
||||
1017406, // Earth Shatter
|
||||
1017407, // Blood Drinking
|
||||
1017408, // Summer Wind
|
||||
1017409, // Elemental Ban
|
||||
1070855 // fey slayer
|
||||
};
|
||||
private readonly SlayerName m_Name;
|
||||
private readonly Type[] m_Types;
|
||||
private SlayerGroup m_Group;
|
||||
public SlayerEntry(SlayerName name, params Type[] types)
|
||||
{
|
||||
this.m_Name = name;
|
||||
this.m_Types = types;
|
||||
}
|
||||
|
||||
public SlayerGroup Group
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Group;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Group = value;
|
||||
}
|
||||
}
|
||||
public SlayerName Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Name;
|
||||
}
|
||||
}
|
||||
public Type[] Types
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Types;
|
||||
}
|
||||
}
|
||||
public int Title
|
||||
{
|
||||
get
|
||||
{
|
||||
int[] titles = (Core.AOS ? m_AosTitles : m_OldTitles);
|
||||
|
||||
return titles[(int)this.m_Name - 1];
|
||||
}
|
||||
}
|
||||
public bool Slays(Mobile m)
|
||||
{
|
||||
|
||||
if (m.SpecialSlayerMechanics)
|
||||
{
|
||||
if (m.SlayerVulnerabilities.Contains(m_Name.ToString()))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
Type t = m.GetType();
|
||||
|
||||
for (int i = 0; i < this.m_Types.Length; ++i)
|
||||
{
|
||||
if (this.m_Types[i].IsAssignableFrom(t))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
774
Scripts/Abilities/SlayerGroup.cs
Normal file
774
Scripts/Abilities/SlayerGroup.cs
Normal file
@@ -0,0 +1,774 @@
|
||||
using System;
|
||||
using Server.Mobiles;
|
||||
using Server.Engines.Shadowguard;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SlayerGroup
|
||||
{
|
||||
private static SlayerEntry[] m_TotalEntries;
|
||||
private static SlayerGroup[] m_Groups;
|
||||
private SlayerGroup[] m_Opposition;
|
||||
private SlayerEntry m_Super;
|
||||
private SlayerEntry[] m_Entries;
|
||||
private Type[] m_FoundOn;
|
||||
|
||||
public SlayerGroup()
|
||||
{
|
||||
}
|
||||
|
||||
static SlayerGroup()
|
||||
{
|
||||
SlayerGroup humanoid = new SlayerGroup();
|
||||
SlayerGroup undead = new SlayerGroup();
|
||||
SlayerGroup elemental = new SlayerGroup();
|
||||
SlayerGroup abyss = new SlayerGroup();
|
||||
SlayerGroup arachnid = new SlayerGroup();
|
||||
SlayerGroup reptilian = new SlayerGroup();
|
||||
SlayerGroup fey = new SlayerGroup();
|
||||
SlayerGroup eodon = new SlayerGroup();
|
||||
SlayerGroup eodonTribe = new SlayerGroup();
|
||||
SlayerGroup dino = new SlayerGroup();
|
||||
SlayerGroup myrmidex = new SlayerGroup();
|
||||
|
||||
humanoid.Opposition = new SlayerGroup[]
|
||||
{
|
||||
undead
|
||||
};
|
||||
|
||||
humanoid.FoundOn = new Type[]
|
||||
{
|
||||
typeof(BoneKnight), typeof(Lich),
|
||||
typeof(LichLord)
|
||||
};
|
||||
|
||||
humanoid.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.Repond,
|
||||
|
||||
typeof(ClanCA), typeof(ClanCT),
|
||||
typeof(ClanRS), typeof(ClanRC),
|
||||
typeof(ClanSS), typeof(ClanSH),
|
||||
typeof(Barracoon), typeof(MasterTheophilus),
|
||||
typeof(Lurg), typeof(ArcticOgreLord),
|
||||
typeof(Cyclops), typeof(Ettin),
|
||||
typeof(EvilMage), typeof(EvilMageLord),
|
||||
typeof(FrostTroll), typeof(MeerCaptain),
|
||||
typeof(MeerEternal), typeof(MeerMage),
|
||||
typeof(MeerWarrior), typeof(Ogre),
|
||||
typeof(OgreLord), typeof(Orc),
|
||||
typeof(OrcBomber), typeof(OrcBrute),
|
||||
typeof(OrcCaptain), typeof(OrcChopper),
|
||||
typeof(OrcScout), typeof(OrcishLord),
|
||||
typeof(OrcishMage), typeof(Ratman),
|
||||
typeof(RatmanArcher), typeof(RatmanMage),
|
||||
typeof(SavageRider), typeof(SavageShaman),
|
||||
typeof(Savage), typeof(Titan),
|
||||
typeof(Troglodyte), typeof(Troll),
|
||||
typeof(Troglodyte), typeof(MougGuur),
|
||||
typeof(Chiikkaha), typeof(Minotaur),
|
||||
typeof(MinotaurGeneral), typeof(Medusa),
|
||||
typeof(RakktaviRenowned), typeof(TikitaviRenowned),
|
||||
typeof(VitaviRenowned), typeof(EnslavedGoblinScout),
|
||||
typeof(EnslavedGoblinKeeper), typeof(EnslavedGreenGoblin),
|
||||
typeof(EnslavedGreenGoblinAlchemist), typeof(EnslavedGoblinMage),
|
||||
typeof(EnslavedGrayGoblin), typeof(GreenGoblinScout),
|
||||
typeof(GreenGoblinAlchemist), typeof(GreenGoblin),
|
||||
typeof(GrayGoblinMage), typeof(GrayGoblinKeeper),
|
||||
typeof(GrayGoblin), typeof(GreenGoblinAlchemistRenowned),
|
||||
typeof(GrayGoblinMageRenowned), typeof(CorgulTheSoulBinder),
|
||||
typeof(PirateCrew), typeof(LizardmanWitchdoctor),
|
||||
typeof(OrcFootSoldier), typeof(RatmanAssassin),
|
||||
typeof(OgreBoneCrusher), typeof(TitanRockHunter)
|
||||
);
|
||||
|
||||
humanoid.Entries = new SlayerEntry[]
|
||||
{
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.OgreTrashing,
|
||||
|
||||
typeof(Ogre), typeof(OgreLord),
|
||||
typeof(ArcticOgreLord), typeof(OgreBoneCrusher)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.OrcSlaying,
|
||||
|
||||
typeof(Orc), typeof(OrcBomber),
|
||||
typeof(OrcBrute), typeof(OrcCaptain),
|
||||
typeof(OrcChopper), typeof(OrcScout),
|
||||
typeof(OrcishLord), typeof(OrcishMage),
|
||||
typeof(OrcFootSoldier)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.TrollSlaughter,
|
||||
|
||||
typeof(Troll), typeof(FrostTroll)
|
||||
),
|
||||
};
|
||||
|
||||
undead.Opposition = new SlayerGroup[]
|
||||
{
|
||||
humanoid
|
||||
};
|
||||
|
||||
undead.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.Silver,
|
||||
|
||||
typeof(AncientLich), typeof(AncientLichRenowned),
|
||||
typeof(Bogle), typeof(BoneKnight),
|
||||
typeof(BoneMagi), typeof(DarkGuardian),
|
||||
typeof(DarknightCreeper), typeof(FleshGolem),
|
||||
typeof(Ghoul), typeof(GoreFiend),
|
||||
typeof(HellSteed), typeof(LadyOfTheSnow),
|
||||
typeof(Lich), typeof(LichLord),
|
||||
typeof(Mummy), typeof(PestilentBandage),
|
||||
typeof(Revenant), typeof(RevenantLion),
|
||||
typeof(RottingCorpse), typeof(Shade),
|
||||
typeof(ShadowKnight), typeof(SkeletalKnight),
|
||||
typeof(SkeletalMage), typeof(SkeletalMount),
|
||||
typeof(Skeleton), typeof(Spectre),
|
||||
typeof(Wraith), typeof(Zombie),
|
||||
typeof(UnfrozenMummy), typeof(RedDeath),
|
||||
typeof(SirPatrick), typeof(LadyJennifyr),
|
||||
typeof(MasterMikael), typeof(MasterJonath),
|
||||
typeof(LadyMarai), typeof(PrimevalLich),
|
||||
typeof(Niporailem), typeof(DreamWraith),
|
||||
typeof(EffeteUndeadGargoyle), typeof(UndeadGargoyle),
|
||||
typeof(UndeadGuardian), typeof(PutridUndeadGargoyle),
|
||||
typeof(PutridUndeadGuardian), typeof(Juonar),
|
||||
typeof(Spellbinder), typeof(AngeredSpirit),
|
||||
typeof(BoneSwordSlinger), typeof(CovetousRevenant),
|
||||
typeof(DiseasedLich), typeof(VileCadaver),
|
||||
typeof(GrizzledMare), typeof(SkeletalCat)
|
||||
);
|
||||
|
||||
undead.Entries = new SlayerEntry[0];
|
||||
|
||||
fey.Opposition = new SlayerGroup[]
|
||||
{
|
||||
abyss
|
||||
};
|
||||
|
||||
fey.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.Fey,
|
||||
|
||||
typeof(Centaur), typeof(CuSidhe),
|
||||
typeof(EtherealWarrior), typeof(Kirin),
|
||||
typeof(LordOaks), typeof(Pixie),
|
||||
typeof(PixieRenowned), typeof(Silvani),
|
||||
typeof(Treefellow), typeof(Unicorn),
|
||||
typeof(Wisp), typeof(MLDryad),
|
||||
typeof(Satyr), typeof(Changeling),
|
||||
typeof(InsaneDryad), typeof(CorporealBrume),
|
||||
typeof(CrystalLatticeSeeker), typeof(LadyMelisande),
|
||||
typeof(DreadHorn), typeof(Travesty),
|
||||
typeof(ShimmeringEffusion), typeof(Guile),
|
||||
typeof(Irk), typeof(DarkWisp),
|
||||
typeof(FeralTreefellow)
|
||||
);
|
||||
|
||||
fey.Entries = new SlayerEntry[0];
|
||||
|
||||
elemental.Opposition = new SlayerGroup[]
|
||||
{
|
||||
abyss
|
||||
};
|
||||
|
||||
elemental.FoundOn = new Type[]
|
||||
{
|
||||
typeof(Balron), typeof(Daemon),
|
||||
typeof(Putrefier), typeof(FireDaemonRenowned)
|
||||
};
|
||||
|
||||
elemental.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.ElementalBan,
|
||||
|
||||
typeof(LavaElemental), typeof(ToxicElemental),
|
||||
typeof(AcidElemental), typeof(AcidElementalRenowned),
|
||||
typeof(FireElementalRenowned), typeof(AgapiteElemental),
|
||||
typeof(AirElemental), typeof(SummonedAirElemental),
|
||||
typeof(BloodElemental), typeof(BronzeElemental),
|
||||
typeof(CopperElemental), typeof(CrystalElemental),
|
||||
typeof(DullCopperElemental), typeof(EarthElemental),
|
||||
typeof(SummonedEarthElemental), typeof(Efreet),
|
||||
typeof(FireElemental), typeof(SummonedFireElemental),
|
||||
typeof(GoldenElemental), typeof(IceElemental),
|
||||
typeof(KazeKemono), typeof(PoisonElemental),
|
||||
typeof(RaiJu), typeof(SandVortex),
|
||||
typeof(ShadowIronElemental), typeof(SnowElemental),
|
||||
typeof(ValoriteElemental), typeof(VeriteElemental),
|
||||
typeof(WaterElemental), typeof(SummonedWaterElemental),
|
||||
typeof(Flurry), typeof(Mistral),
|
||||
typeof(Tempest), typeof(UnboundEnergyVortex),
|
||||
typeof(ChaosVortex), typeof(WindElemental),
|
||||
typeof(FlameElemental), typeof(QuartzElemental),
|
||||
typeof(VoidManifestation), typeof(DemonKnight),
|
||||
typeof(CovetousEarthElemental), typeof(VenomElemental),
|
||||
typeof(SearingElemental), typeof(VortexElemental),
|
||||
typeof(CovetousWaterElemental)
|
||||
);
|
||||
|
||||
elemental.Entries = new SlayerEntry[]
|
||||
{
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.BloodDrinking,
|
||||
|
||||
typeof(BloodElemental), typeof(DemonKnight)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.EarthShatter,
|
||||
|
||||
typeof(AgapiteElemental), typeof(BronzeElemental),
|
||||
typeof(CopperElemental), typeof(DullCopperElemental),
|
||||
typeof(EarthElemental), typeof(SummonedEarthElemental),
|
||||
typeof(GoldenElemental), typeof(ShadowIronElemental),
|
||||
typeof(ValoriteElemental), typeof(VeriteElemental),
|
||||
typeof(QuartzElemental), typeof(DemonKnight),
|
||||
typeof(CovetousEarthElemental)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.ElementalHealth,
|
||||
|
||||
typeof(PoisonElemental), typeof(DemonKnight),
|
||||
typeof(VenomElemental)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.FlameDousing,
|
||||
|
||||
typeof(FireElemental), typeof(FireElementalRenowned),
|
||||
typeof(SummonedFireElemental), typeof(FlameElemental),
|
||||
typeof(DemonKnight), typeof(SearingElemental)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.SummerWind,
|
||||
|
||||
typeof(SnowElemental), typeof(IceElemental),
|
||||
typeof(DemonKnight)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.Vacuum,
|
||||
|
||||
typeof(AirElemental), typeof(SummonedAirElemental),
|
||||
typeof(Flurry), typeof(Mistral),
|
||||
typeof(Tempest), typeof(UnboundEnergyVortex),
|
||||
typeof(ChaosVortex), typeof(WindElemental),
|
||||
typeof(DemonKnight), typeof(VortexElemental)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.WaterDissipation,
|
||||
|
||||
typeof(WaterElemental), typeof(SummonedWaterElemental),
|
||||
typeof(DemonKnight), typeof(CovetousWaterElemental)
|
||||
)
|
||||
};
|
||||
|
||||
abyss.Opposition = new SlayerGroup[]
|
||||
{
|
||||
elemental,
|
||||
fey
|
||||
};
|
||||
|
||||
abyss.FoundOn = new Type[]
|
||||
{
|
||||
typeof(BloodElemental)
|
||||
};
|
||||
|
||||
if (Core.AOS)
|
||||
{
|
||||
abyss.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.Exorcism,
|
||||
|
||||
typeof(DevourerRenowned), typeof(FireDaemonRenowned),
|
||||
typeof(AbysmalHorror), typeof(AbyssalInfernal),
|
||||
typeof(ArcaneDaemon), typeof(Balron),
|
||||
typeof(BoneDemon), typeof(ChaosDaemon),
|
||||
typeof(Daemon), typeof(SummonedDaemon),
|
||||
typeof(DemonKnight), typeof(Devourer),
|
||||
typeof(EnslavedGargoyle), typeof(FanDancer),
|
||||
typeof(FireGargoyle), typeof(Gargoyle),
|
||||
typeof(GargoyleDestroyer), typeof(GargoyleEnforcer),
|
||||
typeof(Gibberling), typeof(HordeMinion),
|
||||
typeof(FireDaemon), typeof(IceFiend),
|
||||
typeof(Imp), typeof(Impaler),
|
||||
typeof(Moloch), typeof(Oni),
|
||||
typeof(Ravager), typeof(Semidar),
|
||||
typeof(StoneGargoyle), typeof(Succubus),
|
||||
typeof(PatchworkSkeleton), typeof(TsukiWolf),
|
||||
typeof(Szavetra), typeof(CrystalDaemon),
|
||||
typeof(SlasherOfVeils), typeof(GargoyleShade),
|
||||
typeof(Putrefier), typeof(ChiefParoxysmus),
|
||||
typeof(Anzuanord), typeof(Ballem),
|
||||
typeof(Betballem), typeof(SkeletalLich),
|
||||
typeof(UsagralemBallem), typeof(EffetePutridGargoyle),
|
||||
typeof(EffeteUndeadGargoyle), typeof(PitFiend),
|
||||
typeof(ArchDaemon), typeof(AbyssalAbomination),
|
||||
typeof(Virtuebane), typeof(LesserOni),
|
||||
typeof(Lifestealer)
|
||||
);
|
||||
|
||||
abyss.Entries = new SlayerEntry[]
|
||||
{
|
||||
// Daemon Dismissal & Balron Damnation have been removed and moved up to super slayer on OSI.
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.GargoylesFoe,
|
||||
|
||||
typeof(EnslavedGargoyle), typeof(FireGargoyle),
|
||||
typeof(Gargoyle), typeof(GargoyleDestroyer),
|
||||
typeof(GargoyleEnforcer), typeof(StoneGargoyle),
|
||||
typeof(GargoyleShade), typeof(EffetePutridGargoyle),
|
||||
typeof(EffeteUndeadGargoyle), typeof(DaemonMongbat),
|
||||
typeof(CovetousDoppleganger), typeof(CovetousFireDaemon),
|
||||
typeof(GargoyleAssassin), typeof(LesserOni)
|
||||
),
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
abyss.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.Exorcism,
|
||||
|
||||
typeof(AbysmalHorror), typeof(Balron),
|
||||
typeof(BoneDemon), typeof(ChaosDaemon),
|
||||
typeof(Daemon), typeof(SummonedDaemon),
|
||||
typeof(DemonKnight), typeof(Devourer),
|
||||
typeof(Gargoyle), typeof(FireGargoyle),
|
||||
typeof(Gibberling), typeof(HordeMinion),
|
||||
typeof(IceFiend), typeof(Imp),
|
||||
typeof(Impaler), typeof(Ravager),
|
||||
typeof(StoneGargoyle), typeof(ArcaneDaemon),
|
||||
typeof(EnslavedGargoyle), typeof(GargoyleDestroyer),
|
||||
typeof(GargoyleEnforcer), typeof(Moloch)
|
||||
);
|
||||
|
||||
abyss.Entries = new SlayerEntry[]
|
||||
{
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.DaemonDismissal,
|
||||
|
||||
typeof(Semidar), typeof(AbyssalInfernal),
|
||||
typeof(AbysmalHorror), typeof(Balron),
|
||||
typeof(BoneDemon), typeof(ChaosDaemon),
|
||||
typeof(Daemon), typeof(SummonedDaemon),
|
||||
typeof(DemonKnight), typeof(Devourer),
|
||||
typeof(Gibberling), typeof(HordeMinion),
|
||||
typeof(IceFiend), typeof(Imp),
|
||||
typeof(Impaler), typeof(Ravager),
|
||||
typeof(ArcaneDaemon), typeof(Moloch)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.GargoylesFoe,
|
||||
|
||||
typeof(FireGargoyle), typeof(Gargoyle),
|
||||
typeof(StoneGargoyle), typeof(EnslavedGargoyle),
|
||||
typeof(GargoyleDestroyer), typeof(GargoyleEnforcer)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.BalronDamnation,
|
||||
|
||||
typeof(Balron)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
arachnid.Opposition = new SlayerGroup[]
|
||||
{
|
||||
reptilian
|
||||
};
|
||||
|
||||
arachnid.FoundOn = new Type[]
|
||||
{
|
||||
typeof(AncientWyrm), typeof(GreaterDragon),
|
||||
typeof(Dragon), typeof(OphidianMatriarch),
|
||||
typeof(ShadowWyrm)
|
||||
};
|
||||
|
||||
arachnid.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.ArachnidDoom,
|
||||
|
||||
typeof(DreadSpider), typeof(FrostSpider),
|
||||
typeof(GiantBlackWidow), typeof(GiantSpider),
|
||||
typeof(Mephitis), typeof(Scorpion),
|
||||
typeof(TerathanAvenger), typeof(TerathanDrone),
|
||||
typeof(TerathanMatriarch), typeof(TerathanWarrior),
|
||||
typeof(Miasma), typeof(SpeckledScorpion),
|
||||
typeof(LadyLissith), typeof(LadySabrix),
|
||||
typeof(Virulent), typeof(Silk),
|
||||
typeof(Malefic), typeof(Navrey),
|
||||
typeof(SentinelSpider), typeof(WolfSpider),
|
||||
typeof(TrapdoorSpider), typeof(Anlorzen),
|
||||
typeof(Anlorlem)
|
||||
);
|
||||
|
||||
arachnid.Entries = new SlayerEntry[]
|
||||
{
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.ScorpionsBane,
|
||||
|
||||
typeof(Scorpion), typeof(Miasma),
|
||||
typeof(SpeckledScorpion)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.SpidersDeath,
|
||||
|
||||
typeof(DreadSpider), typeof(FrostSpider),
|
||||
typeof(GiantBlackWidow), typeof(GiantSpider),
|
||||
typeof(Mephitis), typeof(LadyLissith),
|
||||
typeof(LadySabrix), typeof(Virulent),
|
||||
typeof(Silk), typeof(Malefic),
|
||||
typeof(Navrey), typeof(SentinelSpider),
|
||||
typeof(WolfSpider), typeof(TrapdoorSpider),
|
||||
typeof(Anlorzen)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.Terathan,
|
||||
|
||||
typeof(TerathanAvenger), typeof(TerathanDrone),
|
||||
typeof(TerathanMatriarch), typeof(TerathanWarrior),
|
||||
typeof(Anlorlem)
|
||||
)
|
||||
};
|
||||
|
||||
reptilian.Opposition = new SlayerGroup[]
|
||||
{
|
||||
arachnid
|
||||
};
|
||||
|
||||
reptilian.FoundOn = new Type[]
|
||||
{
|
||||
typeof(TerathanAvenger), typeof(TerathanMatriarch)
|
||||
};
|
||||
|
||||
reptilian.Super = new SlayerEntry
|
||||
(
|
||||
SlayerName.ReptilianDeath,
|
||||
|
||||
typeof(Rikktor), typeof(Serado),
|
||||
typeof(SkeletalDragonRenowned), typeof(WyvernRenowned),
|
||||
typeof(AncientWyrm), typeof(DeepSeaSerpent),
|
||||
typeof(GreaterDragon), typeof(Dragon),
|
||||
typeof(Drake), typeof(GiantIceWorm),
|
||||
typeof(IceSerpent), typeof(GiantSerpent),
|
||||
typeof(Hiryu), typeof(IceSnake),
|
||||
typeof(JukaLord), typeof(JukaMage),
|
||||
typeof(JukaWarrior), typeof(LavaSerpent),
|
||||
typeof(LavaSnake), typeof(LesserHiryu),
|
||||
typeof(Lizardman), typeof(OphidianArchmage),
|
||||
typeof(OphidianKnight), typeof(OphidianMage),
|
||||
typeof(OphidianMatriarch), typeof(OphidianWarrior),
|
||||
typeof(Reptalon), typeof(SeaSerpent),
|
||||
typeof(Serado), typeof(SerpentineDragon),
|
||||
typeof(ShadowWyrm), typeof(SilverSerpent),
|
||||
typeof(SkeletalDragon), typeof(Snake),
|
||||
typeof(SwampDragon), typeof(WhiteWyrm),
|
||||
typeof(Wyvern), typeof(Yamandon),
|
||||
typeof(Hydra), typeof(CrystalHydra),
|
||||
typeof(CrystalSeaSerpent), typeof(Rend),
|
||||
typeof(Thrasher), typeof(Abscess),
|
||||
typeof(Grim), typeof(ChickenLizard),
|
||||
typeof(StygianDragon), typeof(FairyDragon),
|
||||
typeof(Skree), typeof(Slith),
|
||||
typeof(StoneSlith), typeof(ToxicSlith),
|
||||
typeof(Raptor), typeof(Kepetch),
|
||||
typeof(KepetchAmbusher), typeof(FrostDragon),
|
||||
typeof(ColdDrake), typeof(FrostDrake), typeof(Coil),
|
||||
typeof(SkeletalDrake), typeof(CoralSnake)
|
||||
);
|
||||
|
||||
reptilian.Entries = new SlayerEntry[]
|
||||
{
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.DragonSlaying,
|
||||
|
||||
typeof(Rikktor), typeof(SkeletalDragonRenowned),
|
||||
typeof(WyvernRenowned), typeof(AncientWyrm),
|
||||
typeof(GreaterDragon), typeof(Dragon),
|
||||
typeof(Drake), typeof(Hiryu),
|
||||
typeof(LesserHiryu), typeof(Reptalon),
|
||||
typeof(SerpentineDragon), typeof(ShadowWyrm),
|
||||
typeof(SkeletalDragon), typeof(SwampDragon),
|
||||
typeof(WhiteWyrm), typeof(Wyvern),
|
||||
typeof(Hydra), typeof(CrystalHydra),
|
||||
typeof(Rend), typeof(Abscess),
|
||||
typeof(Grim), typeof(StygianDragon),
|
||||
typeof(FairyDragon), typeof(SkeletalDrake),
|
||||
typeof(ColdDrake)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.LizardmanSlaughter,
|
||||
|
||||
typeof(Lizardman)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.Ophidian,
|
||||
|
||||
typeof(OphidianArchmage), typeof(OphidianKnight),
|
||||
typeof(OphidianMage), typeof(OphidianMatriarch),
|
||||
typeof(OphidianWarrior)
|
||||
),
|
||||
|
||||
new SlayerEntry
|
||||
(
|
||||
SlayerName.SnakesBane,
|
||||
|
||||
typeof(CrystalSeaSerpent), typeof(Coil),
|
||||
typeof(CoralSnake), typeof(DeepSeaSerpent),
|
||||
typeof(GiantIceWorm), typeof(GiantSerpent),
|
||||
typeof(IceSerpent), typeof(IceSnake),
|
||||
typeof(LavaSerpent), typeof(LavaSnake),
|
||||
typeof(SeaSerpent), typeof(Serado),
|
||||
typeof(SilverSerpent), typeof(Snake),
|
||||
typeof(Yamandon)
|
||||
)
|
||||
};
|
||||
|
||||
eodon.Opposition = new SlayerGroup[] { };
|
||||
eodon.FoundOn = new Type[] { };
|
||||
eodon.Super =
|
||||
new SlayerEntry(
|
||||
|
||||
SlayerName.Eodon,
|
||||
|
||||
typeof(Dimetrosaur), typeof(Gallusaurus),
|
||||
typeof(Archaeosaurus), typeof(Najasaurus),
|
||||
typeof(Saurosaurus), typeof(Allosaurus),
|
||||
typeof(MyrmidexLarvae), typeof(MyrmidexDrone),
|
||||
typeof(MyrmidexWarrior), typeof(DragonTurtle),
|
||||
typeof(DragonTurtleHatchling), typeof(DesertScorpion),
|
||||
typeof(TribeWarrior), typeof(TribeShaman),
|
||||
typeof(TribeChieftan), typeof(WildTiger),
|
||||
typeof(WildBlackTiger), typeof(WildWhiteTiger),
|
||||
typeof(TRex), typeof(SilverbackGorilla));
|
||||
|
||||
eodon.Entries = new SlayerEntry[] { };
|
||||
|
||||
eodonTribe.Opposition = new SlayerGroup[] { };
|
||||
eodonTribe.FoundOn = new Type[] { };
|
||||
eodonTribe.Super = new SlayerEntry(SlayerName.EodonTribe, typeof(TribeWarrior), typeof(TribeShaman), typeof(TribeChieftan));
|
||||
eodonTribe.Entries = new SlayerEntry[] { };
|
||||
|
||||
dino.Opposition = new SlayerGroup[] { fey };
|
||||
dino.FoundOn = new Type[] { };
|
||||
dino.Super =
|
||||
new SlayerEntry(
|
||||
|
||||
SlayerName.Dinosaur,
|
||||
|
||||
typeof(Dimetrosaur), typeof(Gallusaurus),
|
||||
typeof(Archaeosaurus), typeof(Najasaurus),
|
||||
typeof(Saurosaurus), typeof(Allosaurus),
|
||||
typeof(MyrmidexLarvae), typeof(MyrmidexDrone),
|
||||
typeof(TRex), typeof(MyrmidexWarrior));
|
||||
|
||||
dino.Entries = new SlayerEntry[] { };
|
||||
|
||||
myrmidex.Opposition = new SlayerGroup[] { fey };
|
||||
myrmidex.FoundOn = new Type[] { };
|
||||
myrmidex.Super = new SlayerEntry(
|
||||
|
||||
SlayerName.Myrmidex,
|
||||
|
||||
typeof(MyrmidexLarvae), typeof(MyrmidexDrone),
|
||||
typeof(MyrmidexWarrior));
|
||||
myrmidex.Entries = new SlayerEntry[] { };
|
||||
|
||||
m_Groups = new SlayerGroup[]
|
||||
{
|
||||
humanoid,
|
||||
undead,
|
||||
elemental,
|
||||
abyss,
|
||||
arachnid,
|
||||
reptilian,
|
||||
fey,
|
||||
eodon,
|
||||
eodonTribe,
|
||||
dino,
|
||||
myrmidex,
|
||||
};
|
||||
|
||||
m_TotalEntries = CompileEntries(m_Groups);
|
||||
}
|
||||
|
||||
public static SlayerEntry[] TotalEntries
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_TotalEntries;
|
||||
}
|
||||
}
|
||||
public static SlayerGroup[] Groups
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Groups;
|
||||
}
|
||||
}
|
||||
public SlayerGroup[] Opposition
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Opposition;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Opposition = value;
|
||||
}
|
||||
}
|
||||
public SlayerEntry Super
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Super;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Super = value;
|
||||
}
|
||||
}
|
||||
public SlayerEntry[] Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Entries;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Entries = value;
|
||||
}
|
||||
}
|
||||
public Type[] FoundOn
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_FoundOn;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_FoundOn = value;
|
||||
}
|
||||
}
|
||||
public static SlayerEntry GetEntryByName(SlayerName name)
|
||||
{
|
||||
int v = (int)name;
|
||||
|
||||
if (v >= 0 && v < m_TotalEntries.Length)
|
||||
return m_TotalEntries[v];
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SlayerName GetLootSlayerType(Type type)
|
||||
{
|
||||
for (int i = 0; i < m_Groups.Length; ++i)
|
||||
{
|
||||
SlayerGroup group = m_Groups[i];
|
||||
Type[] foundOn = group.FoundOn;
|
||||
|
||||
bool inGroup = false;
|
||||
|
||||
for (int j = 0; foundOn != null && !inGroup && j < foundOn.Length; ++j)
|
||||
inGroup = (foundOn[j] == type);
|
||||
|
||||
if (inGroup)
|
||||
{
|
||||
int index = Utility.Random(1 + group.Entries.Length);
|
||||
|
||||
if (index == 0)
|
||||
return group.m_Super.Name;
|
||||
|
||||
return group.Entries[index - 1].Name;
|
||||
}
|
||||
}
|
||||
|
||||
return SlayerName.Silver;
|
||||
}
|
||||
|
||||
public bool OppositionSuperSlays(Mobile m)
|
||||
{
|
||||
for (int i = 0; i < this.Opposition.Length; i++)
|
||||
{
|
||||
if (this.Opposition[i].Super.Slays(m))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_Super.Name == SlayerName.Eodon && !m_Super.Slays(m))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static SlayerEntry[] CompileEntries(SlayerGroup[] groups)
|
||||
{
|
||||
SlayerEntry[] entries = new SlayerEntry[32];
|
||||
|
||||
for (int i = 0; i < groups.Length; ++i)
|
||||
{
|
||||
SlayerGroup g = groups[i];
|
||||
|
||||
g.Super.Group = g;
|
||||
|
||||
entries[(int)g.Super.Name] = g.Super;
|
||||
|
||||
for (int j = 0; j < g.Entries.Length; ++j)
|
||||
{
|
||||
g.Entries[j].Group = g;
|
||||
entries[(int)g.Entries[j].Name] = g.Entries[j];
|
||||
}
|
||||
}
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
public static SlayerName RandomSuperSlayerAOS(bool excludeFey = true)
|
||||
{
|
||||
int maxIndex = excludeFey ? 5 : 6;
|
||||
|
||||
return Groups[Utility.Random(maxIndex)].Super.Name;
|
||||
}
|
||||
|
||||
public static SlayerName RandomSuperSlayerTOL()
|
||||
{
|
||||
return Groups[Utility.Random(Groups.Length)].Super.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Scripts/Abilities/SlayerName.cs
Normal file
40
Scripts/Abilities/SlayerName.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public enum SlayerName
|
||||
{
|
||||
None,
|
||||
Silver,
|
||||
OrcSlaying,
|
||||
TrollSlaughter,
|
||||
OgreTrashing,
|
||||
Repond,
|
||||
DragonSlaying,
|
||||
Terathan,
|
||||
SnakesBane,
|
||||
LizardmanSlaughter,
|
||||
ReptilianDeath,
|
||||
DaemonDismissal,
|
||||
GargoylesFoe,
|
||||
BalronDamnation,
|
||||
Exorcism,
|
||||
Ophidian,
|
||||
SpidersDeath,
|
||||
ScorpionsBane,
|
||||
ArachnidDoom,
|
||||
FlameDousing,
|
||||
WaterDissipation,
|
||||
Vacuum,
|
||||
ElementalHealth,
|
||||
EarthShatter,
|
||||
BloodDrinking,
|
||||
SummerWind,
|
||||
ElementalBan,
|
||||
Fey,
|
||||
Dinosaur,
|
||||
Myrmidex,
|
||||
Eodon,
|
||||
EodonTribe
|
||||
}
|
||||
}
|
||||
119
Scripts/Abilities/TalonStrike.cs
Normal file
119
Scripts/Abilities/TalonStrike.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// Attack with increased damage with additional damage over time.
|
||||
/// </summary>
|
||||
public class TalonStrike : WeaponAbility
|
||||
{
|
||||
private static readonly Hashtable m_Registry = new Hashtable();
|
||||
public TalonStrike()
|
||||
{
|
||||
}
|
||||
|
||||
public override SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return from.Skills[SkillName.Ninjitsu].Base > from.Skills[SkillName.Bushido].Base ? SkillName.Ninjitsu : SkillName.Bushido;
|
||||
}
|
||||
|
||||
public static Hashtable Registry
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Registry;
|
||||
}
|
||||
}
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 20;
|
||||
}
|
||||
}
|
||||
public override double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.2;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (Registry.Contains(defender) || !this.Validate(attacker) || !this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
attacker.SendLocalizedMessage(1063358); // You deliver a talon strike!
|
||||
defender.SendLocalizedMessage(1063359); // Your attacker delivers a talon strike!
|
||||
|
||||
defender.FixedParticles(0x373A, 1, 17, 0x26BC, 0x662, 0, EffectLayer.Waist);
|
||||
|
||||
Timer t = new InternalTimer(defender, (int)(10.0 * (attacker.Skills[SkillName.Ninjitsu].Value - 50.0) / 70.0 + 5), attacker); //5 - 15 damage
|
||||
|
||||
BuffInfo.AddBuff(defender, new BuffInfo(BuffIcon.TalonStrike, 1028856, 1151309, TimeSpan.FromSeconds(5.0), defender, "40"));
|
||||
|
||||
t.Start();
|
||||
|
||||
Registry.Add(defender, t);
|
||||
|
||||
if (attacker is BaseCreature)
|
||||
PetTrainingHelper.OnWeaponAbilityUsed((BaseCreature)attacker, SkillName.Ninjitsu);
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Defender;
|
||||
private readonly Mobile m_Attacker;
|
||||
private readonly double DamagePerTick;
|
||||
private double m_DamageRemaining;
|
||||
private double m_DamageToDo;
|
||||
public InternalTimer(Mobile defender, int totalDamage, Mobile attacker)
|
||||
: base(TimeSpan.Zero, TimeSpan.FromSeconds(0.25), 12)// 3 seconds at .25 seconds apart = 12. Confirm delay inbetween of .25 each.
|
||||
{
|
||||
this.m_Defender = defender;
|
||||
this.m_DamageRemaining = (double)totalDamage;
|
||||
this.Priority = TimerPriority.TwentyFiveMS;
|
||||
|
||||
this.m_Attacker = attacker;
|
||||
|
||||
this.DamagePerTick = (double)totalDamage / 12 + .01;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
if (!this.m_Defender.Alive || this.m_DamageRemaining <= 0)
|
||||
{
|
||||
this.Stop();
|
||||
Server.Items.TalonStrike.Registry.Remove(this.m_Defender);
|
||||
return;
|
||||
}
|
||||
|
||||
this.m_DamageRemaining -= this.DamagePerTick;
|
||||
this.m_DamageToDo += this.DamagePerTick;
|
||||
|
||||
if (this.m_DamageRemaining <= 0 && this.m_DamageToDo < 1)
|
||||
this.m_DamageToDo = 1.0; //Confirm this 'round up' at the end
|
||||
|
||||
int damage = (int)this.m_DamageToDo;
|
||||
|
||||
if (damage > 0)
|
||||
{
|
||||
//m_Defender.Damage( damage, m_Attacker, false );
|
||||
this.m_Defender.Hits -= damage; //Don't show damage, don't disrupt
|
||||
this.m_DamageToDo -= damage;
|
||||
}
|
||||
|
||||
if (!this.m_Defender.Alive || this.m_DamageRemaining <= 0)
|
||||
{
|
||||
this.Stop();
|
||||
Server.Items.TalonStrike.Registry.Remove(this.m_Defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Scripts/Abilities/TimedResistanceMod.cs
Normal file
68
Scripts/Abilities/TimedResistanceMod.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
// Created by Peoharen
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class TimedResistanceMod
|
||||
{
|
||||
private static readonly Dictionary<string, ResistanceModTimer> m_Table = new Dictionary<string, ResistanceModTimer>();
|
||||
public static void AddMod(Mobile m, string name, ResistanceMod[] mods, TimeSpan duration)
|
||||
{
|
||||
string fullname = name + ":" + m.Serial.ToString();
|
||||
|
||||
if (m_Table.ContainsKey(fullname))
|
||||
{
|
||||
ResistanceModTimer timer = m_Table[fullname];
|
||||
timer.End();
|
||||
m_Table.Remove(fullname);
|
||||
}
|
||||
|
||||
ResistanceModTimer timertostart = new ResistanceModTimer(m, name, mods, duration);
|
||||
timertostart.Start();
|
||||
m_Table.Add(fullname, timertostart);
|
||||
}
|
||||
|
||||
public static void RemoveMod(Mobile m, string name)
|
||||
{
|
||||
string fullname = name + ":" + m.Serial.ToString();
|
||||
|
||||
if (m_Table.ContainsKey(fullname))
|
||||
{
|
||||
ResistanceModTimer t = m_Table[fullname];
|
||||
|
||||
if (t != null)
|
||||
t.End();
|
||||
|
||||
m_Table.Remove(fullname);
|
||||
}
|
||||
}
|
||||
|
||||
public class ResistanceModTimer : Timer
|
||||
{
|
||||
public Mobile m_Mobile;
|
||||
public ResistanceMod[] m_Mods;
|
||||
public String m_Name;
|
||||
public ResistanceModTimer(Mobile m, string name, ResistanceMod[] mods, TimeSpan duration)
|
||||
: base(duration)
|
||||
{
|
||||
this.m_Mobile = m;
|
||||
this.m_Name = name;
|
||||
this.m_Mods = mods;
|
||||
}
|
||||
|
||||
public void End()
|
||||
{
|
||||
for (int i = 0; i < this.m_Mods.Length; ++i)
|
||||
this.m_Mobile.RemoveResistanceMod(this.m_Mods[i]);
|
||||
|
||||
this.Stop();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
RemoveMod(this.m_Mobile, this.m_Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
561
Scripts/Abilities/WeaponAbility.cs
Normal file
561
Scripts/Abilities/WeaponAbility.cs
Normal file
@@ -0,0 +1,561 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
using Server.Network;
|
||||
using Server.Spells;
|
||||
using Server.Spells.SkillMasteries;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public abstract class WeaponAbility
|
||||
{
|
||||
public virtual int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int AccuracyBonus
|
||||
{
|
||||
get
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public virtual double DamageScalar
|
||||
{
|
||||
get
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool RequiresSE
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return false to make this special ability consume no ammo from ranged weapons
|
||||
/// </summary>
|
||||
public virtual bool ConsumeAmmo
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnMiss(Mobile attacker, Mobile defender)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeSwing(Mobile attacker, Mobile defender)
|
||||
{
|
||||
// Here because you must be sure you can use the skill before calling CheckHit if the ability has a HCI bonus for example
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool RequiresSecondarySkill(Mobile from)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual double GetRequiredSkill(Mobile from)
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon != null && (weapon.PrimaryAbility == this || weapon.PrimaryAbility == Bladeweave))
|
||||
return 70.0;
|
||||
else if (weapon != null && (weapon.SecondaryAbility == this || weapon.SecondaryAbility == Bladeweave))
|
||||
return 90.0;
|
||||
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
public virtual double GetRequiredSecondarySkill(Mobile from)
|
||||
{
|
||||
if (!RequiresSecondarySkill(from))
|
||||
return 0.0;
|
||||
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon != null && (weapon.PrimaryAbility == this || weapon.PrimaryAbility == Bladeweave))
|
||||
return Core.TOL ? 30.0 : 70.0;
|
||||
else if (weapon != null && (weapon.SecondaryAbility == this || weapon.SecondaryAbility == Bladeweave))
|
||||
return Core.TOL ? 60.0 : 90.0;
|
||||
|
||||
return 200.0;
|
||||
}
|
||||
|
||||
public virtual SkillName GetSecondarySkill(Mobile from)
|
||||
{
|
||||
return SkillName.Tactics;
|
||||
}
|
||||
|
||||
public virtual int CalculateMana(Mobile from)
|
||||
{
|
||||
int mana = BaseMana;
|
||||
|
||||
double skillTotal = GetSkillTotal(from);
|
||||
|
||||
if (skillTotal >= 300.0)
|
||||
mana -= 10;
|
||||
else if (skillTotal >= 200.0)
|
||||
mana -= 5;
|
||||
|
||||
double scalar = 1.0;
|
||||
|
||||
if (!Server.Spells.Necromancy.MindRotSpell.GetMindRotScalar(from, ref scalar))
|
||||
{
|
||||
scalar = 1.0;
|
||||
}
|
||||
|
||||
if (Server.Spells.Mysticism.PurgeMagicSpell.IsUnderCurseEffects(from))
|
||||
{
|
||||
scalar += .5;
|
||||
}
|
||||
|
||||
// Lower Mana Cost = 40%
|
||||
int lmc = Math.Min(AosAttributes.GetValue(from, AosAttribute.LowerManaCost), 40);
|
||||
|
||||
lmc += BaseArmor.GetInherentLowerManaCost(from);
|
||||
|
||||
scalar -= (double)lmc / 100;
|
||||
mana = (int)(mana * scalar);
|
||||
|
||||
// Using a special move within 3 seconds of the previous special move costs double mana
|
||||
if (GetContext(from) != null)
|
||||
mana *= 2;
|
||||
|
||||
return mana;
|
||||
}
|
||||
|
||||
public virtual bool CheckWeaponSkill(Mobile from)
|
||||
{
|
||||
BaseWeapon weapon = from.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return false;
|
||||
|
||||
Skill skill = from.Skills[weapon.Skill];
|
||||
|
||||
double reqSkill = GetRequiredSkill(from);
|
||||
double reqSecondarySkill = GetRequiredSecondarySkill(from);
|
||||
SkillName secondarySkill = Core.TOL ? GetSecondarySkill(from) : SkillName.Tactics;
|
||||
|
||||
if (Core.ML && from.Skills[secondarySkill].Base < reqSecondarySkill)
|
||||
{
|
||||
int loc = GetSkillLocalization(secondarySkill);
|
||||
|
||||
if (loc == 1060184)
|
||||
{
|
||||
from.SendLocalizedMessage(loc);
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(loc, reqSecondarySkill.ToString());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (skill != null && skill.Base >= reqSkill)
|
||||
return true;
|
||||
|
||||
/* <UBWS> */
|
||||
if (weapon.WeaponAttributes.UseBestSkill > 0 && (from.Skills[SkillName.Swords].Base >= reqSkill || from.Skills[SkillName.Macing].Base >= reqSkill || from.Skills[SkillName.Fencing].Base >= reqSkill))
|
||||
return true;
|
||||
/* </UBWS> */
|
||||
|
||||
if (reqSecondarySkill != 0.0 && !Core.TOL)
|
||||
{
|
||||
from.SendLocalizedMessage(1079308, reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
}
|
||||
else
|
||||
{
|
||||
from.SendLocalizedMessage(1060182, reqSkill.ToString()); // You need ~1_SKILL_REQUIREMENT~ weapon skill to perform that attack
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetSkillLocalization(SkillName skill)
|
||||
{
|
||||
switch (skill)
|
||||
{
|
||||
default: return Core.TOL ? 1157351 : 1079308;
|
||||
// You need ~1_SKILL_REQUIREMENT~ weapon and tactics skill to perform that attack
|
||||
// You need ~1_SKILL_REQUIREMENT~ tactics skill to perform that attack
|
||||
case SkillName.Bushido:
|
||||
case SkillName.Ninjitsu: return 1063347;
|
||||
// You need ~1_SKILL_REQUIREMENT~ Bushido or Ninjitsu skill to perform that attack!
|
||||
case SkillName.Poisoning: return 1060184;
|
||||
// You lack the required poisoning to perform that attack
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool CheckSkills(Mobile from)
|
||||
{
|
||||
return CheckWeaponSkill(from);
|
||||
}
|
||||
|
||||
public virtual double GetSkillTotal(Mobile from)
|
||||
{
|
||||
return GetSkill(from, SkillName.Swords) + GetSkill(from, SkillName.Macing) +
|
||||
GetSkill(from, SkillName.Fencing) + GetSkill(from, SkillName.Archery) + GetSkill(from, SkillName.Parry) +
|
||||
GetSkill(from, SkillName.Lumberjacking) + GetSkill(from, SkillName.Stealth) + GetSkill(from, SkillName.Throwing) +
|
||||
GetSkill(from, SkillName.Poisoning) + GetSkill(from, SkillName.Bushido) + GetSkill(from, SkillName.Ninjitsu);
|
||||
}
|
||||
|
||||
public virtual double GetSkill(Mobile from, SkillName skillName)
|
||||
{
|
||||
Skill skill = from.Skills[skillName];
|
||||
|
||||
if (skill == null)
|
||||
return 0.0;
|
||||
|
||||
return skill.Value;
|
||||
}
|
||||
|
||||
public virtual bool CheckMana(Mobile from, bool consume)
|
||||
{
|
||||
int mana = CalculateMana(from);
|
||||
|
||||
if (from.Mana < mana)
|
||||
{
|
||||
from.SendLocalizedMessage(1060181, mana.ToString()); // You need ~1_MANA_REQUIREMENT~ mana to perform that attack
|
||||
return false;
|
||||
}
|
||||
|
||||
if (consume)
|
||||
{
|
||||
if (GetContext(from) == null)
|
||||
{
|
||||
Timer timer = new WeaponAbilityTimer(from);
|
||||
timer.Start();
|
||||
|
||||
AddContext(from, new WeaponAbilityContext(timer));
|
||||
}
|
||||
|
||||
if (ManaPhasingOrb.IsInManaPhase(from))
|
||||
ManaPhasingOrb.RemoveFromTable(from);
|
||||
else
|
||||
from.Mana -= mana;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual bool Validate(Mobile from)
|
||||
{
|
||||
if (!from.Player && (!Core.TOL || CheckMana(from, false)))
|
||||
return true;
|
||||
|
||||
NetState state = from.NetState;
|
||||
|
||||
if (state == null)
|
||||
return false;
|
||||
|
||||
if (RequiresSE && !state.SupportsExpansion(Expansion.SE))
|
||||
{
|
||||
from.SendLocalizedMessage(1063456); // You must upgrade to Samurai Empire in order to use that ability.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Spells.Bushido.HonorableExecution.IsUnderPenalty(from) || Spells.Ninjitsu.AnimalForm.UnderTransformation(from))
|
||||
{
|
||||
from.SendLocalizedMessage(1063024); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (Core.ML && from.Spell != null)
|
||||
{
|
||||
from.SendLocalizedMessage(1063024); // You cannot perform this special move right now.
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckSkills(from) && CheckMana(from, false);
|
||||
}
|
||||
|
||||
private static readonly WeaponAbility[] m_Abilities = new WeaponAbility[34]
|
||||
{
|
||||
null,
|
||||
new ArmorIgnore(),
|
||||
new BleedAttack(),
|
||||
new ConcussionBlow(),
|
||||
new CrushingBlow(),
|
||||
new Disarm(),
|
||||
new Dismount(),
|
||||
new DoubleStrike(),
|
||||
new InfectiousStrike(),
|
||||
new MortalStrike(),
|
||||
new MovingShot(),
|
||||
new ParalyzingBlow(),
|
||||
new ShadowStrike(),
|
||||
new WhirlwindAttack(),
|
||||
new RidingSwipe(),
|
||||
new FrenziedWhirlwind(),
|
||||
new Block(),
|
||||
new DefenseMastery(),
|
||||
new NerveStrike(),
|
||||
new TalonStrike(),
|
||||
new Feint(),
|
||||
new DualWield(),
|
||||
new DoubleShot(),
|
||||
new ArmorPierce(),
|
||||
new Bladeweave(),
|
||||
new ForceArrow(),
|
||||
new LightningArrow(),
|
||||
new PsychicAttack(),
|
||||
new SerpentArrow(),
|
||||
new ForceOfNature(),
|
||||
new InfusedThrow(),
|
||||
new MysticArc(),
|
||||
new Disrobe(),
|
||||
new ColdWind()
|
||||
};
|
||||
|
||||
public static WeaponAbility[] Abilities
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Abilities;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Hashtable m_Table = new Hashtable();
|
||||
|
||||
public static Hashtable Table
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Table;
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly WeaponAbility ArmorIgnore = m_Abilities[1];
|
||||
public static readonly WeaponAbility BleedAttack = m_Abilities[2];
|
||||
public static readonly WeaponAbility ConcussionBlow = m_Abilities[3];
|
||||
public static readonly WeaponAbility CrushingBlow = m_Abilities[4];
|
||||
public static readonly WeaponAbility Disarm = m_Abilities[5];
|
||||
public static readonly WeaponAbility Dismount = m_Abilities[6];
|
||||
public static readonly WeaponAbility DoubleStrike = m_Abilities[7];
|
||||
public static readonly WeaponAbility InfectiousStrike = m_Abilities[8];
|
||||
public static readonly WeaponAbility MortalStrike = m_Abilities[9];
|
||||
public static readonly WeaponAbility MovingShot = m_Abilities[10];
|
||||
public static readonly WeaponAbility ParalyzingBlow = m_Abilities[11];
|
||||
public static readonly WeaponAbility ShadowStrike = m_Abilities[12];
|
||||
public static readonly WeaponAbility WhirlwindAttack = m_Abilities[13];
|
||||
|
||||
public static readonly WeaponAbility RidingSwipe = m_Abilities[14];
|
||||
public static readonly WeaponAbility FrenziedWhirlwind = m_Abilities[15];
|
||||
public static readonly WeaponAbility Block = m_Abilities[16];
|
||||
public static readonly WeaponAbility DefenseMastery = m_Abilities[17];
|
||||
public static readonly WeaponAbility NerveStrike = m_Abilities[18];
|
||||
public static readonly WeaponAbility TalonStrike = m_Abilities[19];
|
||||
public static readonly WeaponAbility Feint = m_Abilities[20];
|
||||
public static readonly WeaponAbility DualWield = m_Abilities[21];
|
||||
public static readonly WeaponAbility DoubleShot = m_Abilities[22];
|
||||
public static readonly WeaponAbility ArmorPierce = m_Abilities[23];
|
||||
|
||||
public static readonly WeaponAbility Bladeweave = m_Abilities[24];
|
||||
public static readonly WeaponAbility ForceArrow = m_Abilities[25];
|
||||
public static readonly WeaponAbility LightningArrow = m_Abilities[26];
|
||||
public static readonly WeaponAbility PsychicAttack = m_Abilities[27];
|
||||
public static readonly WeaponAbility SerpentArrow = m_Abilities[28];
|
||||
public static readonly WeaponAbility ForceOfNature = m_Abilities[29];
|
||||
|
||||
public static readonly WeaponAbility InfusedThrow = m_Abilities[30];
|
||||
public static readonly WeaponAbility MysticArc = m_Abilities[31];
|
||||
|
||||
public static readonly WeaponAbility Disrobe = m_Abilities[32];
|
||||
public static readonly WeaponAbility ColdWind = m_Abilities[33];
|
||||
|
||||
public static bool IsWeaponAbility(Mobile m, WeaponAbility a)
|
||||
{
|
||||
if (a == null)
|
||||
return true;
|
||||
|
||||
if (!m.Player)
|
||||
return true;
|
||||
|
||||
BaseWeapon weapon = m.Weapon as BaseWeapon;
|
||||
|
||||
return (weapon != null && (weapon.PrimaryAbility == a || weapon.SecondaryAbility == a));
|
||||
}
|
||||
|
||||
public virtual bool ValidatesDuringHit
|
||||
{
|
||||
get
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static WeaponAbility GetCurrentAbility(Mobile m)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
WeaponAbility a = (WeaponAbility)m_Table[m];
|
||||
|
||||
if (!IsWeaponAbility(m, a))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (a != null && a.ValidatesDuringHit && !a.Validate(m))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return null;
|
||||
}
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static bool SetCurrentAbility(Mobile m, WeaponAbility a)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsWeaponAbility(m, a))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a != null && !a.Validate(m))
|
||||
{
|
||||
ClearCurrentAbility(m);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a == null)
|
||||
{
|
||||
m_Table.Remove(m);
|
||||
}
|
||||
else
|
||||
{
|
||||
SpecialMove.ClearCurrentMove(m);
|
||||
|
||||
m_Table[m] = a;
|
||||
|
||||
SkillMasterySpell.CancelWeaponAbility(m);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void ClearCurrentAbility(Mobile m)
|
||||
{
|
||||
m_Table.Remove(m);
|
||||
|
||||
if (Core.AOS && m.NetState != null)
|
||||
m.Send(ClearWeaponAbility.Instance);
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.SetAbility += new SetAbilityEventHandler(EventSink_SetAbility);
|
||||
}
|
||||
|
||||
public WeaponAbility()
|
||||
{
|
||||
}
|
||||
|
||||
private static void EventSink_SetAbility(SetAbilityEventArgs e)
|
||||
{
|
||||
int index = e.Index;
|
||||
|
||||
if (index == 0)
|
||||
ClearCurrentAbility(e.Mobile);
|
||||
else if (index >= 1 && index < m_Abilities.Length)
|
||||
SetCurrentAbility(e.Mobile, m_Abilities[index]);
|
||||
}
|
||||
|
||||
private static readonly Hashtable m_PlayersTable = new Hashtable();
|
||||
|
||||
private static void AddContext(Mobile m, WeaponAbilityContext context)
|
||||
{
|
||||
m_PlayersTable[m] = context;
|
||||
}
|
||||
|
||||
private static void RemoveContext(Mobile m)
|
||||
{
|
||||
WeaponAbilityContext context = GetContext(m);
|
||||
|
||||
if (context != null)
|
||||
RemoveContext(m, context);
|
||||
}
|
||||
|
||||
private static void RemoveContext(Mobile m, WeaponAbilityContext context)
|
||||
{
|
||||
m_PlayersTable.Remove(m);
|
||||
|
||||
context.Timer.Stop();
|
||||
}
|
||||
|
||||
private static WeaponAbilityContext GetContext(Mobile m)
|
||||
{
|
||||
return (m_PlayersTable[m] as WeaponAbilityContext);
|
||||
}
|
||||
|
||||
private class WeaponAbilityTimer : Timer
|
||||
{
|
||||
private readonly Mobile m_Mobile;
|
||||
|
||||
public WeaponAbilityTimer(Mobile from)
|
||||
: base(TimeSpan.FromSeconds(3.0))
|
||||
{
|
||||
m_Mobile = from;
|
||||
|
||||
Priority = TimerPriority.TwentyFiveMS;
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
RemoveContext(m_Mobile);
|
||||
}
|
||||
}
|
||||
|
||||
private class WeaponAbilityContext
|
||||
{
|
||||
private readonly Timer m_Timer;
|
||||
|
||||
public Timer Timer
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Timer;
|
||||
}
|
||||
}
|
||||
|
||||
public WeaponAbilityContext(Timer timer)
|
||||
{
|
||||
m_Timer = timer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
89
Scripts/Abilities/WhirlwindAttack.cs
Normal file
89
Scripts/Abilities/WhirlwindAttack.cs
Normal file
@@ -0,0 +1,89 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Spells;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
/// <summary>
|
||||
/// A godsend to a warrior surrounded, the Whirlwind Attack allows the fighter to strike at all nearby targets in one mighty spinning swing.
|
||||
/// </summary>
|
||||
public class WhirlwindAttack : WeaponAbility
|
||||
{
|
||||
public WhirlwindAttack()
|
||||
{
|
||||
}
|
||||
|
||||
public override int BaseMana
|
||||
{
|
||||
get
|
||||
{
|
||||
return 15;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool OnBeforeDamage(Mobile attacker, Mobile defender)
|
||||
{
|
||||
BaseWeapon wep = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (wep != null)
|
||||
wep.ProcessingMultipleHits = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override void OnHit(Mobile attacker, Mobile defender, int damage)
|
||||
{
|
||||
if (!this.Validate(attacker))
|
||||
return;
|
||||
|
||||
ClearCurrentAbility(attacker);
|
||||
|
||||
Map map = attacker.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
BaseWeapon weapon = attacker.Weapon as BaseWeapon;
|
||||
|
||||
if (weapon == null)
|
||||
return;
|
||||
|
||||
if (!this.CheckMana(attacker, true))
|
||||
return;
|
||||
|
||||
attacker.FixedEffect(0x3728, 10, 15);
|
||||
attacker.PlaySound(0x2A1);
|
||||
|
||||
var list = SpellHelper.AcquireIndirectTargets(attacker, attacker, attacker.Map, 1)
|
||||
.OfType<Mobile>()
|
||||
.Where(m => attacker.InRange(m, weapon.MaxRange) && m != defender).ToList();
|
||||
|
||||
int count = list.Count;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
double bushido = attacker.Skills.Bushido.Value;
|
||||
double damageBonus = 1.0 + Math.Pow((count * bushido) / 60, 2) / 100;
|
||||
|
||||
if (damageBonus > 2.0)
|
||||
damageBonus = 2.0;
|
||||
|
||||
attacker.RevealingAction();
|
||||
|
||||
foreach(var m in list)
|
||||
{
|
||||
attacker.SendLocalizedMessage(1060161); // The whirling attack strikes a target!
|
||||
m.SendLocalizedMessage(1060162); // You are struck by the whirling attack and take damage!
|
||||
|
||||
weapon.OnHit(attacker, m, damageBonus);
|
||||
}
|
||||
}
|
||||
|
||||
ColUtility.Free(list);
|
||||
|
||||
weapon.ProcessingMultipleHits = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Scripts/Accounting/AccessRestrictions.cs
Normal file
48
Scripts/Accounting/AccessRestrictions.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Server.Misc;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class AccessRestrictions
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.SocketConnect += new SocketConnectEventHandler(EventSink_SocketConnect);
|
||||
}
|
||||
|
||||
private static void EventSink_SocketConnect(SocketConnectEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
IPAddress ip = ((IPEndPoint)e.Socket.RemoteEndPoint).Address;
|
||||
|
||||
if (Firewall.IsBlocked(ip))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Client: {0}: Firewall blocked connection attempt.", ip);
|
||||
Utility.PopColor();
|
||||
e.AllowConnection = false;
|
||||
return;
|
||||
}
|
||||
else if (IPLimiter.SocketBlock && !IPLimiter.Verify(ip))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Client: {0}: Past IP limit threshold", ip);
|
||||
Utility.PopColor();
|
||||
|
||||
using (StreamWriter op = new StreamWriter("ipLimits.log", true))
|
||||
op.WriteLine("{0}\tPast IP limit threshold\t{1}", ip, DateTime.UtcNow);
|
||||
|
||||
e.AllowConnection = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
e.AllowConnection = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1957
Scripts/Accounting/Account.cs
Normal file
1957
Scripts/Accounting/Account.cs
Normal file
File diff suppressed because it is too large
Load Diff
164
Scripts/Accounting/AccountAttackLimiter.cs
Normal file
164
Scripts/Accounting/AccountAttackLimiter.cs
Normal file
@@ -0,0 +1,164 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public class AccountAttackLimiter
|
||||
{
|
||||
public static bool Enabled = true;
|
||||
private static readonly List<InvalidAccountAccessLog> m_List = new List<InvalidAccountAccessLog>();
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
PacketHandlers.RegisterThrottler(0x80, new ThrottlePacketCallback(Throttle_Callback));
|
||||
PacketHandlers.RegisterThrottler(0x91, new ThrottlePacketCallback(Throttle_Callback));
|
||||
PacketHandlers.RegisterThrottler(0xCF, new ThrottlePacketCallback(Throttle_Callback));
|
||||
}
|
||||
|
||||
public static bool Throttle_Callback(byte packetID, NetState ns, out bool drop)
|
||||
{
|
||||
drop = false;
|
||||
|
||||
InvalidAccountAccessLog accessLog = FindAccessLog(ns);
|
||||
|
||||
if (accessLog == null)
|
||||
return true;
|
||||
|
||||
return (DateTime.UtcNow >= (accessLog.LastAccessTime + ComputeThrottle(accessLog.Counts)));
|
||||
}
|
||||
|
||||
public static InvalidAccountAccessLog FindAccessLog(NetState ns)
|
||||
{
|
||||
if (ns == null)
|
||||
return null;
|
||||
|
||||
IPAddress ipAddress = ns.Address;
|
||||
|
||||
for (int i = 0; i < m_List.Count; ++i)
|
||||
{
|
||||
InvalidAccountAccessLog accessLog = m_List[i];
|
||||
|
||||
if (accessLog.HasExpired)
|
||||
m_List.RemoveAt(i--);
|
||||
else if (accessLog.Address.Equals(ipAddress))
|
||||
return accessLog;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void RegisterInvalidAccess(NetState ns)
|
||||
{
|
||||
if (ns == null || !Enabled)
|
||||
return;
|
||||
|
||||
InvalidAccountAccessLog accessLog = FindAccessLog(ns);
|
||||
|
||||
if (accessLog == null)
|
||||
m_List.Add(accessLog = new InvalidAccountAccessLog(ns.Address));
|
||||
|
||||
accessLog.Counts += 1;
|
||||
accessLog.RefreshAccessTime();
|
||||
|
||||
if (accessLog.Counts >= 3)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("throttle.log", true))
|
||||
{
|
||||
op.WriteLine(
|
||||
"{0}\t{1}\t{2}",
|
||||
DateTime.UtcNow,
|
||||
ns,
|
||||
accessLog.Counts);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSpan ComputeThrottle(int counts)
|
||||
{
|
||||
if (counts >= 15)
|
||||
return TimeSpan.FromMinutes(5.0);
|
||||
|
||||
if (counts >= 10)
|
||||
return TimeSpan.FromMinutes(1.0);
|
||||
|
||||
if (counts >= 5)
|
||||
return TimeSpan.FromSeconds(20.0);
|
||||
|
||||
if (counts >= 3)
|
||||
return TimeSpan.FromSeconds(10.0);
|
||||
|
||||
if (counts >= 1)
|
||||
return TimeSpan.FromSeconds(2.0);
|
||||
|
||||
return TimeSpan.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public class InvalidAccountAccessLog
|
||||
{
|
||||
private IPAddress m_Address;
|
||||
private DateTime m_LastAccessTime;
|
||||
private int m_Counts;
|
||||
public InvalidAccountAccessLog(IPAddress address)
|
||||
{
|
||||
this.m_Address = address;
|
||||
this.RefreshAccessTime();
|
||||
}
|
||||
|
||||
public IPAddress Address
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Address;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Address = value;
|
||||
}
|
||||
}
|
||||
public DateTime LastAccessTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_LastAccessTime;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_LastAccessTime = value;
|
||||
}
|
||||
}
|
||||
public bool HasExpired
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DateTime.UtcNow >= (this.m_LastAccessTime + TimeSpan.FromHours(1.0)));
|
||||
}
|
||||
}
|
||||
public int Counts
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Counts;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Counts = value;
|
||||
}
|
||||
}
|
||||
public void RefreshAccessTime()
|
||||
{
|
||||
this.m_LastAccessTime = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Scripts/Accounting/AccountComment.cs
Normal file
86
Scripts/Accounting/AccountComment.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public class AccountComment
|
||||
{
|
||||
private readonly string m_AddedBy;
|
||||
private string m_Content;
|
||||
private DateTime m_LastModified;
|
||||
/// <summary>
|
||||
/// Constructs a new AccountComment instance.
|
||||
/// </summary>
|
||||
/// <param name="addedBy">Initial AddedBy value.</param>
|
||||
/// <param name="content">Initial Content value.</param>
|
||||
public AccountComment(string addedBy, string content)
|
||||
{
|
||||
this.m_AddedBy = addedBy;
|
||||
this.m_Content = content;
|
||||
this.m_LastModified = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an AccountComment instance from an xml element.
|
||||
/// </summary>
|
||||
/// <param name="node">The XmlElement instance from which to deserialize.</param>
|
||||
public AccountComment(XmlElement node)
|
||||
{
|
||||
this.m_AddedBy = Utility.GetAttribute(node, "addedBy", "empty");
|
||||
this.m_LastModified = Utility.GetXMLDateTime(Utility.GetAttribute(node, "lastModified"), DateTime.UtcNow);
|
||||
this.m_Content = Utility.GetText(node, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A string representing who added this comment.
|
||||
/// </summary>
|
||||
public string AddedBy
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_AddedBy;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the body of this comment. Setting this value will reset LastModified.
|
||||
/// </summary>
|
||||
public string Content
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Content;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Content = value;
|
||||
this.m_LastModified = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// The date and time when this account was last modified -or- the comment creation time, if never modified.
|
||||
/// </summary>
|
||||
public DateTime LastModified
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_LastModified;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Serializes this AccountComment instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
|
||||
public void Save(XmlTextWriter xml)
|
||||
{
|
||||
xml.WriteStartElement("comment");
|
||||
|
||||
xml.WriteAttributeString("addedBy", this.m_AddedBy);
|
||||
|
||||
xml.WriteAttributeString("lastModified", XmlConvert.ToString(this.m_LastModified, XmlDateTimeSerializationMode.Utc));
|
||||
|
||||
xml.WriteString(this.m_Content);
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
527
Scripts/Accounting/AccountHandler.cs
Normal file
527
Scripts/Accounting/AccountHandler.cs
Normal file
@@ -0,0 +1,527 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using Server.Accounting;
|
||||
using Server.Commands;
|
||||
using Server.Engines.Help;
|
||||
using Server.Network;
|
||||
using Server.Regions;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
public enum PasswordProtection
|
||||
{
|
||||
None,
|
||||
Crypt,
|
||||
NewCrypt,
|
||||
NewSecureCrypt
|
||||
}
|
||||
|
||||
public class AccountHandler
|
||||
{
|
||||
public static PasswordProtection ProtectPasswords = Config.GetEnum(
|
||||
"Accounts.ProtectPasswords",
|
||||
PasswordProtection.NewSecureCrypt);
|
||||
|
||||
private static readonly int MaxAccountsPerIP = Config.Get("Accounts.AccountsPerIp", 1);
|
||||
private static readonly bool AutoAccountCreation = Config.Get("Accounts.AutoCreateAccounts", true);
|
||||
private static readonly bool RestrictDeletion = Config.Get("Accounts.RestrictDeletion", !TestCenter.Enabled);
|
||||
private static readonly TimeSpan DeleteDelay = Config.Get("Accounts.DeleteDelay", TimeSpan.FromDays(7.0));
|
||||
|
||||
private static readonly CityInfo[] StartingCitiesT2A = new CityInfo[]
|
||||
{
|
||||
new CityInfo("New Haven", "New Haven Bank", 1150168, 3503, 2574, 14, Map.Felucca),
|
||||
new CityInfo("Yew", "The Empath Abbey", 1075072, 633, 858, 0, Map.Felucca),
|
||||
new CityInfo("Minoc", "The Barnacle", 1075073, 2476, 413, 15, Map.Felucca),
|
||||
new CityInfo("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20, Map.Felucca),
|
||||
new CityInfo("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0, Map.Felucca),
|
||||
new CityInfo("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0, Map.Felucca),
|
||||
new CityInfo("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0, Map.Felucca),
|
||||
new CityInfo("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0, Map.Felucca),
|
||||
new CityInfo("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0, Map.Felucca)
|
||||
};
|
||||
|
||||
private static readonly CityInfo[] StartingCities = new CityInfo[]
|
||||
{
|
||||
new CityInfo("New Haven", "New Haven Bank", 1150168, 3503, 2574, 14),
|
||||
new CityInfo("Yew", "The Empath Abbey", 1075072, 633, 858, 0),
|
||||
new CityInfo("Minoc", "The Barnacle", 1075073, 2476, 413, 15),
|
||||
new CityInfo("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20),
|
||||
new CityInfo("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0),
|
||||
new CityInfo("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0),
|
||||
new CityInfo("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0),
|
||||
new CityInfo("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0),
|
||||
new CityInfo("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0)
|
||||
};
|
||||
|
||||
private static readonly CityInfo[] StartingCitiesSA = new CityInfo[]
|
||||
{
|
||||
new CityInfo("New Haven", "New Haven Bank", 1150168, 3503, 2574, 14),
|
||||
new CityInfo("Yew", "The Empath Abbey", 1075072, 633, 858, 0),
|
||||
new CityInfo("Minoc", "The Barnacle", 1075073, 2476, 413, 15),
|
||||
new CityInfo("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20),
|
||||
new CityInfo("Moonglow", "The Scholars Inn", 1075075, 4408, 1168, 0),
|
||||
new CityInfo("Trinsic", "The Traveler's Inn", 1075076, 1845, 2745, 0),
|
||||
new CityInfo("Jhelom", "The Mercenary Inn", 1075078, 1374, 3826, 0),
|
||||
new CityInfo("Skara Brae", "The Falconer's Inn", 1075079, 618, 2234, 0),
|
||||
new CityInfo("Vesper", "The Ironwood Inn", 1075080, 2771, 976, 0),
|
||||
new CityInfo("Royal City", "Royal City Inn", 1150169, 738, 3486, -19, Map.TerMur)
|
||||
};
|
||||
|
||||
private static readonly CityInfo[] SiegeStartingCities = new CityInfo[]
|
||||
{
|
||||
new CityInfo("Britain", "The Wayfarer's Inn", 1075074, 1602, 1591, 20, Map.Felucca),
|
||||
new CityInfo("Royal City", "Royal City Inn", 1150169, 738, 3486, -19, Map.TerMur)
|
||||
};
|
||||
|
||||
/* Old Haven/Magincia Locations
|
||||
new CityInfo( "Britain", "Sweet Dreams Inn", 1496, 1628, 10 );
|
||||
// ..
|
||||
// Trinsic
|
||||
new CityInfo( "Magincia", "The Great Horns Tavern", 3734, 2222, 20 ),
|
||||
// Jhelom
|
||||
// ..
|
||||
new CityInfo( "Haven", "Buckler's Hideaway", 3667, 2625, 0 )
|
||||
|
||||
if ( Core.AOS )
|
||||
{
|
||||
//CityInfo haven = new CityInfo( "Haven", "Uzeraan's Mansion", 3618, 2591, 0 );
|
||||
CityInfo haven = new CityInfo( "Haven", "Uzeraan's Mansion", 3503, 2574, 14 );
|
||||
StartingCities[StartingCities.Length - 1] = haven;
|
||||
}
|
||||
*/
|
||||
|
||||
private static readonly bool PasswordCommandEnabled = Config.Get("Accounts.PasswordCommandEnabled", false);
|
||||
|
||||
private static readonly char[] m_ForbiddenChars = new char[]
|
||||
{
|
||||
'<', '>', ':', '"', '/', '\\', '|', '?', '*', ' '
|
||||
};
|
||||
|
||||
private static AccessLevel m_LockdownLevel;
|
||||
private static Dictionary<IPAddress, Int32> m_IPTable;
|
||||
|
||||
public static AccessLevel LockdownLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_LockdownLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_LockdownLevel = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<IPAddress, Int32> IPTable
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_IPTable == null)
|
||||
{
|
||||
m_IPTable = new Dictionary<IPAddress, Int32>();
|
||||
|
||||
foreach (var a in Accounts.GetAccounts().OfType<Account>())
|
||||
{
|
||||
if (a.LoginIPs.Length > 0)
|
||||
{
|
||||
IPAddress ip = a.LoginIPs[0];
|
||||
|
||||
if (m_IPTable.ContainsKey(ip))
|
||||
m_IPTable[ip]++;
|
||||
else
|
||||
m_IPTable[ip] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_IPTable;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
EventSink.DeleteRequest += new DeleteRequestEventHandler(EventSink_DeleteRequest);
|
||||
EventSink.AccountLogin += new AccountLoginEventHandler(EventSink_AccountLogin);
|
||||
EventSink.GameLogin += new GameLoginEventHandler(EventSink_GameLogin);
|
||||
|
||||
if (PasswordCommandEnabled)
|
||||
CommandSystem.Register("Password", AccessLevel.Player, new CommandEventHandler(Password_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("Password <newPassword> <repeatPassword>")]
|
||||
[Description("Changes the password of the commanding players account. Requires the same C-class IP address as the account's creator.")]
|
||||
public static void Password_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
Mobile from = e.Mobile;
|
||||
Account acct = from.Account as Account;
|
||||
|
||||
if (acct == null)
|
||||
return;
|
||||
|
||||
IPAddress[] accessList = acct.LoginIPs;
|
||||
|
||||
if (accessList.Length == 0)
|
||||
return;
|
||||
|
||||
NetState ns = from.NetState;
|
||||
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
if (e.Length == 0)
|
||||
{
|
||||
from.SendMessage("You must specify the new password.");
|
||||
return;
|
||||
}
|
||||
else if (e.Length == 1)
|
||||
{
|
||||
from.SendMessage("To prevent potential typing mistakes, you must type the password twice. Use the format:");
|
||||
from.SendMessage("Password \"(newPassword)\" \"(repeated)\"");
|
||||
return;
|
||||
}
|
||||
|
||||
string pass = e.GetString(0);
|
||||
string pass2 = e.GetString(1);
|
||||
|
||||
if (pass != pass2)
|
||||
{
|
||||
from.SendMessage("The passwords do not match.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool isSafe = true;
|
||||
|
||||
for (int i = 0; isSafe && i < pass.Length; ++i)
|
||||
isSafe = (pass[i] >= 0x20 && pass[i] < 0x7F);
|
||||
|
||||
if (!isSafe)
|
||||
{
|
||||
from.SendMessage("That is not a valid password.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
IPAddress ipAddress = ns.Address;
|
||||
|
||||
if (Utility.IPMatchClassC(accessList[0], ipAddress))
|
||||
{
|
||||
acct.SetPassword(pass);
|
||||
from.SendMessage("The password to your account has changed.");
|
||||
}
|
||||
else
|
||||
{
|
||||
PageEntry entry = PageQueue.GetEntry(from);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
if (entry.Message.StartsWith("[Automated: Change Password]"))
|
||||
from.SendMessage("You already have a password change request in the help system queue.");
|
||||
else
|
||||
from.SendMessage("Your IP address does not match that which created this account.");
|
||||
}
|
||||
else if (PageQueue.CheckAllowedToPage(from))
|
||||
{
|
||||
from.SendMessage("Your IP address does not match that which created this account. A page has been entered into the help system on your behalf.");
|
||||
|
||||
from.SendLocalizedMessage(501234, "", 0x35); /* The next available Counselor/Game Master will respond as soon as possible.
|
||||
* Please check your Journal for messages every few minutes.
|
||||
*/
|
||||
|
||||
PageQueue.Enqueue(new PageEntry(from, String.Format("[Automated: Change Password]<br>Desired password: {0}<br>Current IP address: {1}<br>Account IP address: {2}", pass, ipAddress, accessList[0]), PageType.Account));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public static bool CanCreate(IPAddress ip)
|
||||
{
|
||||
if (!IPTable.ContainsKey(ip) || IPLimiter.IsExempt(ip))
|
||||
return true;
|
||||
|
||||
return (IPTable[ip] < MaxAccountsPerIP);
|
||||
}
|
||||
|
||||
public static void EventSink_AccountLogin(AccountLoginEventArgs e)
|
||||
{
|
||||
// If the login attempt has already been rejected by another event handler
|
||||
// then just return
|
||||
if (e.Accepted == false)
|
||||
return;
|
||||
|
||||
if (!IPLimiter.SocketBlock && !IPLimiter.Verify(e.State.Address))
|
||||
{
|
||||
e.Accepted = false;
|
||||
e.RejectReason = ALRReason.InUse;
|
||||
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Past IP limit threshold", e.State);
|
||||
Utility.PopColor();
|
||||
|
||||
using (StreamWriter op = new StreamWriter("ipLimits.log", true))
|
||||
op.WriteLine("{0}\tPast IP limit threshold\t{1}", e.State, DateTime.UtcNow);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string un = e.Username;
|
||||
string pw = e.Password;
|
||||
|
||||
e.Accepted = false;
|
||||
Account acct = Accounts.GetAccount(un) as Account;
|
||||
|
||||
if (acct == null)
|
||||
{
|
||||
if (AutoAccountCreation && un.Trim().Length > 0) // To prevent someone from making an account of just '' or a bunch of meaningless spaces
|
||||
{
|
||||
e.State.Account = acct = CreateAccount(e.State, un, pw);
|
||||
e.Accepted = acct == null ? false : acct.CheckAccess(e.State);
|
||||
|
||||
if (!e.Accepted)
|
||||
e.RejectReason = ALRReason.BadComm;
|
||||
}
|
||||
else
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Invalid username '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.RejectReason = ALRReason.Invalid;
|
||||
}
|
||||
}
|
||||
else if (!acct.HasAccess(e.State))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Access denied for '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.RejectReason = (m_LockdownLevel > AccessLevel.VIP ? ALRReason.BadComm : ALRReason.BadPass);
|
||||
}
|
||||
else if (!acct.CheckPassword(pw))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Invalid password for '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.RejectReason = ALRReason.BadPass;
|
||||
}
|
||||
else if (acct.Banned)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Banned account '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.RejectReason = ALRReason.Blocked;
|
||||
}
|
||||
else
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Green);
|
||||
Console.WriteLine("Login: {0}: Valid credentials for '{1}'", e.State, un);
|
||||
Console.WriteLine("Client Type: {0}: {1}", e.State, e.State.IsEnhancedClient ? "Enhanced Client" : "Classic Client");
|
||||
Utility.PopColor();
|
||||
e.State.Account = acct;
|
||||
e.Accepted = true;
|
||||
|
||||
acct.LogAccess(e.State);
|
||||
}
|
||||
|
||||
if (!e.Accepted)
|
||||
AccountAttackLimiter.RegisterInvalidAccess(e.State);
|
||||
}
|
||||
|
||||
public static void EventSink_GameLogin(GameLoginEventArgs e)
|
||||
{
|
||||
if (!IPLimiter.SocketBlock && !IPLimiter.Verify(e.State.Address))
|
||||
{
|
||||
e.Accepted = false;
|
||||
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Past IP limit threshold", e.State);
|
||||
Utility.PopColor();
|
||||
|
||||
using (StreamWriter op = new StreamWriter("ipLimits.log", true))
|
||||
op.WriteLine("{0}\tPast IP limit threshold\t{1}", e.State, DateTime.UtcNow);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
string un = e.Username;
|
||||
string pw = e.Password;
|
||||
|
||||
Account acct = Accounts.GetAccount(un) as Account;
|
||||
|
||||
if (acct == null)
|
||||
{
|
||||
e.Accepted = false;
|
||||
}
|
||||
else if (!acct.HasAccess(e.State))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Access denied for '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.Accepted = false;
|
||||
}
|
||||
else if (!acct.CheckPassword(pw))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Invalid password for '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.Accepted = false;
|
||||
}
|
||||
else if (acct.Banned)
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Login: {0}: Banned account '{1}'", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.Accepted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
acct.LogAccess(e.State);
|
||||
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
Console.WriteLine("Login: {0}: Account '{1}' at character list", e.State, un);
|
||||
Utility.PopColor();
|
||||
e.State.Account = acct;
|
||||
e.Accepted = true;
|
||||
|
||||
if(Siege.SiegeShard)
|
||||
{
|
||||
e.CityInfo = SiegeStartingCities;
|
||||
}
|
||||
else if (!Core.UOR)
|
||||
{
|
||||
e.CityInfo = StartingCitiesT2A;
|
||||
}
|
||||
else if (!Core.SA)
|
||||
{
|
||||
e.CityInfo = StartingCities;
|
||||
}
|
||||
else
|
||||
{
|
||||
e.CityInfo = StartingCitiesSA;
|
||||
}
|
||||
}
|
||||
|
||||
if (!e.Accepted)
|
||||
AccountAttackLimiter.RegisterInvalidAccess(e.State);
|
||||
}
|
||||
|
||||
public static bool CheckAccount(Mobile mobCheck, Mobile accCheck)
|
||||
{
|
||||
if (accCheck != null)
|
||||
{
|
||||
Account a = accCheck.Account as Account;
|
||||
|
||||
if (a != null)
|
||||
{
|
||||
for (int i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (a[i] == mobCheck)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void EventSink_DeleteRequest(DeleteRequestEventArgs e)
|
||||
{
|
||||
NetState state = e.State;
|
||||
int index = e.Index;
|
||||
|
||||
Account acct = state.Account as Account;
|
||||
|
||||
if (acct == null)
|
||||
{
|
||||
state.Dispose();
|
||||
}
|
||||
else if (index < 0 || index >= acct.Length)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.BadRequest));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
else
|
||||
{
|
||||
Mobile m = acct[index];
|
||||
|
||||
if (m == null)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharNotExist));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
else if (m.NetState != null)
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharBeingPlayed));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
else if (RestrictDeletion && DateTime.UtcNow < (m.CreationTime + DeleteDelay))
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.CharTooYoung));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
else if (m.IsPlayer() && Region.Find(m.LogoutLocation, m.LogoutMap).GetRegion(typeof(Jail)) != null) //Don't need to check current location, if netstate is null, they're logged out
|
||||
{
|
||||
state.Send(new DeleteResult(DeleteResultType.BadRequest));
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
else
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Client: {0}: Deleting character {1} (0x{2:X})", state, index, m.Serial.Value);
|
||||
Utility.PopColor();
|
||||
|
||||
acct.Comments.Add(new AccountComment("System", String.Format("Character #{0} {1} deleted by {2}", index + 1, m, state)));
|
||||
|
||||
m.Delete();
|
||||
state.Send(new CharacterListUpdate(acct));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsForbiddenChar(char c)
|
||||
{
|
||||
for (int i = 0; i < m_ForbiddenChars.Length; ++i)
|
||||
if (c == m_ForbiddenChars[i])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static Account CreateAccount(NetState state, string un, string pw)
|
||||
{
|
||||
if (un.Length == 0 || pw.Length == 0)
|
||||
return null;
|
||||
|
||||
bool isSafe = !(un.StartsWith(" ") || un.EndsWith(" ") || un.EndsWith("."));
|
||||
|
||||
for (int i = 0; isSafe && i < un.Length; ++i)
|
||||
isSafe = (un[i] >= 0x20 && un[i] < 0x7F && !IsForbiddenChar(un[i]));
|
||||
|
||||
for (int i = 0; isSafe && i < pw.Length; ++i)
|
||||
isSafe = (pw[i] >= 0x20 && pw[i] < 0x7F);
|
||||
|
||||
if (!isSafe)
|
||||
return null;
|
||||
|
||||
if (!CanCreate(state.Address))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.DarkYellow);
|
||||
Console.WriteLine("Login: {0}: Account '{1}' not created, ip already has {2} account{3}.", state, un, MaxAccountsPerIP, MaxAccountsPerIP == 1 ? "" : "s");
|
||||
Utility.PopColor();
|
||||
return null;
|
||||
}
|
||||
|
||||
Utility.PushColor(ConsoleColor.Green);
|
||||
Console.WriteLine("Login: {0}: Creating new account '{1}'", state, un);
|
||||
Utility.PopColor();
|
||||
|
||||
Account a = new Account(un, pw);
|
||||
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Scripts/Accounting/AccountTag.cs
Normal file
70
Scripts/Accounting/AccountTag.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public class AccountTag
|
||||
{
|
||||
private string m_Name, m_Value;
|
||||
/// <summary>
|
||||
/// Constructs a new AccountTag instance with a specific name and value.
|
||||
/// </summary>
|
||||
/// <param name="name">Initial name.</param>
|
||||
/// <param name="value">Initial value.</param>
|
||||
public AccountTag(string name, string value)
|
||||
{
|
||||
this.m_Name = name;
|
||||
this.m_Value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes an AccountTag instance from an xml element.
|
||||
/// </summary>
|
||||
/// <param name="node">The XmlElement instance from which to deserialize.</param>
|
||||
public AccountTag(XmlElement node)
|
||||
{
|
||||
this.m_Name = Utility.GetAttribute(node, "name", "empty");
|
||||
this.m_Value = Utility.GetText(node, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of this tag.
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Name;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Name = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the value of this tag.
|
||||
/// </summary>
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Value = value;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Serializes this AccountTag instance to an XmlTextWriter.
|
||||
/// </summary>
|
||||
/// <param name="xml">The XmlTextWriter instance from which to serialize.</param>
|
||||
public void Save(XmlTextWriter xml)
|
||||
{
|
||||
xml.WriteStartElement("tag");
|
||||
xml.WriteAttributeString("name", this.m_Name);
|
||||
xml.WriteString(this.m_Value);
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Scripts/Accounting/Accounts.cs
Normal file
111
Scripts/Accounting/Accounts.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public class Accounts
|
||||
{
|
||||
private static Dictionary<string, IAccount> m_Accounts = new Dictionary<string, IAccount>();
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
EventSink.WorldLoad += new WorldLoadEventHandler(Load);
|
||||
EventSink.WorldSave += new WorldSaveEventHandler(Save);
|
||||
}
|
||||
|
||||
static Accounts()
|
||||
{
|
||||
}
|
||||
|
||||
public static int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Accounts.Count;
|
||||
}
|
||||
}
|
||||
|
||||
public static ICollection<IAccount> GetAccounts()
|
||||
{
|
||||
return m_Accounts.Values;
|
||||
}
|
||||
|
||||
public static IAccount GetAccount(string username)
|
||||
{
|
||||
IAccount a;
|
||||
|
||||
m_Accounts.TryGetValue(username, out a);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
public static void Add(IAccount a)
|
||||
{
|
||||
m_Accounts[a.Username] = a;
|
||||
}
|
||||
|
||||
public static void Remove(string username)
|
||||
{
|
||||
m_Accounts.Remove(username);
|
||||
}
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
m_Accounts = new Dictionary<string, IAccount>(32, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
string filePath = Path.Combine("Saves/Accounts", "accounts.xml");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return;
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(filePath);
|
||||
|
||||
XmlElement root = doc["accounts"];
|
||||
|
||||
foreach (XmlElement account in root.GetElementsByTagName("account"))
|
||||
{
|
||||
try
|
||||
{
|
||||
Account acct = new Account(account);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Warning: Account instance load failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Save(WorldSaveEventArgs e)
|
||||
{
|
||||
if (!Directory.Exists("Saves/Accounts"))
|
||||
Directory.CreateDirectory("Saves/Accounts");
|
||||
|
||||
string filePath = Path.Combine("Saves/Accounts", "accounts.xml");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
XmlTextWriter xml = new XmlTextWriter(op);
|
||||
|
||||
xml.Formatting = Formatting.Indented;
|
||||
xml.IndentChar = '\t';
|
||||
xml.Indentation = 1;
|
||||
|
||||
xml.WriteStartDocument(true);
|
||||
|
||||
xml.WriteStartElement("accounts");
|
||||
|
||||
xml.WriteAttributeString("count", m_Accounts.Count.ToString());
|
||||
|
||||
foreach (Account a in GetAccounts())
|
||||
a.Save(xml);
|
||||
|
||||
xml.WriteEndElement();
|
||||
|
||||
xml.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
335
Scripts/Accounting/Firewall.cs
Normal file
335
Scripts/Accounting/Firewall.cs
Normal file
@@ -0,0 +1,335 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class Firewall
|
||||
{
|
||||
#region Firewall Entries
|
||||
public interface IFirewallEntry
|
||||
{
|
||||
bool IsBlocked(IPAddress address);
|
||||
}
|
||||
|
||||
public class IPFirewallEntry : IFirewallEntry
|
||||
{
|
||||
readonly IPAddress m_Address;
|
||||
public IPFirewallEntry(IPAddress address)
|
||||
{
|
||||
this.m_Address = address;
|
||||
}
|
||||
|
||||
public bool IsBlocked(IPAddress address)
|
||||
{
|
||||
return this.m_Address.Equals(address);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.m_Address.ToString();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is IPAddress)
|
||||
{
|
||||
return obj.Equals(this.m_Address);
|
||||
}
|
||||
else if (obj is string)
|
||||
{
|
||||
IPAddress otherAddress;
|
||||
|
||||
if (IPAddress.TryParse((string)obj, out otherAddress))
|
||||
return otherAddress.Equals(this.m_Address);
|
||||
}
|
||||
else if (obj is IPFirewallEntry)
|
||||
{
|
||||
return this.m_Address.Equals(((IPFirewallEntry)obj).m_Address);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.m_Address.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class CIDRFirewallEntry : IFirewallEntry
|
||||
{
|
||||
readonly IPAddress m_CIDRPrefix;
|
||||
readonly int m_CIDRLength;
|
||||
|
||||
public CIDRFirewallEntry(IPAddress cidrPrefix, int cidrLength)
|
||||
{
|
||||
this.m_CIDRPrefix = cidrPrefix;
|
||||
this.m_CIDRLength = cidrLength;
|
||||
}
|
||||
|
||||
public bool IsBlocked(IPAddress address)
|
||||
{
|
||||
return Utility.IPMatchCIDR(this.m_CIDRPrefix, address, this.m_CIDRLength);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Format("{0}/{1}", this.m_CIDRPrefix, this.m_CIDRLength);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is string)
|
||||
{
|
||||
string entry = (string)obj;
|
||||
|
||||
string[] str = entry.Split('/');
|
||||
|
||||
if (str.Length == 2)
|
||||
{
|
||||
IPAddress cidrPrefix;
|
||||
|
||||
if (IPAddress.TryParse(str[0], out cidrPrefix))
|
||||
{
|
||||
int cidrLength;
|
||||
|
||||
if (int.TryParse(str[1], out cidrLength))
|
||||
return this.m_CIDRPrefix.Equals(cidrPrefix) && this.m_CIDRLength.Equals(cidrLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (obj is CIDRFirewallEntry)
|
||||
{
|
||||
CIDRFirewallEntry entry = obj as CIDRFirewallEntry;
|
||||
|
||||
return this.m_CIDRPrefix.Equals(entry.m_CIDRPrefix) && this.m_CIDRLength.Equals(entry.m_CIDRLength);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.m_CIDRPrefix.GetHashCode() ^ this.m_CIDRLength.GetHashCode();
|
||||
}
|
||||
}
|
||||
|
||||
public class WildcardIPFirewallEntry : IFirewallEntry
|
||||
{
|
||||
readonly string m_Entry;
|
||||
|
||||
bool m_Valid = true;
|
||||
|
||||
public WildcardIPFirewallEntry(string entry)
|
||||
{
|
||||
this.m_Entry = entry;
|
||||
}
|
||||
|
||||
public bool IsBlocked(IPAddress address)
|
||||
{
|
||||
if (!this.m_Valid)
|
||||
return false; //Why process if it's invalid? it'll return false anyway after processing it.
|
||||
|
||||
return Utility.IPMatch(this.m_Entry, address, ref this.m_Valid);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return this.m_Entry.ToString();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is string)
|
||||
return obj.Equals(this.m_Entry);
|
||||
else if (obj is WildcardIPFirewallEntry)
|
||||
return this.m_Entry.Equals(((WildcardIPFirewallEntry)obj).m_Entry);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.m_Entry.GetHashCode();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static List<IFirewallEntry> m_Blocked;
|
||||
|
||||
static Firewall()
|
||||
{
|
||||
m_Blocked = new List<IFirewallEntry>();
|
||||
|
||||
string path = "firewall.cfg";
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using (StreamReader ip = new StreamReader(path))
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
{
|
||||
line = line.Trim();
|
||||
|
||||
if (line.Length == 0)
|
||||
continue;
|
||||
|
||||
m_Blocked.Add(ToFirewallEntry(line));
|
||||
/*
|
||||
object toAdd;
|
||||
IPAddress addr;
|
||||
if( IPAddress.TryParse( line, out addr ) )
|
||||
toAdd = addr;
|
||||
else
|
||||
toAdd = line;
|
||||
m_Blocked.Add( toAdd.ToString() );
|
||||
* */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<IFirewallEntry> List
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Blocked;
|
||||
}
|
||||
}
|
||||
|
||||
public static IFirewallEntry ToFirewallEntry(object entry)
|
||||
{
|
||||
if (entry is IFirewallEntry)
|
||||
return (IFirewallEntry)entry;
|
||||
else if (entry is IPAddress)
|
||||
return new IPFirewallEntry((IPAddress)entry);
|
||||
else if (entry is string)
|
||||
return ToFirewallEntry((string)entry);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static IFirewallEntry ToFirewallEntry(string entry)
|
||||
{
|
||||
IPAddress addr;
|
||||
|
||||
if (IPAddress.TryParse(entry, out addr))
|
||||
return new IPFirewallEntry(addr);
|
||||
|
||||
//Try CIDR parse
|
||||
string[] str = entry.Split('/');
|
||||
|
||||
if (str.Length == 2)
|
||||
{
|
||||
IPAddress cidrPrefix;
|
||||
|
||||
if (IPAddress.TryParse(str[0], out cidrPrefix))
|
||||
{
|
||||
int cidrLength;
|
||||
|
||||
if (int.TryParse(str[1], out cidrLength))
|
||||
return new CIDRFirewallEntry(cidrPrefix, cidrLength);
|
||||
}
|
||||
}
|
||||
|
||||
return new WildcardIPFirewallEntry(entry);
|
||||
}
|
||||
|
||||
public static void RemoveAt(int index)
|
||||
{
|
||||
m_Blocked.RemoveAt(index);
|
||||
Save();
|
||||
}
|
||||
|
||||
public static void Remove(object obj)
|
||||
{
|
||||
IFirewallEntry entry = ToFirewallEntry(obj);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
m_Blocked.Remove(entry);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Add(object obj)
|
||||
{
|
||||
if (obj is IPAddress)
|
||||
Add((IPAddress)obj);
|
||||
else if (obj is string)
|
||||
Add((string)obj);
|
||||
else if (obj is IFirewallEntry)
|
||||
Add((IFirewallEntry)obj);
|
||||
}
|
||||
|
||||
public static void Add(IFirewallEntry entry)
|
||||
{
|
||||
if (!m_Blocked.Contains(entry))
|
||||
m_Blocked.Add(entry);
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
public static void Add(string pattern)
|
||||
{
|
||||
IFirewallEntry entry = ToFirewallEntry(pattern);
|
||||
|
||||
if (!m_Blocked.Contains(entry))
|
||||
m_Blocked.Add(entry);
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
public static void Add(IPAddress ip)
|
||||
{
|
||||
IFirewallEntry entry = new IPFirewallEntry(ip);
|
||||
|
||||
if (!m_Blocked.Contains(entry))
|
||||
m_Blocked.Add(entry);
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
public static void Save()
|
||||
{
|
||||
string path = "firewall.cfg";
|
||||
|
||||
using (StreamWriter op = new StreamWriter(path))
|
||||
{
|
||||
for (int i = 0; i < m_Blocked.Count; ++i)
|
||||
op.WriteLine(m_Blocked[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsBlocked(IPAddress ip)
|
||||
{
|
||||
for (int i = 0; i < m_Blocked.Count; i++)
|
||||
{
|
||||
if (m_Blocked[i].IsBlocked(ip))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
/*
|
||||
bool contains = false;
|
||||
for ( int i = 0; !contains && i < m_Blocked.Count; ++i )
|
||||
{
|
||||
if ( m_Blocked[i] is IPAddress )
|
||||
contains = ip.Equals( m_Blocked[i] );
|
||||
else if ( m_Blocked[i] is String )
|
||||
{
|
||||
string s = (string)m_Blocked[i];
|
||||
contains = Utility.IPMatchCIDR( s, ip );
|
||||
if( !contains )
|
||||
contains = Utility.IPMatch( s, ip );
|
||||
}
|
||||
}
|
||||
return contains;
|
||||
* */
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Scripts/Accounting/IPLimiter.cs
Normal file
55
Scripts/Accounting/IPLimiter.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Misc
|
||||
{
|
||||
public class IPLimiter
|
||||
{
|
||||
public static bool Enabled = true;
|
||||
public static bool SocketBlock = true;// true to block at connection, false to block at login request
|
||||
public static int MaxAddresses = 10;
|
||||
|
||||
public static IPAddress[] Exemptions = new IPAddress[] //For hosting services where there are cases where IPs can be proxied
|
||||
{
|
||||
IPAddress.Parse( "127.0.0.1" ),
|
||||
};
|
||||
|
||||
public static bool IsExempt(IPAddress ip)
|
||||
{
|
||||
for (int i = 0; i < Exemptions.Length; i++)
|
||||
{
|
||||
if (ip.Equals(Exemptions[i]))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool Verify(IPAddress ourAddress)
|
||||
{
|
||||
if (!Enabled || IsExempt(ourAddress))
|
||||
return true;
|
||||
|
||||
List<NetState> netStates = NetState.Instances;
|
||||
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < netStates.Count; ++i)
|
||||
{
|
||||
NetState compState = netStates[i];
|
||||
|
||||
if (ourAddress.Equals(compState.Address))
|
||||
{
|
||||
++count;
|
||||
|
||||
if (count >= MaxAddresses)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
44
Scripts/Commands/AccountGoldCheck.cs
Normal file
44
Scripts/Commands/AccountGoldCheck.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Server;
|
||||
using Server.Mobiles;
|
||||
using Server.Commands;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Server.SkillHandlers;
|
||||
using Server.Accounting;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public static class AccountGoldCheck
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("CheckAccountGold", AccessLevel.Administrator, e =>
|
||||
{
|
||||
double currency = 0.0;
|
||||
|
||||
var table = new Dictionary<string, long>();
|
||||
|
||||
foreach (var account in Accounts.GetAccounts().OfType<Account>())
|
||||
{
|
||||
table[account.Username] = (long)(account.TotalCurrency * Account.CurrencyThreshold);
|
||||
currency += account.TotalCurrency;
|
||||
}
|
||||
|
||||
using (StreamWriter op = new StreamWriter("TotalAccountGold.txt", true))
|
||||
{
|
||||
foreach (var kvp in table.OrderBy(k => -k.Value))
|
||||
{
|
||||
op.WriteLine(
|
||||
String.Format("{0} currency: {1}", kvp.Key, kvp.Value.ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("en-US"))));
|
||||
}
|
||||
|
||||
op.WriteLine("");
|
||||
op.WriteLine("Total Accounts: {0}", table.Count);
|
||||
op.WriteLine("Total Shard Gold: {0}", (currency * Account.CurrencyThreshold).ToString("N0", System.Globalization.CultureInfo.GetCultureInfo("en-US")));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
724
Scripts/Commands/Add.cs
Normal file
724
Scripts/Commands/Add.cs
Normal file
@@ -0,0 +1,724 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
using CPA = Server.CommandPropertyAttribute;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class Add
|
||||
{
|
||||
private static readonly Type m_EntityType = typeof(IEntity);
|
||||
private static readonly Type m_ConstructableType = typeof(ConstructableAttribute);
|
||||
private static readonly Type m_EnumType = typeof(Enum);
|
||||
private static readonly Type m_TypeType = typeof(Type);
|
||||
private static readonly Type m_ParsableType = typeof(ParsableAttribute);
|
||||
private static readonly Type[] m_ParseTypes = new Type[] { typeof(string) };
|
||||
private static readonly object[] m_ParseArgs = new object[1];
|
||||
private static readonly Type[] m_SignedNumerics = new Type[]
|
||||
{
|
||||
typeof(Int64),
|
||||
typeof(Int32),
|
||||
typeof(Int16),
|
||||
typeof(SByte)
|
||||
};
|
||||
private static readonly Type[] m_UnsignedNumerics = new Type[]
|
||||
{
|
||||
typeof(UInt64),
|
||||
typeof(UInt32),
|
||||
typeof(UInt16),
|
||||
typeof(Byte)
|
||||
};
|
||||
|
||||
private enum TileZType
|
||||
{
|
||||
Start,
|
||||
Fixed,
|
||||
MapAverage
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Tile", AccessLevel.GameMaster, new CommandEventHandler(Tile_OnCommand));
|
||||
CommandSystem.Register("TileRXYZ", AccessLevel.GameMaster, new CommandEventHandler(TileRXYZ_OnCommand));
|
||||
CommandSystem.Register("TileXYZ", AccessLevel.GameMaster, new CommandEventHandler(TileXYZ_OnCommand));
|
||||
CommandSystem.Register("TileZ", AccessLevel.GameMaster, new CommandEventHandler(TileZ_OnCommand));
|
||||
CommandSystem.Register("TileAvg", AccessLevel.GameMaster, new CommandEventHandler(TileAvg_OnCommand));
|
||||
|
||||
CommandSystem.Register("Outline", AccessLevel.GameMaster, new CommandEventHandler(Outline_OnCommand));
|
||||
CommandSystem.Register("OutlineRXYZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineRXYZ_OnCommand));
|
||||
CommandSystem.Register("OutlineXYZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineXYZ_OnCommand));
|
||||
CommandSystem.Register("OutlineZ", AccessLevel.GameMaster, new CommandEventHandler(OutlineZ_OnCommand));
|
||||
CommandSystem.Register("OutlineAvg", AccessLevel.GameMaster, new CommandEventHandler(OutlineAvg_OnCommand));
|
||||
}
|
||||
|
||||
public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args)
|
||||
{
|
||||
Invoke(from, start, end, args, null, false, false);
|
||||
}
|
||||
|
||||
public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args, List<Container> packs)
|
||||
{
|
||||
Invoke(from, start, end, args, packs, false, false);
|
||||
}
|
||||
|
||||
public static void Invoke(Mobile from, Point3D start, Point3D end, string[] args, List<Container> packs, bool outline, bool mapAvg)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.AppendFormat("{0} {1} building ", from.AccessLevel, CommandLogging.Format(from));
|
||||
|
||||
if (start == end)
|
||||
sb.AppendFormat("at {0} in {1}", start, from.Map);
|
||||
else
|
||||
sb.AppendFormat("from {0} to {1} in {2}", start, end, from.Map);
|
||||
|
||||
sb.Append(":");
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
sb.AppendFormat(" \"{0}\"", args[i]);
|
||||
|
||||
CommandLogging.WriteLine(from, sb.ToString());
|
||||
|
||||
string name = args[0];
|
||||
|
||||
FixArgs(ref args);
|
||||
|
||||
string[,] props = null;
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
if (Insensitive.Equals(args[i], "set"))
|
||||
{
|
||||
int remains = args.Length - i - 1;
|
||||
|
||||
if (remains >= 2)
|
||||
{
|
||||
props = new string[remains / 2, 2];
|
||||
|
||||
remains /= 2;
|
||||
|
||||
for (int j = 0; j < remains; ++j)
|
||||
{
|
||||
props[j, 0] = args[i + (j * 2) + 1];
|
||||
props[j, 1] = args[i + (j * 2) + 2];
|
||||
}
|
||||
|
||||
FixSetString(ref args, i);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Type type = ScriptCompiler.FindTypeByName(name);
|
||||
|
||||
if (!IsEntity(type))
|
||||
{
|
||||
from.SendMessage("No type with that name was found.");
|
||||
return;
|
||||
}
|
||||
|
||||
DateTime time = DateTime.UtcNow;
|
||||
|
||||
int built = BuildObjects(from, type, start, end, args, props, packs, outline, mapAvg);
|
||||
|
||||
if (built > 0)
|
||||
from.SendMessage("{0} object{1} generated in {2:F1} seconds.", built, built != 1 ? "s" : "", (DateTime.UtcNow - time).TotalSeconds);
|
||||
else
|
||||
SendUsage(type, from);
|
||||
}
|
||||
|
||||
public static void FixSetString(ref string[] args, int index)
|
||||
{
|
||||
string[] old = args;
|
||||
args = new string[index];
|
||||
|
||||
Array.Copy(old, 0, args, 0, index);
|
||||
}
|
||||
|
||||
public static void FixArgs(ref string[] args)
|
||||
{
|
||||
string[] old = args;
|
||||
args = new string[args.Length - 1];
|
||||
|
||||
Array.Copy(old, 1, args, 0, args.Length);
|
||||
}
|
||||
|
||||
public static int BuildObjects(Mobile from, Type type, Point3D start, Point3D end, string[] args, string[,] props, List<Container> packs)
|
||||
{
|
||||
return BuildObjects(from, type, start, end, args, props, packs, false, false);
|
||||
}
|
||||
|
||||
public static int BuildObjects(Mobile from, Type type, Point3D start, Point3D end, string[] args, string[,] props, List<Container> packs, bool outline, bool mapAvg)
|
||||
{
|
||||
Utility.FixPoints(ref start, ref end);
|
||||
|
||||
PropertyInfo[] realProps = null;
|
||||
|
||||
if (props != null)
|
||||
{
|
||||
realProps = new PropertyInfo[props.GetLength(0)];
|
||||
|
||||
PropertyInfo[] allProps = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
for (int i = 0; i < realProps.Length; ++i)
|
||||
{
|
||||
PropertyInfo thisProp = null;
|
||||
|
||||
string propName = props[i, 0];
|
||||
|
||||
for (int j = 0; thisProp == null && j < allProps.Length; ++j)
|
||||
{
|
||||
if (Insensitive.Equals(propName, allProps[j].Name))
|
||||
thisProp = allProps[j];
|
||||
}
|
||||
|
||||
if (thisProp == null)
|
||||
{
|
||||
from.SendMessage("Property not found: {0}", propName);
|
||||
}
|
||||
else
|
||||
{
|
||||
CPA attr = Properties.GetCPA(thisProp);
|
||||
|
||||
if (attr == null)
|
||||
from.SendMessage("Property ({0}) not found.", propName);
|
||||
else if (from.AccessLevel < attr.WriteLevel)
|
||||
from.SendMessage("Setting this property ({0}) requires at least {1} access level.", propName, Mobile.GetAccessLevelName(attr.WriteLevel));
|
||||
else if (!thisProp.CanWrite || attr.ReadOnly)
|
||||
from.SendMessage("Property ({0}) is read only.", propName);
|
||||
else
|
||||
realProps[i] = thisProp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConstructorInfo[] ctors = type.GetConstructors();
|
||||
|
||||
for (int i = 0; i < ctors.Length; ++i)
|
||||
{
|
||||
ConstructorInfo ctor = ctors[i];
|
||||
|
||||
if (!IsConstructable(ctor, from.AccessLevel))
|
||||
continue;
|
||||
|
||||
ParameterInfo[] paramList = ctor.GetParameters();
|
||||
|
||||
if (args.Length == paramList.Length)
|
||||
{
|
||||
object[] paramValues = ParseValues(paramList, args);
|
||||
|
||||
if (paramValues == null)
|
||||
continue;
|
||||
|
||||
int built = Build(from, start, end, ctor, paramValues, props, realProps, packs, outline, mapAvg);
|
||||
|
||||
if (built > 0)
|
||||
return built;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static object[] ParseValues(ParameterInfo[] paramList, string[] args)
|
||||
{
|
||||
object[] values = new object[args.Length];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
object value = ParseValue(paramList[i].ParameterType, args[i]);
|
||||
|
||||
if (value != null)
|
||||
values[i] = value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static object ParseValue(Type type, string value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (IsEnum(type))
|
||||
{
|
||||
return Enum.Parse(type, value, true);
|
||||
}
|
||||
else if (IsType(type))
|
||||
{
|
||||
return ScriptCompiler.FindTypeByName(value);
|
||||
}
|
||||
else if (IsParsable(type))
|
||||
{
|
||||
return ParseParsable(type, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
object obj = value;
|
||||
|
||||
if (value != null && value.StartsWith("0x"))
|
||||
{
|
||||
if (IsSignedNumeric(type))
|
||||
obj = Convert.ToInt64(value.Substring(2), 16);
|
||||
else if (IsUnsignedNumeric(type))
|
||||
obj = Convert.ToUInt64(value.Substring(2), 16);
|
||||
|
||||
obj = Convert.ToInt32(value.Substring(2), 16);
|
||||
}
|
||||
|
||||
if (obj == null && !type.IsValueType)
|
||||
return null;
|
||||
else
|
||||
return Convert.ChangeType(obj, type);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static IEntity Build(Mobile from, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, ref bool sendError)
|
||||
{
|
||||
object built = ctor.Invoke(values);
|
||||
|
||||
if (built != null && realProps != null)
|
||||
{
|
||||
bool hadError = false;
|
||||
|
||||
for (int i = 0; i < realProps.Length; ++i)
|
||||
{
|
||||
if (realProps[i] == null)
|
||||
continue;
|
||||
|
||||
string result = Properties.InternalSetValue(from, built, built, realProps[i], props[i, 1], props[i, 1], false);
|
||||
|
||||
if (result != "Property has been set.")
|
||||
{
|
||||
if (sendError)
|
||||
from.SendMessage(result);
|
||||
|
||||
hadError = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hadError)
|
||||
sendError = false;
|
||||
}
|
||||
|
||||
return (IEntity)built;
|
||||
}
|
||||
|
||||
public static int Build(Mobile from, Point3D start, Point3D end, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, List<Container> packs)
|
||||
{
|
||||
return Build(from, start, end, ctor, values, props, realProps, packs, false, false);
|
||||
}
|
||||
|
||||
public static int Build(Mobile from, Point3D start, Point3D end, ConstructorInfo ctor, object[] values, string[,] props, PropertyInfo[] realProps, List<Container> packs, bool outline, bool mapAvg)
|
||||
{
|
||||
try
|
||||
{
|
||||
Map map = from.Map;
|
||||
|
||||
int width = end.X - start.X + 1;
|
||||
int height = end.Y - start.Y + 1;
|
||||
|
||||
if (outline && (width < 3 || height < 3))
|
||||
outline = false;
|
||||
|
||||
int objectCount;
|
||||
|
||||
if (packs != null)
|
||||
objectCount = packs.Count;
|
||||
else if (outline)
|
||||
objectCount = (width + height - 2) * 2;
|
||||
else
|
||||
objectCount = width * height;
|
||||
|
||||
if (objectCount >= 20)
|
||||
from.SendMessage("Constructing {0} objects, please wait.", objectCount);
|
||||
|
||||
bool sendError = true;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("Serials: ");
|
||||
|
||||
if (packs != null)
|
||||
{
|
||||
for (int i = 0; i < packs.Count; ++i)
|
||||
{
|
||||
IEntity built = Build(from, ctor, values, props, realProps, ref sendError);
|
||||
|
||||
sb.AppendFormat("0x{0:X}; ", built.Serial.Value);
|
||||
|
||||
if (built is Item)
|
||||
{
|
||||
Container pack = packs[i];
|
||||
pack.DropItem((Item)built);
|
||||
}
|
||||
else if (built is Mobile)
|
||||
{
|
||||
Mobile m = (Mobile)built;
|
||||
m.MoveToWorld(new Point3D(start.X, start.Y, start.Z), map);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int z = start.Z;
|
||||
|
||||
for (int x = start.X; x <= end.X; ++x)
|
||||
{
|
||||
for (int y = start.Y; y <= end.Y; ++y)
|
||||
{
|
||||
if (outline && x != start.X && x != end.X && y != start.Y && y != end.Y)
|
||||
continue;
|
||||
|
||||
if (mapAvg)
|
||||
z = map.GetAverageZ(x, y);
|
||||
|
||||
IEntity built = Build(from, ctor, values, props, realProps, ref sendError);
|
||||
|
||||
sb.AppendFormat("0x{0:X}; ", built.Serial.Value);
|
||||
|
||||
if (built is Item)
|
||||
{
|
||||
Item item = (Item)built;
|
||||
item.MoveToWorld(new Point3D(x, y, z), map);
|
||||
}
|
||||
else if (built is Mobile)
|
||||
{
|
||||
Mobile m = (Mobile)built;
|
||||
m.MoveToWorld(new Point3D(x, y, z), map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CommandLogging.WriteLine(from, sb.ToString());
|
||||
|
||||
return objectCount;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendUsage(Type type, Mobile from)
|
||||
{
|
||||
ConstructorInfo[] ctors = type.GetConstructors();
|
||||
bool foundCtor = false;
|
||||
|
||||
for (int i = 0; i < ctors.Length; ++i)
|
||||
{
|
||||
ConstructorInfo ctor = ctors[i];
|
||||
|
||||
if (!IsConstructable(ctor, from.AccessLevel))
|
||||
continue;
|
||||
|
||||
if (!foundCtor)
|
||||
{
|
||||
foundCtor = true;
|
||||
from.SendMessage("Usage:");
|
||||
}
|
||||
|
||||
SendCtor(type, ctor, from);
|
||||
}
|
||||
|
||||
if (!foundCtor)
|
||||
from.SendMessage("That type is not marked constructable.");
|
||||
}
|
||||
|
||||
public static void SendCtor(Type type, ConstructorInfo ctor, Mobile from)
|
||||
{
|
||||
ParameterInfo[] paramList = ctor.GetParameters();
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append(type.Name);
|
||||
|
||||
for (int i = 0; i < paramList.Length; ++i)
|
||||
{
|
||||
if (i != 0)
|
||||
sb.Append(',');
|
||||
|
||||
sb.Append(' ');
|
||||
|
||||
sb.Append(paramList[i].ParameterType.Name);
|
||||
sb.Append(' ');
|
||||
sb.Append(paramList[i].Name);
|
||||
}
|
||||
|
||||
from.SendMessage(sb.ToString());
|
||||
}
|
||||
|
||||
[Usage("Tile <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name into a targeted bounding box. Optional constructor parameters. Optional set property list.")]
|
||||
public static void Tile_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
Internal_OnCommand(e, false);
|
||||
}
|
||||
|
||||
[Usage("TileRXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name into a given bounding box, (x, y) parameters are relative to your characters position. Optional constructor parameters. Optional set property list.")]
|
||||
public static void TileRXYZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalRXYZ_OnCommand(e, false);
|
||||
}
|
||||
|
||||
[Usage("TileXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name into a given bounding box. Optional constructor parameters. Optional set property list.")]
|
||||
public static void TileXYZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalXYZ_OnCommand(e, false);
|
||||
}
|
||||
|
||||
[Usage("TileZ <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name into a targeted bounding box at a fixed Z location. Optional constructor parameters. Optional set property list.")]
|
||||
public static void TileZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalZ_OnCommand(e, false);
|
||||
}
|
||||
|
||||
[Usage("TileAvg <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name into a targeted bounding box on the map's average Z elevation. Optional constructor parameters. Optional set property list.")]
|
||||
public static void TileAvg_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalAvg_OnCommand(e, false);
|
||||
}
|
||||
|
||||
[Usage("Outline <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name around a targeted bounding box. Optional constructor parameters. Optional set property list.")]
|
||||
public static void Outline_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
Internal_OnCommand(e, true);
|
||||
}
|
||||
|
||||
[Usage("OutlineRXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name around a given bounding box, (x, y) parameters are relative to your characters position. Optional constructor parameters. Optional set property list.")]
|
||||
public static void OutlineRXYZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalRXYZ_OnCommand(e, true);
|
||||
}
|
||||
|
||||
[Usage("OutlineXYZ <x> <y> <w> <h> <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name around a given bounding box. Optional constructor parameters. Optional set property list.")]
|
||||
public static void OutlineXYZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalXYZ_OnCommand(e, true);
|
||||
}
|
||||
|
||||
[Usage("OutlineZ <z> <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name around a targeted bounding box at a fixed Z location. Optional constructor parameters. Optional set property list.")]
|
||||
public static void OutlineZ_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalZ_OnCommand(e, true);
|
||||
}
|
||||
|
||||
[Usage("OutlineAvg <name> [params] [set {<propertyName> <value> ...}]")]
|
||||
[Description("Tiles an item or npc by name around a targeted bounding box on the map's average Z elevation. Optional constructor parameters. Optional set property list.")]
|
||||
public static void OutlineAvg_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
InternalAvg_OnCommand(e, true);
|
||||
}
|
||||
|
||||
public static bool IsEntity(Type t)
|
||||
{
|
||||
return t != null && t.GetInterface(m_EntityType.Name) != null;
|
||||
}
|
||||
|
||||
public static bool IsConstructable(ConstructorInfo ctor, AccessLevel accessLevel)
|
||||
{
|
||||
object[] attrs = ctor.GetCustomAttributes(m_ConstructableType, false);
|
||||
|
||||
if (attrs.Length == 0)
|
||||
return false;
|
||||
|
||||
return accessLevel >= ((ConstructableAttribute)attrs[0]).AccessLevel;
|
||||
}
|
||||
|
||||
public static bool IsEnum(Type type)
|
||||
{
|
||||
return type.IsSubclassOf(m_EnumType);
|
||||
}
|
||||
|
||||
public static bool IsType(Type type)
|
||||
{
|
||||
return (type == m_TypeType || type.IsSubclassOf(m_TypeType));
|
||||
}
|
||||
|
||||
public static bool IsParsable(Type type)
|
||||
{
|
||||
return type.IsDefined(m_ParsableType, false);
|
||||
}
|
||||
|
||||
public static object ParseParsable(Type type, string value)
|
||||
{
|
||||
MethodInfo method = type.GetMethod("Parse", m_ParseTypes);
|
||||
|
||||
m_ParseArgs[0] = value;
|
||||
|
||||
return method.Invoke(null, m_ParseArgs);
|
||||
}
|
||||
|
||||
public static bool IsSignedNumeric(Type type)
|
||||
{
|
||||
for (int i = 0; i < m_SignedNumerics.Length; ++i)
|
||||
if (type == m_SignedNumerics[i])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsUnsignedNumeric(Type type)
|
||||
{
|
||||
for (int i = 0; i < m_UnsignedNumerics.Length; ++i)
|
||||
if (type == m_UnsignedNumerics[i])
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void TileBox_Callback(Mobile from, Map map, Point3D start, Point3D end, object state)
|
||||
{
|
||||
TileState ts = (TileState)state;
|
||||
bool mapAvg = false;
|
||||
|
||||
switch ( ts.m_ZType )
|
||||
{
|
||||
case TileZType.Fixed:
|
||||
{
|
||||
start.Z = end.Z = ts.m_FixedZ;
|
||||
break;
|
||||
}
|
||||
case TileZType.MapAverage:
|
||||
{
|
||||
mapAvg = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Invoke(from, start, end, ts.m_Args, null, ts.m_Outline, mapAvg);
|
||||
}
|
||||
|
||||
private static void Internal_OnCommand(CommandEventArgs e, bool outline)
|
||||
{
|
||||
if (e.Length >= 1)
|
||||
BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.Start, 0, e.Arguments, outline));
|
||||
else
|
||||
e.Mobile.SendMessage("Format: {0} <type> [params] [set {{<propertyName> <value> ...}}]", outline ? "Outline" : "Tile");
|
||||
}
|
||||
|
||||
private static void InternalRXYZ_OnCommand(CommandEventArgs e, bool outline)
|
||||
{
|
||||
if (e.Length >= 6)
|
||||
{
|
||||
Point3D p = new Point3D(e.Mobile.X + e.GetInt32(0), e.Mobile.Y + e.GetInt32(1), e.Mobile.Z + e.GetInt32(4));
|
||||
Point3D p2 = new Point3D(p.X + e.GetInt32(2) - 1, p.Y + e.GetInt32(3) - 1, p.Z);
|
||||
|
||||
string[] subArgs = new string[e.Length - 5];
|
||||
|
||||
for (int i = 0; i < subArgs.Length; ++i)
|
||||
subArgs[i] = e.Arguments[i + 5];
|
||||
|
||||
Add.Invoke(e.Mobile, p, p2, subArgs, null, outline, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("Format: {0}RXYZ <x> <y> <w> <h> <z> <type> [params] [set {{<propertyName> <value> ...}}]", outline ? "Outline" : "Tile");
|
||||
}
|
||||
}
|
||||
|
||||
private static void InternalXYZ_OnCommand(CommandEventArgs e, bool outline)
|
||||
{
|
||||
if (e.Length >= 6)
|
||||
{
|
||||
Point3D p = new Point3D(e.GetInt32(0), e.GetInt32(1), e.GetInt32(4));
|
||||
Point3D p2 = new Point3D(p.X + e.GetInt32(2) - 1, p.Y + e.GetInt32(3) - 1, e.GetInt32(4));
|
||||
|
||||
string[] subArgs = new string[e.Length - 5];
|
||||
|
||||
for (int i = 0; i < subArgs.Length; ++i)
|
||||
subArgs[i] = e.Arguments[i + 5];
|
||||
|
||||
Add.Invoke(e.Mobile, p, p2, subArgs, null, outline, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("Format: {0}XYZ <x> <y> <w> <h> <z> <type> [params] [set {{<propertyName> <value> ...}}]", outline ? "Outline" : "Tile");
|
||||
}
|
||||
}
|
||||
|
||||
private static void InternalZ_OnCommand(CommandEventArgs e, bool outline)
|
||||
{
|
||||
if (e.Length >= 2)
|
||||
{
|
||||
string[] subArgs = new string[e.Length - 1];
|
||||
|
||||
for (int i = 0; i < subArgs.Length; ++i)
|
||||
subArgs[i] = e.Arguments[i + 1];
|
||||
|
||||
BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.Fixed, e.GetInt32(0), subArgs, outline));
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("Format: {0}Z <z> <type> [params] [set {{<propertyName> <value> ...}}]", outline ? "Outline" : "Tile");
|
||||
}
|
||||
}
|
||||
|
||||
private static void InternalAvg_OnCommand(CommandEventArgs e, bool outline)
|
||||
{
|
||||
if (e.Length >= 1)
|
||||
BoundingBoxPicker.Begin(e.Mobile, new BoundingBoxCallback(TileBox_Callback), new TileState(TileZType.MapAverage, 0, e.Arguments, outline));
|
||||
else
|
||||
e.Mobile.SendMessage("Format: {0}Avg <type> [params] [set {{<propertyName> <value> ...}}]", outline ? "Outline" : "Tile");
|
||||
}
|
||||
|
||||
public class AddTarget : Target
|
||||
{
|
||||
private readonly string[] m_Args;
|
||||
public AddTarget(string[] args)
|
||||
: base(-1, true, TargetFlags.None)
|
||||
{
|
||||
this.m_Args = args;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object o)
|
||||
{
|
||||
IPoint3D p = o as IPoint3D;
|
||||
|
||||
if (p != null)
|
||||
{
|
||||
if (p is Item)
|
||||
p = ((Item)p).GetWorldTop();
|
||||
else if (p is Mobile)
|
||||
p = ((Mobile)p).Location;
|
||||
|
||||
Point3D point = new Point3D(p);
|
||||
Add.Invoke(from, point, point, this.m_Args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class TileState
|
||||
{
|
||||
public readonly TileZType m_ZType;
|
||||
public readonly int m_FixedZ;
|
||||
public readonly string[] m_Args;
|
||||
public readonly bool m_Outline;
|
||||
public TileState(TileZType zType, int fixedZ, string[] args, bool outline)
|
||||
{
|
||||
this.m_ZType = zType;
|
||||
this.m_FixedZ = fixedZ;
|
||||
this.m_Args = args;
|
||||
this.m_Outline = outline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
55
Scripts/Commands/Attributes.cs
Normal file
55
Scripts/Commands/Attributes.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class UsageAttribute : Attribute
|
||||
{
|
||||
private readonly string m_Usage;
|
||||
public UsageAttribute(string usage)
|
||||
{
|
||||
this.m_Usage = usage;
|
||||
}
|
||||
|
||||
public string Usage
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class DescriptionAttribute : Attribute
|
||||
{
|
||||
private readonly string m_Description;
|
||||
public DescriptionAttribute(string description)
|
||||
{
|
||||
this.m_Description = description;
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Description;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class AliasesAttribute : Attribute
|
||||
{
|
||||
private readonly string[] m_Aliases;
|
||||
public AliasesAttribute(params string[] aliases)
|
||||
{
|
||||
this.m_Aliases = aliases;
|
||||
}
|
||||
|
||||
public string[] Aliases
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Aliases;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
476
Scripts/Commands/Batch.cs
Normal file
476
Scripts/Commands/Batch.cs
Normal file
@@ -0,0 +1,476 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using Server.Commands.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class Batch : BaseCommand
|
||||
{
|
||||
private readonly ArrayList m_BatchCommands;
|
||||
private BaseCommandImplementor m_Scope;
|
||||
private string m_Condition;
|
||||
public Batch()
|
||||
{
|
||||
this.Commands = new string[] { "Batch" };
|
||||
this.ListOptimized = true;
|
||||
|
||||
this.m_BatchCommands = new ArrayList();
|
||||
this.m_Condition = "";
|
||||
}
|
||||
|
||||
public BaseCommandImplementor Scope
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Scope;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Scope = value;
|
||||
}
|
||||
}
|
||||
public string Condition
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Condition;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Condition = value;
|
||||
}
|
||||
}
|
||||
public ArrayList BatchCommands
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_BatchCommands;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Batch", AccessLevel.Counselor, new CommandEventHandler(Batch_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("Batch")]
|
||||
[Description("Allows multiple commands to be run at the same time.")]
|
||||
public static void Batch_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
Batch batch = new Batch();
|
||||
|
||||
e.Mobile.SendGump(new BatchGump(e.Mobile, batch));
|
||||
}
|
||||
|
||||
public override void ExecuteList(CommandEventArgs e, ArrayList list)
|
||||
{
|
||||
if (list.Count == 0)
|
||||
{
|
||||
this.LogFailure("Nothing was found to use this command on.");
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BaseCommand[] commands = new BaseCommand[this.m_BatchCommands.Count];
|
||||
CommandEventArgs[] eventArgs = new CommandEventArgs[this.m_BatchCommands.Count];
|
||||
|
||||
for (int i = 0; i < this.m_BatchCommands.Count; ++i)
|
||||
{
|
||||
BatchCommand bc = (BatchCommand)this.m_BatchCommands[i];
|
||||
|
||||
string commandString, argString;
|
||||
string[] args;
|
||||
|
||||
bc.GetDetails(out commandString, out argString, out args);
|
||||
|
||||
BaseCommand command = this.m_Scope.Commands[commandString];
|
||||
|
||||
commands[i] = command;
|
||||
eventArgs[i] = new CommandEventArgs(e.Mobile, commandString, argString, args);
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier: {0}.", commandString);
|
||||
return;
|
||||
}
|
||||
else if (e.Mobile.AccessLevel < command.AccessLevel)
|
||||
{
|
||||
e.Mobile.SendMessage("You do not have access to that command: {0}.", commandString);
|
||||
return;
|
||||
}
|
||||
else if (!command.ValidateArgs(this.m_Scope, eventArgs[i]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < commands.Length; ++i)
|
||||
{
|
||||
BaseCommand command = commands[i];
|
||||
BatchCommand bc = (BatchCommand)this.m_BatchCommands[i];
|
||||
|
||||
if (list.Count > 20)
|
||||
CommandLogging.Enabled = false;
|
||||
|
||||
ArrayList usedList;
|
||||
|
||||
if (Utility.InsensitiveCompare(bc.Object, "Current") == 0)
|
||||
{
|
||||
usedList = list;
|
||||
}
|
||||
else
|
||||
{
|
||||
Hashtable propertyChains = new Hashtable();
|
||||
|
||||
usedList = new ArrayList(list.Count);
|
||||
|
||||
for (int j = 0; j < list.Count; ++j)
|
||||
{
|
||||
object obj = list[j];
|
||||
|
||||
if (obj == null)
|
||||
continue;
|
||||
|
||||
Type type = obj.GetType();
|
||||
|
||||
PropertyInfo[] chain = (PropertyInfo[])propertyChains[type];
|
||||
|
||||
string failReason = "";
|
||||
|
||||
if (chain == null && !propertyChains.Contains(type))
|
||||
propertyChains[type] = chain = Properties.GetPropertyInfoChain(e.Mobile, type, bc.Object, PropertyAccess.Read, ref failReason);
|
||||
|
||||
if (chain == null)
|
||||
continue;
|
||||
|
||||
PropertyInfo endProp = Properties.GetPropertyInfo(ref obj, chain, ref failReason);
|
||||
|
||||
if (endProp == null)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
obj = endProp.GetValue(obj, null);
|
||||
|
||||
if (obj != null)
|
||||
usedList.Add(obj);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
command.ExecuteList(eventArgs[i], usedList);
|
||||
|
||||
if (list.Count > 20)
|
||||
CommandLogging.Enabled = true;
|
||||
|
||||
command.Flush(e.Mobile, list.Count > 20);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
e.Mobile.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Run(Mobile from)
|
||||
{
|
||||
if (this.m_Scope == null)
|
||||
{
|
||||
from.SendMessage("You must select the batch command scope.");
|
||||
return false;
|
||||
}
|
||||
else if (this.m_Condition.Length > 0 && !this.m_Scope.SupportsConditionals)
|
||||
{
|
||||
from.SendMessage("This command scope does not support conditionals.");
|
||||
return false;
|
||||
}
|
||||
else if (this.m_Condition.Length > 0 && !Utility.InsensitiveStartsWith(this.m_Condition, "where"))
|
||||
{
|
||||
from.SendMessage("The condition field must start with \"where\".");
|
||||
return false;
|
||||
}
|
||||
|
||||
string[] args = CommandSystem.Split(this.m_Condition);
|
||||
|
||||
this.m_Scope.Process(from, this, args);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class BatchCommand
|
||||
{
|
||||
private string m_Command;
|
||||
private string m_Object;
|
||||
public BatchCommand(string command, string obj)
|
||||
{
|
||||
this.m_Command = command;
|
||||
this.m_Object = obj;
|
||||
}
|
||||
|
||||
public string Command
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Command;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Command = value;
|
||||
}
|
||||
}
|
||||
public string Object
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Object;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Object = value;
|
||||
}
|
||||
}
|
||||
public void GetDetails(out string command, out string argString, out string[] args)
|
||||
{
|
||||
int indexOf = this.m_Command.IndexOf(' ');
|
||||
|
||||
if (indexOf >= 0)
|
||||
{
|
||||
argString = this.m_Command.Substring(indexOf + 1);
|
||||
|
||||
command = this.m_Command.Substring(0, indexOf);
|
||||
args = CommandSystem.Split(argString);
|
||||
}
|
||||
else
|
||||
{
|
||||
argString = "";
|
||||
command = this.m_Command.ToLower();
|
||||
args = new string[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class BatchGump : BaseGridGump
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly Batch m_Batch;
|
||||
public BatchGump(Mobile from, Batch batch)
|
||||
: base(30, 30)
|
||||
{
|
||||
this.m_From = from;
|
||||
this.m_Batch = batch;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
this.AddNewPage();
|
||||
|
||||
/* Header */
|
||||
this.AddEntryHeader(20);
|
||||
this.AddEntryHtml(180, this.Center("Batch Commands"));
|
||||
this.AddEntryHeader(20);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddEntryHeader(9);
|
||||
this.AddEntryLabel(191, "Run Batch");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, this.GetButtonID(1, 0, 0), ArrowRightWidth, ArrowRightHeight);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddBlankLine();
|
||||
|
||||
/* Scope */
|
||||
this.AddEntryHeader(20);
|
||||
this.AddEntryHtml(180, this.Center("Scope"));
|
||||
this.AddEntryHeader(20);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddEntryHeader(9);
|
||||
this.AddEntryLabel(191, this.m_Batch.Scope == null ? "Select Scope" : this.m_Batch.Scope.Accessors[0]);
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, this.GetButtonID(1, 0, 1), ArrowRightWidth, ArrowRightHeight);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddBlankLine();
|
||||
|
||||
/* Condition */
|
||||
this.AddEntryHeader(20);
|
||||
this.AddEntryHtml(180, this.Center("Condition"));
|
||||
this.AddEntryHeader(20);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddEntryHeader(9);
|
||||
this.AddEntryText(202, 0, this.m_Batch.Condition);
|
||||
this.AddEntryHeader(9);
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddBlankLine();
|
||||
|
||||
/* Commands */
|
||||
this.AddEntryHeader(20);
|
||||
this.AddEntryHtml(180, this.Center("Commands"));
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
for (int i = 0; i < this.m_Batch.BatchCommands.Count; ++i)
|
||||
{
|
||||
BatchCommand bc = (BatchCommand)this.m_Batch.BatchCommands[i];
|
||||
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddImageTiled(this.CurrentX, this.CurrentY, 9, 2, 0x24A8);
|
||||
this.AddImageTiled(this.CurrentX, this.CurrentY + 2, 2, this.EntryHeight + this.OffsetSize + this.EntryHeight - 4, 0x24A8);
|
||||
this.AddImageTiled(this.CurrentX, this.CurrentY + this.EntryHeight + this.OffsetSize + this.EntryHeight - 2, 9, 2, 0x24A8);
|
||||
this.AddImageTiled(this.CurrentX + 3, this.CurrentY + 3, 6, this.EntryHeight + this.EntryHeight - 4 - this.OffsetSize, this.HeaderGumpID);
|
||||
|
||||
this.IncreaseX(9);
|
||||
this.AddEntryText(202, 1 + (i * 2), bc.Command);
|
||||
this.AddEntryHeader(9, 2);
|
||||
|
||||
this.AddNewLine();
|
||||
|
||||
this.IncreaseX(9);
|
||||
this.AddEntryText(202, 2 + (i * 2), bc.Object);
|
||||
}
|
||||
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddEntryHeader(9);
|
||||
this.AddEntryLabel(191, "Add New Command");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, this.GetButtonID(1, 0, 2), ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.FinishPage();
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
int type, index;
|
||||
|
||||
if (!this.SplitButtonID(info.ButtonID, 1, out type, out index))
|
||||
return;
|
||||
|
||||
TextRelay entry = info.GetTextEntry(0);
|
||||
|
||||
if (entry != null)
|
||||
this.m_Batch.Condition = entry.Text;
|
||||
|
||||
for (int i = this.m_Batch.BatchCommands.Count - 1; i >= 0; --i)
|
||||
{
|
||||
BatchCommand sc = (BatchCommand)this.m_Batch.BatchCommands[i];
|
||||
|
||||
entry = info.GetTextEntry(1 + (i * 2));
|
||||
|
||||
if (entry != null)
|
||||
sc.Command = entry.Text;
|
||||
|
||||
entry = info.GetTextEntry(2 + (i * 2));
|
||||
|
||||
if (entry != null)
|
||||
sc.Object = entry.Text;
|
||||
|
||||
if (sc.Command.Length == 0 && sc.Object.Length == 0)
|
||||
this.m_Batch.BatchCommands.RemoveAt(i);
|
||||
}
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case 0: // main
|
||||
{
|
||||
switch ( index )
|
||||
{
|
||||
case 0: // run
|
||||
{
|
||||
this.m_Batch.Run(this.m_From);
|
||||
break;
|
||||
}
|
||||
case 1: // set scope
|
||||
{
|
||||
this.m_From.SendGump(new BatchScopeGump(this.m_From, this.m_Batch));
|
||||
return;
|
||||
}
|
||||
case 2: // add command
|
||||
{
|
||||
this.m_Batch.BatchCommands.Add(new BatchCommand("", ""));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.m_From.SendGump(new BatchGump(this.m_From, this.m_Batch));
|
||||
}
|
||||
}
|
||||
|
||||
public class BatchScopeGump : BaseGridGump
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly Batch m_Batch;
|
||||
public BatchScopeGump(Mobile from, Batch batch)
|
||||
: base(30, 30)
|
||||
{
|
||||
this.m_From = from;
|
||||
this.m_Batch = batch;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
this.AddNewPage();
|
||||
|
||||
/* Header */
|
||||
this.AddEntryHeader(20);
|
||||
this.AddEntryHtml(140, this.Center("Change Scope"));
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
/* Options */
|
||||
for (int i = 0; i < BaseCommandImplementor.Implementors.Count; ++i)
|
||||
{
|
||||
BaseCommandImplementor impl = BaseCommandImplementor.Implementors[i];
|
||||
|
||||
if (this.m_From.AccessLevel < impl.AccessLevel)
|
||||
continue;
|
||||
|
||||
this.AddNewLine();
|
||||
|
||||
this.AddEntryLabel(20 + this.OffsetSize + 140, impl.Accessors[0]);
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, this.GetButtonID(1, 0, i), ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
|
||||
this.FinishPage();
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
int type, index;
|
||||
|
||||
if (this.SplitButtonID(info.ButtonID, 1, out type, out index))
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if (index < BaseCommandImplementor.Implementors.Count)
|
||||
{
|
||||
BaseCommandImplementor impl = BaseCommandImplementor.Implementors[index];
|
||||
|
||||
if (this.m_From.AccessLevel >= impl.AccessLevel)
|
||||
this.m_Batch.Scope = impl;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.m_From.SendGump(new BatchGump(this.m_From, this.m_Batch));
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Scripts/Commands/BoundingBoxPicker.cs
Normal file
68
Scripts/Commands/BoundingBoxPicker.cs
Normal file
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public delegate void BoundingBoxCallback(Mobile from, Map map, Point3D start, Point3D end, object state);
|
||||
|
||||
public class BoundingBoxPicker
|
||||
{
|
||||
public static void Begin(Mobile from, BoundingBoxCallback callback, object state)
|
||||
{
|
||||
from.SendMessage("Target the first location of the bounding box.");
|
||||
from.Target = new PickTarget(callback, state);
|
||||
}
|
||||
|
||||
private class PickTarget : Target
|
||||
{
|
||||
private readonly Point3D m_Store;
|
||||
private readonly bool m_First;
|
||||
private readonly Map m_Map;
|
||||
private readonly BoundingBoxCallback m_Callback;
|
||||
private readonly object m_State;
|
||||
public PickTarget(BoundingBoxCallback callback, object state)
|
||||
: this(Point3D.Zero, true, null, callback, state)
|
||||
{
|
||||
}
|
||||
|
||||
public PickTarget(Point3D store, bool first, Map map, BoundingBoxCallback callback, object state)
|
||||
: base(-1, true, TargetFlags.None)
|
||||
{
|
||||
this.m_Store = store;
|
||||
this.m_First = first;
|
||||
this.m_Map = map;
|
||||
this.m_Callback = callback;
|
||||
this.m_State = state;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
IPoint3D p = targeted as IPoint3D;
|
||||
|
||||
if (p == null)
|
||||
return;
|
||||
else if (p is Item)
|
||||
p = ((Item)p).GetWorldTop();
|
||||
|
||||
if (this.m_First)
|
||||
{
|
||||
from.SendMessage("Target another location to complete the bounding box.");
|
||||
from.Target = new PickTarget(new Point3D(p), false, from.Map, this.m_Callback, this.m_State);
|
||||
}
|
||||
else if (from.Map != this.m_Map)
|
||||
{
|
||||
from.SendMessage("Both locations must reside on the same map.");
|
||||
}
|
||||
else if (this.m_Map != null && this.m_Map != Map.Internal && this.m_Callback != null)
|
||||
{
|
||||
Point3D start = this.m_Store;
|
||||
Point3D end = new Point3D(p);
|
||||
|
||||
Utility.FixPoints(ref start, ref end);
|
||||
|
||||
this.m_Callback(from, this.m_Map, start, end, this.m_State);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
647
Scripts/Commands/CreateWorld.cs
Normal file
647
Scripts/Commands/CreateWorld.cs
Normal file
@@ -0,0 +1,647 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Commands;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class CreateWorld
|
||||
{
|
||||
public enum GumpType
|
||||
{
|
||||
Create,
|
||||
Delete,
|
||||
Recreate,
|
||||
}
|
||||
|
||||
public enum Category
|
||||
{
|
||||
All,
|
||||
Decoration,
|
||||
Spawn,
|
||||
System,
|
||||
Dungeon,
|
||||
RevampedDungeon,
|
||||
Expansion
|
||||
}
|
||||
|
||||
public class CommandEntry
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string CreateCommand { get; set; }
|
||||
public string DeleteCommand { get; set; }
|
||||
public int CheckID { get; set; }
|
||||
public int Delay { get; set; }
|
||||
|
||||
public Category Category { get; set; }
|
||||
public Expansion RequiredExpansion { get; set; }
|
||||
|
||||
public CommandEntry(string n, string c, string d, Category cat, Expansion expansion, int i, int delay = 0)
|
||||
{
|
||||
Name = n;
|
||||
CreateCommand = c;
|
||||
DeleteCommand = d;
|
||||
Category = cat;
|
||||
RequiredExpansion = expansion;
|
||||
CheckID = i;
|
||||
Delay = delay;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<CommandEntry> Commands = new List<CommandEntry>(new CommandEntry[]
|
||||
{
|
||||
new CommandEntry("Moongates", "Moongen", "MoonGenDelete", Category.Decoration, Expansion.None, 101),
|
||||
new CommandEntry("Doors", "DoorGen", "DoorGenDelete", Category.Decoration, Expansion.None, 102),
|
||||
new CommandEntry("Signs", "SignGen", "SignGenDelete", Category.Decoration, Expansion.None, 103),
|
||||
new CommandEntry("Teleporters", "TelGen", "TelGenDelete", Category.Decoration, Expansion.None, 104),
|
||||
new CommandEntry("Doom Lamp", "GenLeverPuzzle", "LampPuzzleDelete", Category.System, Expansion.AOS, 105),
|
||||
new CommandEntry("Doom Gauntlet", "GenGauntlet", "DeleteGauntlet", Category.Dungeon, Expansion.AOS, 106),
|
||||
new CommandEntry("Khaldun", "GenKhaldun", "DeleteKhaldun", Category.Dungeon, Expansion.None, 107),
|
||||
new CommandEntry("Stealables", "GenStealArties", "RemoveStealArties", Category.Spawn, Expansion.AOS, 108),
|
||||
new CommandEntry("Solen Hives", "SHTelGen", "SHTelGenDelete", Category.Dungeon, Expansion.LBR, 109),
|
||||
new CommandEntry("Malas Secrets", "SecretLocGen", "SecretLocDelete", Category.System, Expansion.AOS, 110),
|
||||
new CommandEntry("Factions", "GenerateFactions", "DeleteFactions", Category.System, Expansion.None, 111),
|
||||
new CommandEntry("Decorations", "Decorate", "DecorateDelete", Category.Decoration, Expansion.None, 113),
|
||||
new CommandEntry("ML Decorations", "DecorateML", "DecorateMLDelete", Category.Decoration, Expansion.ML, 114),
|
||||
new CommandEntry("SA Decorations", "DecorateSA", "DecorateSADelete", Category.Decoration, Expansion.SA, 115),
|
||||
new CommandEntry("Spawners", "XmlLoad Spawns", "WipeAllXmlSpawners", Category.Spawn, Expansion.None, 116),
|
||||
new CommandEntry("New Despise", "SetupDespise", "DeleteDespise", Category.RevampedDungeon, Expansion.SA, 117),
|
||||
new CommandEntry("New Covetous", "SetupNewCovetous", "DeleteCovetous", Category.RevampedDungeon, Expansion.SA, 118),
|
||||
new CommandEntry("New Shame", "GenerateNewShame", "DeleteShame", Category.RevampedDungeon, Expansion.SA, 119),
|
||||
new CommandEntry("New Magincia", "GenNewMagincia", "DeleteNewMagincia", Category.Decoration, Expansion.None, 120),
|
||||
new CommandEntry("High Seas", "DecorateHS", "DeleteHS", Category.Expansion, Expansion.HS, 121),
|
||||
new CommandEntry("City Loyalty", "SetupCityLoyaltySystem","DeleteCityLoyaltySystem",Category.System, Expansion.SA, 122),
|
||||
new CommandEntry("Castle Blackthorn", "GenBlackthorn", null, Category.RevampedDungeon, Expansion.SA, 123),
|
||||
new CommandEntry("TOL Decorations", "DecorateTOL", null, Category.Decoration, Expansion.TOL, 124),
|
||||
new CommandEntry("New Wrong", "GenWrongRevamp", null, Category.RevampedDungeon, Expansion.SA, 125),
|
||||
new CommandEntry("Kotl City", "GenerateTreasuresOfKotlCity", null, Category.System, Expansion.TOL, 126),
|
||||
new CommandEntry("Fillable Containers", "CheckFillables", null, Category.Spawn, Expansion.None, 127, 5),
|
||||
new CommandEntry("Champ Spawns", "GenChampSpawns", "DelChampSpawns", Category.Spawn, Expansion.UOR, 128),
|
||||
});
|
||||
|
||||
public static bool WorldCreating { get; set; }
|
||||
|
||||
public CreateWorld()
|
||||
{
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Createworld", AccessLevel.Administrator, new CommandEventHandler(Create_OnCommand));
|
||||
CommandSystem.Register("DeleteWorld", AccessLevel.Administrator, new CommandEventHandler(Delete_OnCommand));
|
||||
CommandSystem.Register("RecreateWorld", AccessLevel.Administrator, new CommandEventHandler(Recreate_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("CreateWorld [nogump]")]
|
||||
[Description("Generates the world with a menu. If nogump argument is given, no gump will be displayed, all options will be assumed true, and the action will proceed immediately.")]
|
||||
private static void Create_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (String.IsNullOrEmpty(e.ArgString))
|
||||
{
|
||||
if (e.Mobile is PlayerMobile)
|
||||
BaseGump.SendGump(new NewCreateWorldGump((PlayerMobile)e.Mobile, GumpType.Create));
|
||||
else
|
||||
e.Mobile.SendGump(new CreateWorldGump(e, GumpType.Create));
|
||||
}
|
||||
else if (e.ArgString.ToLower().Equals("nogump"))
|
||||
{
|
||||
DoAllCommands(GumpType.Create, e.Mobile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Mobile != null)
|
||||
e.Mobile.SendMessage("Usage: CreateWorld [nogump]");
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("DeleteWorld [nogump]")]
|
||||
[Description("Undoes world generation with a menu. If nogump argument is given, no gump will be displayed, all options will be assumed true, and the action will proceed immediately.")]
|
||||
private static void Delete_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (String.IsNullOrEmpty(e.ArgString))
|
||||
{
|
||||
if (e.Mobile is PlayerMobile)
|
||||
BaseGump.SendGump(new NewCreateWorldGump((PlayerMobile)e.Mobile, GumpType.Delete));
|
||||
else
|
||||
e.Mobile.SendGump(new CreateWorldGump(e, GumpType.Delete));
|
||||
}
|
||||
else if (e.ArgString.ToLower().Equals("nogump"))
|
||||
{
|
||||
DoAllCommands(GumpType.Delete, e.Mobile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Mobile != null)
|
||||
e.Mobile.SendMessage("Usage: DeleteWorld [nogump]");
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("RecreateWorld [nogump]")]
|
||||
[Description("Re-generates the world with a menu. If nogump argument is given, no gump will be displayed, all options will be assumed true, and the action will proceed immediately.")]
|
||||
private static void Recreate_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (String.IsNullOrEmpty(e.ArgString))
|
||||
{
|
||||
e.Mobile.SendGump(new CreateWorldGump(e, GumpType.Recreate));
|
||||
}
|
||||
else if (e.ArgString.ToLower().Equals("nogump"))
|
||||
{
|
||||
DoAllCommands(GumpType.Recreate, e.Mobile);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e.Mobile != null)
|
||||
e.Mobile.SendMessage("Usage: RecreateWorld [nogump]");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void DoAllCommands(GumpType type, Mobile from)
|
||||
{
|
||||
List<int> ids = new List<int>();
|
||||
foreach (CommandEntry entry in Commands)
|
||||
{
|
||||
ids.Add(entry.CheckID);
|
||||
}
|
||||
DoCommands(ids.ToArray(), type, from);
|
||||
}
|
||||
|
||||
public static void DoCommands(int[] selections, GumpType type, Mobile from)
|
||||
{
|
||||
World.Broadcast(0x35, false, "The world is generating. This may take some time...");
|
||||
string prefix = Server.Commands.CommandSystem.Prefix;
|
||||
|
||||
string error = null;
|
||||
WorldCreating = true;
|
||||
|
||||
foreach (int sel in selections)
|
||||
{
|
||||
foreach (CreateWorld.CommandEntry entry in CreateWorld.Commands)
|
||||
{
|
||||
if (entry.CheckID == sel)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case CreateWorld.GumpType.Create:
|
||||
from.Say("Generating " + entry.Name);
|
||||
|
||||
if (CanGenerate(entry, ref error))
|
||||
{
|
||||
if (entry.Delay > 0)
|
||||
{
|
||||
DoDelayedCommand(from, TimeSpan.FromMinutes(entry.Delay), prefix + entry.CreateCommand);
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandSystem.Handle(from, prefix + entry.CreateCommand);
|
||||
}
|
||||
|
||||
if (CreateWorldData.CreateTable.ContainsKey(sel))
|
||||
CreateWorldData.CreateTable[sel] = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case CreateWorld.GumpType.Delete:
|
||||
if (!String.IsNullOrEmpty(entry.DeleteCommand))
|
||||
{
|
||||
from.Say("Deleting " + entry.Name);
|
||||
CommandSystem.Handle(from, prefix + entry.DeleteCommand);
|
||||
|
||||
if (CreateWorldData.CreateTable.ContainsKey(sel))
|
||||
CreateWorldData.CreateTable[sel] = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (error != null)
|
||||
{
|
||||
from.SendGump(new BasicInfoGump(error, "World Generation Error"));
|
||||
}
|
||||
|
||||
WorldCreating = false;
|
||||
World.Broadcast(0x35, false, "World generation complete.");
|
||||
}
|
||||
|
||||
public static bool CanGenerate(CommandEntry entry, ref string error)
|
||||
{
|
||||
if (CreateWorldData.CreateTable.ContainsKey(entry.CheckID) && CreateWorldData.CreateTable[entry.CheckID])
|
||||
{
|
||||
string er = String.Format("<br>- {0} have been generated already.", entry.Name);
|
||||
Console.WriteLine(er);
|
||||
|
||||
error += er;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.CheckID == 127)
|
||||
{
|
||||
if (CreateWorldData.HasGenerated(116) && CreateWorldData.HasGenerated(113))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
string er = String.Format("<br>- Cannot generate {0}. You need to generate Decorations and Spawners first.", entry.Name);
|
||||
Console.WriteLine(er);
|
||||
|
||||
error += er;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry.Category == Category.RevampedDungeon)
|
||||
{
|
||||
if (CreateWorldData.HasGenerated(116))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
string er = String.Format("<br>- Cannot generate {0}. You need to generate Spawners first.", entry.Name);
|
||||
Console.WriteLine(er);
|
||||
|
||||
error += er;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void DoDelayedCommand(Mobile from, TimeSpan delay, string command)
|
||||
{
|
||||
Console.WriteLine("Setting delayed create command: {0} [{1}] minutes", command, delay.TotalMinutes);
|
||||
|
||||
Timer.DelayCall(delay, () =>
|
||||
{
|
||||
CommandSystem.Handle(from, command);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class CreateWorldGump : Gump
|
||||
{
|
||||
private readonly CommandEventArgs m_CommandEventArgs;
|
||||
private CreateWorld.GumpType m_Type;
|
||||
|
||||
public CreateWorldGump(CommandEventArgs e, CreateWorld.GumpType type)
|
||||
: base(50,50)
|
||||
{
|
||||
m_Type = type;
|
||||
m_CommandEventArgs = e;
|
||||
Closable = true;
|
||||
Dragable = true;
|
||||
|
||||
AddPage(1);
|
||||
|
||||
int items = CreateWorld.Commands.Count;
|
||||
|
||||
if (!Server.Factions.Settings.Enabled)
|
||||
items--;
|
||||
|
||||
AddBackground(0, 0, 280, 75 + items * 25, 5054);
|
||||
switch (m_Type)
|
||||
{
|
||||
case CreateWorld.GumpType.Create:
|
||||
AddLabel(40, 2, 200, "CREATE WORLD GUMP");
|
||||
break;
|
||||
case CreateWorld.GumpType.Delete:
|
||||
AddLabel(40, 2, 200, "DELETE WORLD GUMP");
|
||||
break;
|
||||
case CreateWorld.GumpType.Recreate:
|
||||
AddLabel(40, 2, 200, "RECREATE WORLD GUMP");
|
||||
break;
|
||||
}
|
||||
|
||||
AddImageTiled(10, 20, 220, 10 + items * 25, 3004);
|
||||
int y = 25;
|
||||
|
||||
foreach(CreateWorld.CommandEntry entry in CreateWorld.Commands)
|
||||
{
|
||||
if (entry.Name == "Factions" && !Server.Factions.Settings.Enabled)
|
||||
continue;
|
||||
|
||||
bool created = CreateWorldData.CreateTable.ContainsKey(entry.CheckID) && CreateWorldData.CreateTable[entry.CheckID];
|
||||
|
||||
AddLabel(20, y + 1, created ? 200 : 338, String.Format("{0} {1}", entry.Name, created ? "[created]" : "[not created]"));
|
||||
AddCheck(210, y - 2, 210, 211, m_Type == CreateWorld.GumpType.Create ? !created : created, entry.CheckID);
|
||||
|
||||
y += 25;
|
||||
}
|
||||
|
||||
y = 25 + (items * 25);
|
||||
|
||||
AddButton(60, y + 15, 247, 249, 1, GumpButtonType.Reply, 0);
|
||||
AddButton(130, y + 15, 241, 243, 0, GumpButtonType.Reply, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState state, RelayInfo info)
|
||||
{
|
||||
Mobile from = state.Mobile;
|
||||
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 0: // Closed or Cancel
|
||||
return;
|
||||
case 1:
|
||||
CreateWorld.DoCommands(info.Switches, m_Type, from);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class NewCreateWorldGump : BaseGump
|
||||
{
|
||||
public CreateWorld.GumpType GumpType { get; set; }
|
||||
public CreateWorld.Category CategoryFilter { get; set; }
|
||||
|
||||
public bool CheckAll { get; set; }
|
||||
public bool UncheckAll { get; set; }
|
||||
|
||||
public NewCreateWorldGump(PlayerMobile pm, CreateWorld.GumpType type)
|
||||
: base(pm, 50, 50)
|
||||
{
|
||||
GumpType = type;
|
||||
}
|
||||
|
||||
public override void AddGumpLayout()
|
||||
{
|
||||
AddBackground(0, 0, 640, 500, 5054);
|
||||
|
||||
AddImageTiled(10, 10, 140, 28, 3004);
|
||||
AddImageTiled(152, 10, 478, 28, 3004);
|
||||
|
||||
AddImageTiled(10, 40, 140, 430, 3004);
|
||||
AddImageTiled(152, 40, 478, 430, 3004);
|
||||
|
||||
string label = GumpType == CreateWorld.GumpType.Create ? "CREATE WORLD GUMP" : "DELETE WORLD GUMP";
|
||||
switch (GumpType)
|
||||
{
|
||||
default:
|
||||
case CreateWorld.GumpType.Create:
|
||||
label = "CREATE WORLD GUMP";
|
||||
break;
|
||||
case CreateWorld.GumpType.Delete:
|
||||
label = "DELETE WORLD GUMP";
|
||||
break;
|
||||
}
|
||||
|
||||
AddHtml(152, 15, 450, 20, ColorAndCenter("#00FFFF", label), false, false);
|
||||
AddHtml(12, 15, 140, 20, ColorAndCenter("#696969", String.Format("Your Expansion: {0}", Core.Expansion.ToString())), false, false);
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
CreateWorld.Category cat = (CreateWorld.Category)i;
|
||||
int id = CategoryFilter == cat || CategoryFilter == CreateWorld.Category.All ? 4030 : 4029;
|
||||
|
||||
AddButton(12, 55 + (i * 25), id, id == 4030 ? 4029 : 4030, i + 500, GumpButtonType.Reply, 0);
|
||||
AddHtml(45, 55 + (i * 25), 100, 20, Color("#696969", cat.ToString()), false, false);
|
||||
}
|
||||
|
||||
List<CreateWorld.CommandEntry> commands = new List<CreateWorld.CommandEntry>(CreateWorld.Commands.Where(c =>
|
||||
CategoryFilter == CreateWorld.Category.All || CategoryFilter == c.Category));
|
||||
|
||||
int perpage = CreateWorld.Commands.Count / 2;
|
||||
int x = 154;
|
||||
int y = 55;
|
||||
|
||||
for (int i = 0; i < commands.Count; i++)
|
||||
{
|
||||
var entry = commands[i];
|
||||
bool created = CreateWorldData.CreateTable[entry.CheckID];
|
||||
bool meetsExpansion = entry.RequiredExpansion <= Core.Expansion;
|
||||
|
||||
bool check;
|
||||
|
||||
if (CheckAll)
|
||||
check = true;
|
||||
else if (UncheckAll)
|
||||
check = false;
|
||||
else
|
||||
check = GumpType == CreateWorld.GumpType.Create ? !created : created;
|
||||
|
||||
if (meetsExpansion)
|
||||
{
|
||||
AddLabel(x + 21, y, created ? 200 : 338, String.Format("{0} {1}", entry.Name, created ? "[created]" : "[not created]"));
|
||||
AddCheck(x, y - 2, 210, 211, check, entry.CheckID);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddLabel(x + 21, y, created ? 200 : 33, String.Format("{0} {1}", entry.Name, "[Wrong Expansion]"));
|
||||
AddImage(x, y - 2, 210);
|
||||
}
|
||||
|
||||
y += 20;
|
||||
|
||||
if (i == perpage)
|
||||
{
|
||||
x = 382;
|
||||
y = 55;
|
||||
}
|
||||
}
|
||||
|
||||
AddButton(154, 426, 4005, 4007, 2500, GumpButtonType.Reply, 0);
|
||||
AddHtml(187, 426, 150, 20, Color("#696969", "Check All"), false, false);
|
||||
|
||||
AddButton(154, 448, 4017, 4019, 2501, GumpButtonType.Reply, 0);
|
||||
AddHtml(187, 448, 150, 20, Color("#696969", "Uncheck All"), false, false);
|
||||
|
||||
AddButton(260, 473, 247, 249, 1, GumpButtonType.Reply, 0);
|
||||
AddButton(323, 473, 241, 243, 0, GumpButtonType.Reply, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(RelayInfo info)
|
||||
{
|
||||
switch (info.ButtonID)
|
||||
{
|
||||
case 0: // Closed or Cancel
|
||||
return;
|
||||
case 1:
|
||||
CreateWorld.DoCommands(info.Switches, GumpType, User);
|
||||
break;
|
||||
case 2500:
|
||||
CheckAll = true;
|
||||
UncheckAll = false;
|
||||
Refresh();
|
||||
break;
|
||||
case 2501:
|
||||
CheckAll = false;
|
||||
UncheckAll = true;
|
||||
Refresh();
|
||||
break;
|
||||
default:
|
||||
int id = info.ButtonID - 500;
|
||||
|
||||
if (id >= 0 && id <= 6)
|
||||
{
|
||||
CategoryFilter = (CreateWorld.Category)id;
|
||||
}
|
||||
|
||||
Refresh();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CreateWorldData
|
||||
{
|
||||
public static Dictionary<int, bool> CreateTable { get; set; }
|
||||
|
||||
public static bool HasGenerated(int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 101:
|
||||
return PublicMoongate.Moongates.Count > 0;
|
||||
case 102:
|
||||
return WeakEntityCollection.HasCollection("door");
|
||||
case 103:
|
||||
return WeakEntityCollection.HasCollection("sign");
|
||||
case 104:
|
||||
return WeakEntityCollection.HasCollection("tel");
|
||||
case 105:
|
||||
return WeakEntityCollection.HasCollection("LeverPuzzleController");
|
||||
case 106:
|
||||
return WeakEntityCollection.HasCollection("doom");
|
||||
case 107:
|
||||
return WeakEntityCollection.HasCollection("khaldun");
|
||||
case 108:
|
||||
return StealableArtifactsSpawner.Instance != null;
|
||||
case 109:
|
||||
return SHTeleporter.SHTeleporterCreator.FindSHTeleporter(Map.Trammel, new Point3D(5747, 1895, 0)) != null;
|
||||
case 110:
|
||||
return WeakEntityCollection.HasCollection("malas");
|
||||
case 111:
|
||||
return WeakEntityCollection.HasCollection("factions");
|
||||
case 113:
|
||||
return WeakEntityCollection.HasCollection("deco");
|
||||
case 114:
|
||||
return WeakEntityCollection.HasCollection("ml");
|
||||
case 115:
|
||||
return WeakEntityCollection.HasCollection("sa");
|
||||
case 116:
|
||||
return World.Items.Values.Where(i => i != null && (i is XmlSpawner || i is Spawner)).Count() > 1000;
|
||||
case 117:
|
||||
return WeakEntityCollection.HasCollection("despise");
|
||||
case 118:
|
||||
return WeakEntityCollection.HasCollection("newcovetous");
|
||||
case 119:
|
||||
return WeakEntityCollection.HasCollection("newshame");
|
||||
case 120:
|
||||
return Server.Engines.NewMagincia.MaginciaBazaar.Instance != null;
|
||||
case 121:
|
||||
return WeakEntityCollection.HasCollection("highseas") || CharydbisSpawner.SpawnInstance != null;
|
||||
case 122:
|
||||
return Server.Engines.CityLoyalty.CityLoyaltySystem.Cities != null && Server.Engines.CityLoyalty.CityLoyaltySystem.Cities.Count > 0 && Server.Engines.CityLoyalty.CityLoyaltySystem.Cities[0].Stone != null;
|
||||
case 123:
|
||||
return HasItem(typeof(DungeonHitchingPost), new Point3D(6428, 2677, 0), Map.Trammel) &&
|
||||
HasItem(typeof(DungeonHitchingPost), new Point3D(6428, 2677, 0), Map.Felucca);
|
||||
case 124:
|
||||
return WeakEntityCollection.HasCollection("tol");
|
||||
case 125:
|
||||
return BedrollSpawner.Instances != null && BedrollSpawner.Instances.Count > 0;
|
||||
case 126:
|
||||
return Server.Engines.TreasuresOfKotlCity.KotlBattleSimulator.Instance != null;
|
||||
case 128:
|
||||
return Server.Engines.CannedEvil.ChampionSystem.AllSpawns.Count > 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool HasItem(Type type, Point3D p, Map map)
|
||||
{
|
||||
IPooledEnumerable eable = map.GetItemsInRange(p, 0);
|
||||
|
||||
foreach (Item item in eable)
|
||||
{
|
||||
if (item.GetType() == type)
|
||||
{
|
||||
eable.Free();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!_HasRan)
|
||||
{
|
||||
CreateTable = new Dictionary<int, bool>();
|
||||
|
||||
foreach (CreateWorld.CommandEntry entry in CreateWorld.Commands)
|
||||
{
|
||||
CreateTable[entry.CheckID] = HasGenerated(entry.CheckID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly string FilePath = Path.Combine("Saves/Misc", "Persistence.bin");
|
||||
private static bool _HasRan;
|
||||
|
||||
public static void Configure()
|
||||
{
|
||||
EventSink.WorldSave += OnSave;
|
||||
EventSink.WorldLoad += OnLoad;
|
||||
}
|
||||
|
||||
public static void OnSave(WorldSaveEventArgs e)
|
||||
{
|
||||
Persistence.Serialize(
|
||||
FilePath,
|
||||
writer =>
|
||||
{
|
||||
writer.Write(1);
|
||||
writer.Write(true);
|
||||
|
||||
writer.Write(CreateTable.Count);
|
||||
foreach (var kvp in CreateTable)
|
||||
{
|
||||
writer.Write(kvp.Key);
|
||||
writer.Write(kvp.Value);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void OnLoad()
|
||||
{
|
||||
Persistence.Deserialize(
|
||||
FilePath,
|
||||
reader =>
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
_HasRan = reader.ReadBool();
|
||||
|
||||
CreateTable = new Dictionary<int, bool>();
|
||||
|
||||
int count = reader.ReadInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
CreateTable[reader.ReadInt()] = reader.ReadBool();
|
||||
}
|
||||
|
||||
if (version == 0)
|
||||
{
|
||||
CreateTable[128] = HasGenerated(128);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
1417
Scripts/Commands/Decorate.cs
Normal file
1417
Scripts/Commands/Decorate.cs
Normal file
File diff suppressed because it is too large
Load Diff
1377
Scripts/Commands/DecorateDelete.cs
Normal file
1377
Scripts/Commands/DecorateDelete.cs
Normal file
File diff suppressed because it is too large
Load Diff
1154
Scripts/Commands/DecorateMag.cs
Normal file
1154
Scripts/Commands/DecorateMag.cs
Normal file
File diff suppressed because it is too large
Load Diff
47
Scripts/Commands/DecorateSA.cs
Normal file
47
Scripts/Commands/DecorateSA.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using Server.Commands;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class StygianAbyss
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("DecorateSA", AccessLevel.Administrator, new CommandEventHandler(DecorateSA_OnCommand));
|
||||
CommandSystem.Register("DecorateSADelete", AccessLevel.Administrator, new CommandEventHandler(DecorateSADelete_OnCommand));
|
||||
}
|
||||
[Usage("DecorateSADelete")]
|
||||
[Description("Deletes Stygian Abyss world decoration.")]
|
||||
private static void DecorateSADelete_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
WeakEntityCollection.Delete("sa");
|
||||
|
||||
Server.Engines.ExploringTheDeep.GenerateExploringTheDeep.Delete(e);
|
||||
|
||||
SpawnerPersistence.RemoveSpawnsFromXmlFile("Spawns", "GravewaterLake");
|
||||
}
|
||||
|
||||
[Usage("DecorateSA")]
|
||||
[Description("Generates Stygian Abyss world decoration.")]
|
||||
private static void DecorateSA_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
e.Mobile.SendMessage("Generating Stygian Abyss world decoration, please wait.");
|
||||
|
||||
Decorate.Generate("sa", "Data/Decoration/Stygian Abyss/Ter Mur", Map.TerMur);
|
||||
Decorate.Generate("sa", "Data/Decoration/Stygian Abyss/Trammel", Map.Trammel);
|
||||
Decorate.Generate("sa", "Data/Decoration/Stygian Abyss/Felucca", Map.Felucca);
|
||||
|
||||
NavreysController.GenNavery(e.Mobile);
|
||||
CommandSystem.Handle(e.Mobile, Server.Commands.CommandSystem.Prefix + "GenToK");
|
||||
CommandSystem.Handle(e.Mobile, Server.Commands.CommandSystem.Prefix + "GenSutek");
|
||||
|
||||
GenerateUnderworldRooms.Generate();
|
||||
|
||||
Server.Engines.ResortAndCasino.FireCasinoGenerator.Generate(e);
|
||||
Server.Engines.ExploringTheDeep.GenerateExploringTheDeep.Generate(e);
|
||||
|
||||
e.Mobile.SendMessage("Stygian Abyss world generation complete.");
|
||||
}
|
||||
}
|
||||
}
|
||||
3158
Scripts/Commands/Docs.cs
Normal file
3158
Scripts/Commands/Docs.cs
Normal file
File diff suppressed because it is too large
Load Diff
563
Scripts/Commands/DoorGenDelete.cs
Normal file
563
Scripts/Commands/DoorGenDelete.cs
Normal file
@@ -0,0 +1,563 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Commands;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class DoorGeneratorDelete
|
||||
{
|
||||
private static readonly Rectangle2D[] m_BritRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)),
|
||||
new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)),
|
||||
new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)),
|
||||
new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)),
|
||||
new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)),
|
||||
new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)),
|
||||
new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)),
|
||||
new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)),
|
||||
new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)),
|
||||
new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)),
|
||||
new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)),
|
||||
new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)),
|
||||
new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)),
|
||||
new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)),
|
||||
new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)),
|
||||
new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095))
|
||||
};
|
||||
private static readonly Rectangle2D[] m_IlshRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8))
|
||||
};
|
||||
private static readonly Rectangle2D[] m_MalasRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(0, 0), new Point2D(320 * 8, 256 * 8))
|
||||
};
|
||||
private static readonly int[] m_SouthFrames = new int[]
|
||||
{
|
||||
0x0006,
|
||||
0x0008,
|
||||
0x000B,
|
||||
0x001A,
|
||||
0x001B,
|
||||
0x001F,
|
||||
0x0038,
|
||||
0x0057,
|
||||
0x0059,
|
||||
0x005B,
|
||||
0x005D,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0091,
|
||||
0x0094,
|
||||
0x0096,
|
||||
0x0099,
|
||||
0x00A6,
|
||||
0x00A7,
|
||||
0x00AA,
|
||||
0x00AE,
|
||||
0x00B0,
|
||||
0x00B3,
|
||||
0x00C7,
|
||||
0x00C9,
|
||||
0x00F8,
|
||||
0x00FA,
|
||||
0x00FD,
|
||||
0x00FE,
|
||||
0x0100,
|
||||
0x0103,
|
||||
0x0104,
|
||||
0x0106,
|
||||
0x0109,
|
||||
0x0127,
|
||||
0x0129,
|
||||
0x012B,
|
||||
0x012D,
|
||||
0x012F,
|
||||
0x0131,
|
||||
0x0132,
|
||||
0x0134,
|
||||
0x0135,
|
||||
0x0137,
|
||||
0x0139,
|
||||
0x013B,
|
||||
0x014C,
|
||||
0x014E,
|
||||
0x014F,
|
||||
0x0151,
|
||||
0x0153,
|
||||
0x0155,
|
||||
0x0157,
|
||||
0x0158,
|
||||
0x015A,
|
||||
0x015D,
|
||||
0x015E,
|
||||
0x015F,
|
||||
0x0162,
|
||||
0x01CF,
|
||||
0x01D1,
|
||||
0x01D4,
|
||||
0x01FF,
|
||||
0x0204,
|
||||
0x0206,
|
||||
0x0208,
|
||||
0x020A
|
||||
};
|
||||
private static readonly int[] m_NorthFrames = new int[]
|
||||
{
|
||||
0x0006,
|
||||
0x0008,
|
||||
0x000D,
|
||||
0x001A,
|
||||
0x001B,
|
||||
0x0020,
|
||||
0x003A,
|
||||
0x0057,
|
||||
0x0059,
|
||||
0x005B,
|
||||
0x005D,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0091,
|
||||
0x0094,
|
||||
0x0096,
|
||||
0x0099,
|
||||
0x00A6,
|
||||
0x00A7,
|
||||
0x00AC,
|
||||
0x00AE,
|
||||
0x00B0,
|
||||
0x00C7,
|
||||
0x00C9,
|
||||
0x00F8,
|
||||
0x00FA,
|
||||
0x00FD,
|
||||
0x00FE,
|
||||
0x0100,
|
||||
0x0103,
|
||||
0x0104,
|
||||
0x0106,
|
||||
0x0109,
|
||||
0x0127,
|
||||
0x0129,
|
||||
0x012B,
|
||||
0x012D,
|
||||
0x012F,
|
||||
0x0131,
|
||||
0x0132,
|
||||
0x0134,
|
||||
0x0135,
|
||||
0x0137,
|
||||
0x0139,
|
||||
0x013B,
|
||||
0x014C,
|
||||
0x014E,
|
||||
0x014F,
|
||||
0x0151,
|
||||
0x0153,
|
||||
0x0155,
|
||||
0x0157,
|
||||
0x0158,
|
||||
0x015A,
|
||||
0x015D,
|
||||
0x015E,
|
||||
0x015F,
|
||||
0x0162,
|
||||
0x01CF,
|
||||
0x01D1,
|
||||
0x01D4,
|
||||
0x01FF,
|
||||
0x0201,
|
||||
0x0204,
|
||||
0x0208,
|
||||
0x020A
|
||||
};
|
||||
private static readonly int[] m_EastFrames = new int[]
|
||||
{
|
||||
0x0007,
|
||||
0x000A,
|
||||
0x001A,
|
||||
0x001C,
|
||||
0x001E,
|
||||
0x0037,
|
||||
0x0058,
|
||||
0x0059,
|
||||
0x005C,
|
||||
0x005E,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0092,
|
||||
0x0095,
|
||||
0x0097,
|
||||
0x0098,
|
||||
0x00A6,
|
||||
0x00A8,
|
||||
0x00AB,
|
||||
0x00AE,
|
||||
0x00AF,
|
||||
0x00B2,
|
||||
0x00C7,
|
||||
0x00C8,
|
||||
0x00EA,
|
||||
0x00F8,
|
||||
0x00F9,
|
||||
0x00FC,
|
||||
0x00FE,
|
||||
0x00FF,
|
||||
0x0102,
|
||||
0x0104,
|
||||
0x0105,
|
||||
0x0108,
|
||||
0x0127,
|
||||
0x0128,
|
||||
0x012B,
|
||||
0x012C,
|
||||
0x012E,
|
||||
0x0130,
|
||||
0x0132,
|
||||
0x0133,
|
||||
0x0135,
|
||||
0x0136,
|
||||
0x0138,
|
||||
0x013A,
|
||||
0x014C,
|
||||
0x014D,
|
||||
0x014F,
|
||||
0x0150,
|
||||
0x0152,
|
||||
0x0154,
|
||||
0x0156,
|
||||
0x0158,
|
||||
0x0159,
|
||||
0x015C,
|
||||
0x015E,
|
||||
0x0160,
|
||||
0x0163,
|
||||
0x01CF,
|
||||
0x01D0,
|
||||
0x01D3,
|
||||
0x01FF,
|
||||
0x0203,
|
||||
0x0205,
|
||||
0x0207,
|
||||
0x0209
|
||||
};
|
||||
private static readonly int[] m_WestFrames = new int[]
|
||||
{
|
||||
0x0007,
|
||||
0x000C,
|
||||
0x001A,
|
||||
0x001C,
|
||||
0x0021,
|
||||
0x0039,
|
||||
0x0058,
|
||||
0x0059,
|
||||
0x005C,
|
||||
0x005E,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0092,
|
||||
0x0095,
|
||||
0x0097,
|
||||
0x0098,
|
||||
0x00A6,
|
||||
0x00A8,
|
||||
0x00AD,
|
||||
0x00AE,
|
||||
0x00AF,
|
||||
0x00B5,
|
||||
0x00C7,
|
||||
0x00C8,
|
||||
0x00EA,
|
||||
0x00F8,
|
||||
0x00F9,
|
||||
0x00FC,
|
||||
0x00FE,
|
||||
0x00FF,
|
||||
0x0102,
|
||||
0x0104,
|
||||
0x0105,
|
||||
0x0108,
|
||||
0x0127,
|
||||
0x0128,
|
||||
0x012C,
|
||||
0x012E,
|
||||
0x0130,
|
||||
0x0132,
|
||||
0x0133,
|
||||
0x0135,
|
||||
0x0136,
|
||||
0x0138,
|
||||
0x013A,
|
||||
0x014C,
|
||||
0x014D,
|
||||
0x014F,
|
||||
0x0150,
|
||||
0x0152,
|
||||
0x0154,
|
||||
0x0156,
|
||||
0x0158,
|
||||
0x0159,
|
||||
0x015C,
|
||||
0x015E,
|
||||
0x0160,
|
||||
0x0163,
|
||||
0x01CF,
|
||||
0x01D0,
|
||||
0x01D3,
|
||||
0x01FF,
|
||||
0x0200,
|
||||
0x0203,
|
||||
0x0207,
|
||||
0x0209
|
||||
};
|
||||
private static Map m_Map;
|
||||
private static int m_Count;
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("DoorGenDelete", AccessLevel.Administrator, new CommandEventHandler(DoorGenDelete_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("DoorGenDelete")]
|
||||
[Description("Deletes doors by analyzing the map.")]
|
||||
public static void DoorGenDelete_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
WeakEntityCollection.Delete("door");
|
||||
// Retained for backward compatibility
|
||||
Delete();
|
||||
}
|
||||
|
||||
public static void Delete()
|
||||
{
|
||||
World.Broadcast(0x35, true, "Deleting doors, please wait.");
|
||||
|
||||
Network.NetState.FlushAll();
|
||||
Network.NetState.Pause();
|
||||
|
||||
m_Map = Map.Trammel;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_BritRegions.Length; ++i)
|
||||
Delete(m_BritRegions[i]);
|
||||
|
||||
int trammelCount = m_Count;
|
||||
|
||||
m_Map = Map.Felucca;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_BritRegions.Length; ++i)
|
||||
Delete(m_BritRegions[i]);
|
||||
|
||||
int feluccaCount = m_Count;
|
||||
|
||||
m_Map = Map.Ilshenar;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_IlshRegions.Length; ++i)
|
||||
Delete(m_IlshRegions[i]);
|
||||
|
||||
int ilshenarCount = m_Count;
|
||||
|
||||
m_Map = Map.Malas;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_MalasRegions.Length; ++i)
|
||||
Delete(m_MalasRegions[i]);
|
||||
|
||||
int malasCount = m_Count;
|
||||
|
||||
Network.NetState.Resume();
|
||||
|
||||
World.Broadcast(0x35, true, "Door deletion complete. Trammel: {0}; Felucca: {1}; Ilshenar: {2}; Malas: {3};", trammelCount, feluccaCount, ilshenarCount, malasCount);
|
||||
}
|
||||
|
||||
public static void DeleteDoor(int x, int y, int z)
|
||||
{
|
||||
int doorZ = z;
|
||||
int doorTop = doorZ + 20;
|
||||
|
||||
m_Count += DeleteBaseDoor(m_Map, new Point3D(x, y, z));
|
||||
}
|
||||
|
||||
public static void Delete(Rectangle2D region)
|
||||
{
|
||||
for (int rx = 0; rx < region.Width; ++rx)
|
||||
{
|
||||
for (int ry = 0; ry < region.Height; ++ry)
|
||||
{
|
||||
int vx = rx + region.X;
|
||||
int vy = ry + region.Y;
|
||||
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(vx, vy);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
int id = tile.ID;
|
||||
int z = tile.Z;
|
||||
|
||||
if (IsWestFrame(id))
|
||||
{
|
||||
if (IsEastFrame(vx + 2, vy, z))
|
||||
{
|
||||
DeleteDoor(vx + 1, vy, z);
|
||||
}
|
||||
else if (IsEastFrame(vx + 3, vy, z))
|
||||
{
|
||||
/*BaseDoor first = */DeleteDoor(vx + 1, vy, z);
|
||||
/*BaseDoor second = */DeleteDoor(vx + 2, vy, z);
|
||||
/*if (first != null && second != null)
|
||||
{
|
||||
first.Link = second;
|
||||
second.Link = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first != null)
|
||||
first.Delete();
|
||||
if (second != null)
|
||||
second.Delete();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
else if (IsNorthFrame(id))
|
||||
{
|
||||
if (IsSouthFrame(vx, vy + 2, z))
|
||||
{
|
||||
DeleteDoor(vx, vy + 1, z);
|
||||
}
|
||||
else if (IsSouthFrame(vx, vy + 3, z))
|
||||
{
|
||||
/*BaseDoor first = */DeleteDoor(vx, vy + 1, z);
|
||||
/*BaseDoor second = */DeleteDoor(vx, vy + 2, z);
|
||||
/*if (first != null && second != null)
|
||||
{
|
||||
first.Link = second;
|
||||
second.Link = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first != null)
|
||||
first.Delete();
|
||||
if (second != null)
|
||||
second.Delete();
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsFrame(int id, int[] list)
|
||||
{
|
||||
id &= 0x3FFF;
|
||||
|
||||
if (id > list[list.Length - 1])
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list.Length; ++i)
|
||||
{
|
||||
int delta = id - list[i];
|
||||
|
||||
if (delta < 0)
|
||||
return false;
|
||||
else if (delta == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsNorthFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_NorthFrames);
|
||||
}
|
||||
|
||||
public static bool IsSouthFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_SouthFrames);
|
||||
}
|
||||
|
||||
public static bool IsWestFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_WestFrames);
|
||||
}
|
||||
|
||||
public static bool IsEastFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_EastFrames);
|
||||
}
|
||||
|
||||
public static bool IsEastFrame(int x, int y, int z)
|
||||
{
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
if (tile.Z == z && IsEastFrame(tile.ID))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsSouthFrame(int x, int y, int z)
|
||||
{
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
if (tile.Z == z && IsSouthFrame(tile.ID))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int DeleteBaseDoor(Map map, Point3D p)
|
||||
{
|
||||
Queue<Item> m_Queue = new Queue<Item>();
|
||||
|
||||
IPooledEnumerable eable = map.GetItemsInRange(p, 0);
|
||||
|
||||
foreach (Item item in eable)
|
||||
{
|
||||
if (item is BaseDoor)
|
||||
{
|
||||
int delta = item.Z - p.Z;
|
||||
|
||||
if (delta >= -12 && delta <= 12)
|
||||
m_Queue.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
int count = m_Queue.Count;
|
||||
|
||||
while (m_Queue.Count > 0)
|
||||
(m_Queue.Dequeue()).Delete();
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
556
Scripts/Commands/DoorGenerator.cs
Normal file
556
Scripts/Commands/DoorGenerator.cs
Normal file
@@ -0,0 +1,556 @@
|
||||
using System;
|
||||
using Server.Commands;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class DoorGenerator
|
||||
{
|
||||
private static readonly Rectangle2D[] m_BritRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(250, 750), new Point2D(775, 1330)),
|
||||
new Rectangle2D(new Point2D(525, 2095), new Point2D(925, 2430)),
|
||||
new Rectangle2D(new Point2D(1025, 2155), new Point2D(1265, 2310)),
|
||||
new Rectangle2D(new Point2D(1635, 2430), new Point2D(1705, 2508)),
|
||||
new Rectangle2D(new Point2D(1775, 2605), new Point2D(2165, 2975)),
|
||||
new Rectangle2D(new Point2D(1055, 3520), new Point2D(1570, 4075)),
|
||||
new Rectangle2D(new Point2D(2860, 3310), new Point2D(3120, 3630)),
|
||||
new Rectangle2D(new Point2D(2470, 1855), new Point2D(3950, 3045)),
|
||||
new Rectangle2D(new Point2D(3425, 990), new Point2D(3900, 1455)),
|
||||
new Rectangle2D(new Point2D(4175, 735), new Point2D(4840, 1600)),
|
||||
new Rectangle2D(new Point2D(2375, 330), new Point2D(3100, 1045)),
|
||||
new Rectangle2D(new Point2D(2100, 1090), new Point2D(2310, 1450)),
|
||||
new Rectangle2D(new Point2D(1495, 1400), new Point2D(1550, 1475)),
|
||||
new Rectangle2D(new Point2D(1085, 1520), new Point2D(1415, 1910)),
|
||||
new Rectangle2D(new Point2D(1410, 1500), new Point2D(1745, 1795)),
|
||||
new Rectangle2D(new Point2D(5120, 2300), new Point2D(6143, 4095))
|
||||
};
|
||||
private static readonly Rectangle2D[] m_IlshRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(0, 0), new Point2D(288 * 8, 200 * 8))
|
||||
};
|
||||
private static readonly Rectangle2D[] m_MalasRegions = new Rectangle2D[]
|
||||
{
|
||||
new Rectangle2D(new Point2D(0, 0), new Point2D(320 * 8, 256 * 8))
|
||||
};
|
||||
private static readonly int[] m_SouthFrames = new int[]
|
||||
{
|
||||
0x0006,
|
||||
0x0008,
|
||||
0x000B,
|
||||
0x001A,
|
||||
0x001B,
|
||||
0x001F,
|
||||
0x0038,
|
||||
0x0057,
|
||||
0x0059,
|
||||
0x005B,
|
||||
0x005D,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0091,
|
||||
0x0094,
|
||||
0x0096,
|
||||
0x0099,
|
||||
0x00A6,
|
||||
0x00A7,
|
||||
0x00AA,
|
||||
0x00AE,
|
||||
0x00B0,
|
||||
0x00B3,
|
||||
0x00C7,
|
||||
0x00C9,
|
||||
0x00F8,
|
||||
0x00FA,
|
||||
0x00FD,
|
||||
0x00FE,
|
||||
0x0100,
|
||||
0x0103,
|
||||
0x0104,
|
||||
0x0106,
|
||||
0x0109,
|
||||
0x0127,
|
||||
0x0129,
|
||||
0x012B,
|
||||
0x012D,
|
||||
0x012F,
|
||||
0x0131,
|
||||
0x0132,
|
||||
0x0134,
|
||||
0x0135,
|
||||
0x0137,
|
||||
0x0139,
|
||||
0x013B,
|
||||
0x014C,
|
||||
0x014E,
|
||||
0x014F,
|
||||
0x0151,
|
||||
0x0153,
|
||||
0x0155,
|
||||
0x0157,
|
||||
0x0158,
|
||||
0x015A,
|
||||
0x015D,
|
||||
0x015E,
|
||||
0x015F,
|
||||
0x0162,
|
||||
0x01CF,
|
||||
0x01D1,
|
||||
0x01D4,
|
||||
0x01FF,
|
||||
0x0204,
|
||||
0x0206,
|
||||
0x0208,
|
||||
0x020A
|
||||
};
|
||||
private static readonly int[] m_NorthFrames = new int[]
|
||||
{
|
||||
0x0006,
|
||||
0x0008,
|
||||
0x000D,
|
||||
0x001A,
|
||||
0x001B,
|
||||
0x0020,
|
||||
0x003A,
|
||||
0x0057,
|
||||
0x0059,
|
||||
0x005B,
|
||||
0x005D,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0091,
|
||||
0x0094,
|
||||
0x0096,
|
||||
0x0099,
|
||||
0x00A6,
|
||||
0x00A7,
|
||||
0x00AC,
|
||||
0x00AE,
|
||||
0x00B0,
|
||||
0x00C7,
|
||||
0x00C9,
|
||||
0x00F8,
|
||||
0x00FA,
|
||||
0x00FD,
|
||||
0x00FE,
|
||||
0x0100,
|
||||
0x0103,
|
||||
0x0104,
|
||||
0x0106,
|
||||
0x0109,
|
||||
0x0127,
|
||||
0x0129,
|
||||
0x012B,
|
||||
0x012D,
|
||||
0x012F,
|
||||
0x0131,
|
||||
0x0132,
|
||||
0x0134,
|
||||
0x0135,
|
||||
0x0137,
|
||||
0x0139,
|
||||
0x013B,
|
||||
0x014C,
|
||||
0x014E,
|
||||
0x014F,
|
||||
0x0151,
|
||||
0x0153,
|
||||
0x0155,
|
||||
0x0157,
|
||||
0x0158,
|
||||
0x015A,
|
||||
0x015D,
|
||||
0x015E,
|
||||
0x015F,
|
||||
0x0162,
|
||||
0x01CF,
|
||||
0x01D1,
|
||||
0x01D4,
|
||||
0x01FF,
|
||||
0x0201,
|
||||
0x0204,
|
||||
0x0208,
|
||||
0x020A
|
||||
};
|
||||
private static readonly int[] m_EastFrames = new int[]
|
||||
{
|
||||
0x0007,
|
||||
0x000A,
|
||||
0x001A,
|
||||
0x001C,
|
||||
0x001E,
|
||||
0x0037,
|
||||
0x0058,
|
||||
0x0059,
|
||||
0x005C,
|
||||
0x005E,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0092,
|
||||
0x0095,
|
||||
0x0097,
|
||||
0x0098,
|
||||
0x00A6,
|
||||
0x00A8,
|
||||
0x00AB,
|
||||
0x00AE,
|
||||
0x00AF,
|
||||
0x00B2,
|
||||
0x00C7,
|
||||
0x00C8,
|
||||
0x00EA,
|
||||
0x00F8,
|
||||
0x00F9,
|
||||
0x00FC,
|
||||
0x00FE,
|
||||
0x00FF,
|
||||
0x0102,
|
||||
0x0104,
|
||||
0x0105,
|
||||
0x0108,
|
||||
0x0127,
|
||||
0x0128,
|
||||
0x012B,
|
||||
0x012C,
|
||||
0x012E,
|
||||
0x0130,
|
||||
0x0132,
|
||||
0x0133,
|
||||
0x0135,
|
||||
0x0136,
|
||||
0x0138,
|
||||
0x013A,
|
||||
0x014C,
|
||||
0x014D,
|
||||
0x014F,
|
||||
0x0150,
|
||||
0x0152,
|
||||
0x0154,
|
||||
0x0156,
|
||||
0x0158,
|
||||
0x0159,
|
||||
0x015C,
|
||||
0x015E,
|
||||
0x0160,
|
||||
0x0163,
|
||||
0x01CF,
|
||||
0x01D0,
|
||||
0x01D3,
|
||||
0x01FF,
|
||||
0x0203,
|
||||
0x0205,
|
||||
0x0207,
|
||||
0x0209
|
||||
};
|
||||
private static readonly int[] m_WestFrames = new int[]
|
||||
{
|
||||
0x0007,
|
||||
0x000C,
|
||||
0x001A,
|
||||
0x001C,
|
||||
0x0021,
|
||||
0x0039,
|
||||
0x0058,
|
||||
0x0059,
|
||||
0x005C,
|
||||
0x005E,
|
||||
0x0080,
|
||||
0x0081,
|
||||
0x0082,
|
||||
0x0084,
|
||||
0x0090,
|
||||
0x0092,
|
||||
0x0095,
|
||||
0x0097,
|
||||
0x0098,
|
||||
0x00A6,
|
||||
0x00A8,
|
||||
0x00AD,
|
||||
0x00AE,
|
||||
0x00AF,
|
||||
0x00B5,
|
||||
0x00C7,
|
||||
0x00C8,
|
||||
0x00EA,
|
||||
0x00F8,
|
||||
0x00F9,
|
||||
0x00FC,
|
||||
0x00FE,
|
||||
0x00FF,
|
||||
0x0102,
|
||||
0x0104,
|
||||
0x0105,
|
||||
0x0108,
|
||||
0x0127,
|
||||
0x0128,
|
||||
0x012C,
|
||||
0x012E,
|
||||
0x0130,
|
||||
0x0132,
|
||||
0x0133,
|
||||
0x0135,
|
||||
0x0136,
|
||||
0x0138,
|
||||
0x013A,
|
||||
0x014C,
|
||||
0x014D,
|
||||
0x014F,
|
||||
0x0150,
|
||||
0x0152,
|
||||
0x0154,
|
||||
0x0156,
|
||||
0x0158,
|
||||
0x0159,
|
||||
0x015C,
|
||||
0x015E,
|
||||
0x0160,
|
||||
0x0163,
|
||||
0x01CF,
|
||||
0x01D0,
|
||||
0x01D3,
|
||||
0x01FF,
|
||||
0x0200,
|
||||
0x0203,
|
||||
0x0207,
|
||||
0x0209
|
||||
};
|
||||
private static Map m_Map;
|
||||
private static int m_Count;
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("DoorGen", AccessLevel.Administrator, new CommandEventHandler(DoorGen_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("DoorGen")]
|
||||
[Description("Generates doors by analyzing the map. Slow.")]
|
||||
public static void DoorGen_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
Generate();
|
||||
}
|
||||
|
||||
public static void Generate()
|
||||
{
|
||||
World.Broadcast(0x35, true, "Generating doors, please wait.");
|
||||
|
||||
Network.NetState.FlushAll();
|
||||
Network.NetState.Pause();
|
||||
|
||||
m_Map = Map.Trammel;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_BritRegions.Length; ++i)
|
||||
Generate(m_BritRegions[i]);
|
||||
|
||||
int trammelCount = m_Count;
|
||||
|
||||
m_Map = Map.Felucca;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_BritRegions.Length; ++i)
|
||||
Generate(m_BritRegions[i]);
|
||||
|
||||
int feluccaCount = m_Count;
|
||||
|
||||
m_Map = Map.Ilshenar;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_IlshRegions.Length; ++i)
|
||||
Generate(m_IlshRegions[i]);
|
||||
|
||||
int ilshenarCount = m_Count;
|
||||
|
||||
m_Map = Map.Malas;
|
||||
m_Count = 0;
|
||||
|
||||
for (int i = 0; i < m_MalasRegions.Length; ++i)
|
||||
Generate(m_MalasRegions[i]);
|
||||
|
||||
int malasCount = m_Count;
|
||||
|
||||
Network.NetState.Resume();
|
||||
|
||||
World.Broadcast(0x35, true, "Door generation complete. Trammel: {0}; Felucca: {1}; Ilshenar: {2}; Malas: {3};", trammelCount, feluccaCount, ilshenarCount, malasCount);
|
||||
}
|
||||
|
||||
public static bool IsFrame(int id, int[] list)
|
||||
{
|
||||
if (id > list[list.Length - 1])
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < list.Length; ++i)
|
||||
{
|
||||
int delta = id - list[i];
|
||||
|
||||
if (delta < 0)
|
||||
return false;
|
||||
else if (delta == 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsNorthFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_NorthFrames);
|
||||
}
|
||||
|
||||
public static bool IsSouthFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_SouthFrames);
|
||||
}
|
||||
|
||||
public static bool IsWestFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_WestFrames);
|
||||
}
|
||||
|
||||
public static bool IsEastFrame(int id)
|
||||
{
|
||||
return IsFrame(id, m_EastFrames);
|
||||
}
|
||||
|
||||
public static bool IsEastFrame(int x, int y, int z)
|
||||
{
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
if (tile.Z == z && IsEastFrame(tile.ID))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool IsSouthFrame(int x, int y, int z)
|
||||
{
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(x, y);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
if (tile.Z == z && IsSouthFrame(tile.ID))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static BaseDoor AddDoor(int x, int y, int z, DoorFacing facing)
|
||||
{
|
||||
int doorZ = z;
|
||||
int doorTop = doorZ + 20;
|
||||
|
||||
if (!m_Map.CanFit(x, y, z, 16, false, false))
|
||||
return null;
|
||||
|
||||
if (y == 1743 && x >= 1343 && x <= 1344)
|
||||
return null;
|
||||
|
||||
if (y == 1679 && x >= 1392 && x <= 1393)
|
||||
return null;
|
||||
|
||||
if (x == 1320 && y >= 1618 && y <= 1640)
|
||||
return null;
|
||||
|
||||
if (x == 1383 && y >= 1642 && y <= 1643)
|
||||
return null;
|
||||
|
||||
BaseDoor door = new DarkWoodDoor(facing);
|
||||
WeakEntityCollection.Add("door", door);
|
||||
door.MoveToWorld(new Point3D(x, y, z), m_Map);
|
||||
|
||||
++m_Count;
|
||||
|
||||
return door;
|
||||
}
|
||||
|
||||
public static void Generate(Rectangle2D region)
|
||||
{
|
||||
for (int rx = 0; rx < region.Width; ++rx)
|
||||
{
|
||||
for (int ry = 0; ry < region.Height; ++ry)
|
||||
{
|
||||
int vx = rx + region.X;
|
||||
int vy = ry + region.Y;
|
||||
|
||||
StaticTile[] tiles = m_Map.Tiles.GetStaticTiles(vx, vy);
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
int id = tile.ID;
|
||||
int z = tile.Z;
|
||||
|
||||
if (IsWestFrame(id))
|
||||
{
|
||||
if (IsEastFrame(vx + 2, vy, z))
|
||||
{
|
||||
AddDoor(vx + 1, vy, z, DoorFacing.WestCW);
|
||||
}
|
||||
else if (IsEastFrame(vx + 3, vy, z))
|
||||
{
|
||||
BaseDoor first = AddDoor(vx + 1, vy, z, DoorFacing.WestCW);
|
||||
BaseDoor second = AddDoor(vx + 2, vy, z, DoorFacing.EastCCW);
|
||||
|
||||
if (first != null && second != null)
|
||||
{
|
||||
first.Link = second;
|
||||
second.Link = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first != null)
|
||||
first.Delete();
|
||||
|
||||
if (second != null)
|
||||
second.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsNorthFrame(id))
|
||||
{
|
||||
if (IsSouthFrame(vx, vy + 2, z))
|
||||
{
|
||||
AddDoor(vx, vy + 1, z, DoorFacing.SouthCW);
|
||||
}
|
||||
else if (IsSouthFrame(vx, vy + 3, z))
|
||||
{
|
||||
BaseDoor first = AddDoor(vx, vy + 1, z, DoorFacing.NorthCCW);
|
||||
BaseDoor second = AddDoor(vx, vy + 2, z, DoorFacing.SouthCW);
|
||||
|
||||
if (first != null && second != null)
|
||||
{
|
||||
first.Link = second;
|
||||
second.Link = first;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (first != null)
|
||||
first.Delete();
|
||||
|
||||
if (second != null)
|
||||
second.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
357
Scripts/Commands/Dupe.cs
Normal file
357
Scripts/Commands/Dupe.cs
Normal file
@@ -0,0 +1,357 @@
|
||||
#region References
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
#endregion
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class Dupe
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("Dupe", AccessLevel.GameMaster, Dupe_OnCommand);
|
||||
CommandSystem.Register("DupeInBag", AccessLevel.GameMaster, DupeInBag_OnCommand);
|
||||
}
|
||||
|
||||
[Usage("Dupe [amount]")]
|
||||
[Description("Dupes a targeted item.")]
|
||||
private static void Dupe_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
var amount = 1;
|
||||
|
||||
if (e.Length > 0)
|
||||
{
|
||||
amount = e.GetInt32(0);
|
||||
}
|
||||
|
||||
e.Mobile.Target = new DupeTarget(false, Math.Max(1, amount));
|
||||
e.Mobile.SendMessage("What do you wish to dupe?");
|
||||
}
|
||||
|
||||
[Usage("DupeInBag <count>")]
|
||||
[Description("Dupes an item at it's current location (count) number of times.")]
|
||||
private static void DupeInBag_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
var amount = 1;
|
||||
|
||||
if (e.Length > 0)
|
||||
{
|
||||
amount = e.GetInt32(0);
|
||||
}
|
||||
|
||||
e.Mobile.Target = new DupeTarget(true, Math.Max(1, amount));
|
||||
e.Mobile.SendMessage("What do you wish to dupe?");
|
||||
}
|
||||
|
||||
private class DupeTarget : Target
|
||||
{
|
||||
private readonly bool _InBag;
|
||||
private readonly int _Amount;
|
||||
|
||||
public DupeTarget(bool inbag, int amount)
|
||||
: base(15, false, TargetFlags.None)
|
||||
{
|
||||
_InBag = inbag;
|
||||
_Amount = amount;
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile m, object targ)
|
||||
{
|
||||
var done = false;
|
||||
|
||||
if (!(targ is Item))
|
||||
{
|
||||
m.SendMessage("You can only dupe items.");
|
||||
return;
|
||||
}
|
||||
|
||||
CommandLogging.WriteLine(
|
||||
m,
|
||||
"{0} {1} duping {2} (inBag={3}; amount={4})",
|
||||
m.AccessLevel,
|
||||
CommandLogging.Format(m),
|
||||
CommandLogging.Format(targ),
|
||||
_InBag,
|
||||
_Amount);
|
||||
|
||||
var item = (Item)targ;
|
||||
|
||||
Container pack;
|
||||
|
||||
if (_InBag)
|
||||
{
|
||||
if (item.Parent is Container)
|
||||
{
|
||||
pack = (Container)item.Parent;
|
||||
}
|
||||
else if (item.Parent is Mobile)
|
||||
{
|
||||
pack = ((Mobile)item.Parent).Backpack;
|
||||
}
|
||||
else
|
||||
{
|
||||
pack = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pack = m.Backpack;
|
||||
}
|
||||
|
||||
var t = item.GetType();
|
||||
|
||||
var a = t.GetCustomAttributes(typeof(ConstructableAttribute), false);
|
||||
|
||||
if (a.OfType<ConstructableAttribute>().Any(ca => ca.AccessLevel > m.AccessLevel))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m.SendMessage("Duping {0}...", _Amount);
|
||||
|
||||
var noCtor = false;
|
||||
|
||||
for (var i = 0; i < _Amount; i++)
|
||||
{
|
||||
Item o;
|
||||
|
||||
try
|
||||
{
|
||||
o = Activator.CreateInstance(t, true) as Item;
|
||||
}
|
||||
catch
|
||||
{
|
||||
o = null;
|
||||
}
|
||||
|
||||
if (o == null)
|
||||
{
|
||||
noCtor = true;
|
||||
break;
|
||||
}
|
||||
|
||||
CopyProperties(item, o);
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
item.OnAfterDuped(o);
|
||||
|
||||
if (item is Container && o is Container)
|
||||
{
|
||||
m.SendMessage("Duping Container Children...");
|
||||
DupeChildren(m, (Container)item, (Container)o);
|
||||
}
|
||||
|
||||
if (pack != null)
|
||||
{
|
||||
pack.DropItem(o);
|
||||
}
|
||||
else
|
||||
{
|
||||
o.MoveToWorld(m.Location, m.Map);
|
||||
}
|
||||
|
||||
o.UpdateTotals();
|
||||
o.InvalidateProperties();
|
||||
o.Delta(ItemDelta.Update);
|
||||
|
||||
CommandLogging.WriteLine(
|
||||
m,
|
||||
"{0} {1} duped {2} creating {3}",
|
||||
m.AccessLevel,
|
||||
CommandLogging.Format(m),
|
||||
CommandLogging.Format(item),
|
||||
CommandLogging.Format(o));
|
||||
}
|
||||
|
||||
if (!noCtor)
|
||||
{
|
||||
m.SendMessage("Done");
|
||||
done = true;
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Console.WriteLine(e.StackTrace);
|
||||
|
||||
m.SendMessage("Error!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!done)
|
||||
{
|
||||
m.SendMessage("Unable to dupe. Item must have a 0 parameter constructor.");
|
||||
}
|
||||
else
|
||||
{
|
||||
item.Delta(ItemDelta.Update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Item DupeItem(Item item)
|
||||
{
|
||||
return DupeItem(null, item);
|
||||
}
|
||||
|
||||
public static Item DupeItem(Mobile m, Item item)
|
||||
{
|
||||
try
|
||||
{
|
||||
var t = item.GetType();
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
var a = t.GetCustomAttributes(typeof(ConstructableAttribute), false);
|
||||
|
||||
if (a.OfType<ConstructableAttribute>().Any(ca => ca.AccessLevel > m.AccessLevel))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Item o;
|
||||
|
||||
try
|
||||
{
|
||||
o = Activator.CreateInstance(t, true) as Item;
|
||||
}
|
||||
catch
|
||||
{
|
||||
o = null;
|
||||
}
|
||||
|
||||
if (o == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
CopyProperties(item, o);
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
item.OnAfterDuped(o);
|
||||
|
||||
if (item is Container && o is Container)
|
||||
{
|
||||
DupeChildren(m, (Container)item, (Container)o);
|
||||
}
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
o.MoveToWorld(m.Location, m.Map);
|
||||
|
||||
o.UpdateTotals();
|
||||
o.InvalidateProperties();
|
||||
o.Delta(ItemDelta.Update);
|
||||
|
||||
CommandLogging.WriteLine(m, "{0} {1} duped {2} creating {3}", m.AccessLevel, CommandLogging.Format(m),
|
||||
CommandLogging.Format(item), CommandLogging.Format(o));
|
||||
}
|
||||
|
||||
item.Delta(ItemDelta.Update);
|
||||
|
||||
return o;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void DupeChildren(Container src, Container dest)
|
||||
{
|
||||
DupeChildren(null, src, dest);
|
||||
}
|
||||
|
||||
public static void DupeChildren(Mobile m, Container src, Container dest)
|
||||
{
|
||||
foreach (var item in src.Items)
|
||||
{
|
||||
try
|
||||
{
|
||||
var t = item.GetType();
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
var a = t.GetCustomAttributes(typeof(ConstructableAttribute), false);
|
||||
|
||||
if (a.OfType<ConstructableAttribute>().Any(ca => ca.AccessLevel > m.AccessLevel))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
Item o;
|
||||
|
||||
try
|
||||
{
|
||||
o = Activator.CreateInstance(t, true) as Item;
|
||||
}
|
||||
catch
|
||||
{
|
||||
o = null;
|
||||
}
|
||||
|
||||
if (o == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
CopyProperties(item, o);
|
||||
|
||||
o.Parent = null;
|
||||
|
||||
item.OnAfterDuped(o);
|
||||
|
||||
if (item is Container && o is Container)
|
||||
{
|
||||
DupeChildren(m, (Container)item, (Container)o);
|
||||
}
|
||||
|
||||
dest.DropItem(o);
|
||||
o.Location = item.Location;
|
||||
|
||||
o.UpdateTotals();
|
||||
o.InvalidateProperties();
|
||||
o.Delta(ItemDelta.Update);
|
||||
|
||||
CommandLogging.WriteLine(
|
||||
m,
|
||||
"{0} {1} duped {2} creating {3}",
|
||||
m.AccessLevel,
|
||||
CommandLogging.Format(m),
|
||||
CommandLogging.Format(item),
|
||||
CommandLogging.Format(o));
|
||||
|
||||
item.Delta(ItemDelta.Update);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
public static void CopyProperties(object src, object dest)
|
||||
{
|
||||
var props = src.GetType().GetProperties();
|
||||
|
||||
foreach (var p in props)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (p.CanRead && p.CanWrite)
|
||||
{
|
||||
p.SetValue(dest, p.GetValue(src, null), null);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Scripts/Commands/ExportWSC.cs
Normal file
81
Scripts/Commands/ExportWSC.cs
Normal file
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class ExportCommand
|
||||
{
|
||||
private const string ExportFile = @"C:\Uo\WorldForge\items.wsc";
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("ExportWSC", AccessLevel.Administrator, new CommandEventHandler(Export_OnCommand));
|
||||
}
|
||||
|
||||
public static void Export_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
StreamWriter w = new StreamWriter(ExportFile);
|
||||
ArrayList remove = new ArrayList();
|
||||
int count = 0;
|
||||
|
||||
e.Mobile.SendMessage("Exporting all static items to \"{0}\"...", ExportFile);
|
||||
e.Mobile.SendMessage("This will delete all static items in the world. Please make a backup.");
|
||||
|
||||
foreach (Item item in World.Items.Values)
|
||||
{
|
||||
if ((item is Static || item is BaseFloor || item is BaseWall) &&
|
||||
item.RootParent == null)
|
||||
{
|
||||
w.WriteLine("SECTION WORLDITEM {0}", count);
|
||||
w.WriteLine("{");
|
||||
w.WriteLine("SERIAL {0}", item.Serial);
|
||||
w.WriteLine("NAME #");
|
||||
w.WriteLine("NAME2 #");
|
||||
w.WriteLine("ID {0}", item.ItemID);
|
||||
w.WriteLine("X {0}", item.X);
|
||||
w.WriteLine("Y {0}", item.Y);
|
||||
w.WriteLine("Z {0}", item.Z);
|
||||
w.WriteLine("COLOR {0}", item.Hue);
|
||||
w.WriteLine("CONT -1");
|
||||
w.WriteLine("TYPE 0");
|
||||
w.WriteLine("AMOUNT 1");
|
||||
w.WriteLine("WEIGHT 255");
|
||||
w.WriteLine("OWNER -1");
|
||||
w.WriteLine("SPAWN -1");
|
||||
w.WriteLine("VALUE 1");
|
||||
w.WriteLine("}");
|
||||
w.WriteLine("");
|
||||
|
||||
count++;
|
||||
remove.Add(item);
|
||||
w.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
w.Close();
|
||||
|
||||
foreach (Item item in remove)
|
||||
item.Delete();
|
||||
|
||||
e.Mobile.SendMessage("Export complete. Exported {0} statics.", count);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*SECTION WORLDITEM 1
|
||||
{
|
||||
SERIAL 1073741830
|
||||
NAME #
|
||||
NAME2 #
|
||||
ID 1709
|
||||
X 1439
|
||||
Y 1613
|
||||
Z 20
|
||||
CONT -1
|
||||
TYPE 12
|
||||
AMOUNT 1
|
||||
WEIGHT 25500
|
||||
OWNER -1
|
||||
SPAWN -1
|
||||
VALUE 1
|
||||
}*/
|
||||
198
Scripts/Commands/GMbody.cs
Normal file
198
Scripts/Commands/GMbody.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
using Server.Mobiles;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class GMbody
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("GMbody", AccessLevel.Counselor, new CommandEventHandler(GM_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("GMbody")]
|
||||
[Description("Helps staff members get going.")]
|
||||
public static void GM_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
e.Mobile.Target = new GMmeTarget();
|
||||
}
|
||||
|
||||
private class GMmeTarget : Target
|
||||
{
|
||||
private static Mobile m_Mobile;
|
||||
public GMmeTarget()
|
||||
: base(-1, false, TargetFlags.None)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object targeted)
|
||||
{
|
||||
if (targeted is Mobile)
|
||||
{
|
||||
Mobile targ = (Mobile)targeted;
|
||||
if (from != targ)
|
||||
from.SendMessage("You may only set your own body to GM style.");
|
||||
|
||||
else
|
||||
{
|
||||
m_Mobile = from;
|
||||
|
||||
if (Config.Get("Staff.Staffbody", true))
|
||||
{
|
||||
m_Mobile.BodyValue = 987;
|
||||
|
||||
if (Config.Get("Staff.UseColoring", true))
|
||||
{
|
||||
switch (m_Mobile.AccessLevel)
|
||||
{
|
||||
case AccessLevel.Owner:m_Mobile.Hue = Config.Get("Staff.Owner", 1001); break;
|
||||
case AccessLevel.Developer:m_Mobile.Hue = Config.Get("Staff.Developer", 1001); break;
|
||||
case AccessLevel.Administrator: m_Mobile.Hue = Config.Get("Staff.Administrator", 1001); break;
|
||||
case AccessLevel.Seer: m_Mobile.Hue = Config.Get("Staff.Seer", 467); break;
|
||||
case AccessLevel.GameMaster: m_Mobile.Hue = Config.Get("Staff.GameMaster", 39); break;
|
||||
case AccessLevel.Counselor: m_Mobile.Hue = Config.Get("Staff.Counselor", 3); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Config.Get("Staff.CutHair", true))
|
||||
m_Mobile.HairItemID = 0;
|
||||
|
||||
if (Config.Get("Staff.CutFacialHair", true))
|
||||
m_Mobile.FacialHairItemID = 0;
|
||||
|
||||
CommandLogging.WriteLine(from, "{0} {1} is assuming a GM body", from.AccessLevel, CommandLogging.Format(from));
|
||||
|
||||
Container pack = from.Backpack;
|
||||
|
||||
ArrayList ItemsToDelete = new ArrayList();
|
||||
|
||||
foreach (Item item in from.Items)
|
||||
{
|
||||
if (item.Layer != Layer.Bank && item.Layer != Layer.Hair && item.Layer != Layer.FacialHair && item.Layer != Layer.Mount && item.Layer != Layer.Backpack)
|
||||
{
|
||||
ItemsToDelete.Add(item);
|
||||
}
|
||||
}
|
||||
foreach (Item item in ItemsToDelete)
|
||||
item.Delete();
|
||||
|
||||
if (pack == null)
|
||||
{
|
||||
pack = new Backpack();
|
||||
pack.Movable = false;
|
||||
|
||||
from.AddItem(pack);
|
||||
}
|
||||
else
|
||||
{
|
||||
pack.Delete();
|
||||
pack = new Backpack();
|
||||
pack.Movable = false;
|
||||
|
||||
from.AddItem(pack);
|
||||
}
|
||||
|
||||
from.Hunger = 20;
|
||||
from.Thirst = 20;
|
||||
from.Fame = 0;
|
||||
from.Karma = 0;
|
||||
from.Kills = 0;
|
||||
from.Hidden = true;
|
||||
from.Blessed = true;
|
||||
from.Hits = from.HitsMax;
|
||||
from.Mana = from.ManaMax;
|
||||
from.Stam = from.StamMax;
|
||||
|
||||
if (from.IsStaff())
|
||||
{
|
||||
EquipItem(new StaffRing());
|
||||
|
||||
PackItem(new GMHidingStone());
|
||||
PackItem(new GMEthereal());
|
||||
PackItem(new StaffOrb());
|
||||
|
||||
from.RawStr = 100;
|
||||
from.RawDex = 100;
|
||||
from.RawInt = 100;
|
||||
|
||||
from.Hits = from.HitsMax;
|
||||
from.Mana = from.ManaMax;
|
||||
from.Stam = from.StamMax;
|
||||
|
||||
for (int i = 0; i < targ.Skills.Length; ++i)
|
||||
targ.Skills[i].Base = 120;
|
||||
}
|
||||
|
||||
if (Config.Get("Staff.GiveBoots", true))
|
||||
{
|
||||
int color = 0;
|
||||
if (Config.Get("Staff.UseColoring", true))
|
||||
{
|
||||
switch (m_Mobile.AccessLevel)
|
||||
{
|
||||
case AccessLevel.Owner: color = Config.Get("Staff.Owner", 1001); break;
|
||||
case AccessLevel.Developer: color = Config.Get("Staff.Developer", 1001); break;
|
||||
case AccessLevel.Administrator: color = Config.Get("Staff.Administrator", 1001); break;
|
||||
case AccessLevel.Seer: color = Config.Get("Staff.Seer", 467); break;
|
||||
case AccessLevel.GameMaster: color = Config.Get("Staff.GameMaster", 39); break;
|
||||
case AccessLevel.Counselor: color = Config.Get("Staff.Counselor", 3); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (from.IsStaff() && from.AccessLevel <= AccessLevel.Spawner)
|
||||
EquipItem(new FurBoots(color));
|
||||
else if (from.AccessLevel == AccessLevel.GameMaster)
|
||||
EquipItem(new FurBoots(color));
|
||||
if (from.AccessLevel == AccessLevel.Seer)
|
||||
EquipItem(new FurBoots(color));
|
||||
if (from.AccessLevel == AccessLevel.Administrator)
|
||||
EquipItem(new FurBoots(color));
|
||||
if (from.AccessLevel == AccessLevel.Developer)
|
||||
EquipItem(new FurBoots(color));
|
||||
if (from.AccessLevel >= AccessLevel.CoOwner)
|
||||
EquipItem(new FurBoots(color));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EquipItem(Item item)
|
||||
{
|
||||
EquipItem(item, false);
|
||||
}
|
||||
|
||||
private static void EquipItem(Item item, bool mustEquip)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
item.LootType = LootType.Blessed;
|
||||
|
||||
if (m_Mobile != null && m_Mobile.EquipItem(item))
|
||||
return;
|
||||
|
||||
Container pack = m_Mobile.Backpack;
|
||||
|
||||
if (!mustEquip && pack != null)
|
||||
pack.DropItem(item);
|
||||
else
|
||||
item.Delete();
|
||||
}
|
||||
|
||||
private static void PackItem(Item item)
|
||||
{
|
||||
if (!Core.AOS)
|
||||
item.LootType = LootType.Blessed;
|
||||
|
||||
Container pack = m_Mobile.Backpack;
|
||||
|
||||
if (pack != null)
|
||||
pack.DropItem(item);
|
||||
else
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Scripts/Commands/GenBounds.cs
Normal file
52
Scripts/Commands/GenBounds.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Server.Commands;
|
||||
|
||||
namespace Server.Bounds
|
||||
{
|
||||
public class Bounds
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("GenBounds", AccessLevel.Administrator, new CommandEventHandler(GenBounds_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("GenBounds")]
|
||||
[Description("GenBounds")]
|
||||
public static void GenBounds_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if(Ultima.Files.MulPath["artlegacymul.uop"] != null || (Ultima.Files.MulPath["art.mul"] != null && Ultima.Files.MulPath["artidx.mul"] != null))
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Yellow);
|
||||
Console.Write("Generating Bounds.bin...");
|
||||
Utility.PopColor();
|
||||
|
||||
FileStream fs = new FileStream( "Data/Binary/Bounds.bin", FileMode.Create, FileAccess.Write );
|
||||
|
||||
BinaryWriter bin = new BinaryWriter( fs );
|
||||
|
||||
int xMin, yMin, xMax, yMax;
|
||||
|
||||
for ( int i = 0; i < Ultima.Art.GetMaxItemID(); ++i )
|
||||
{
|
||||
Ultima.Art.Measure(Item.GetBitmap(i), out xMin, out yMin, out xMax, out yMax);
|
||||
|
||||
bin.Write((ushort)xMin);
|
||||
bin.Write((ushort)yMin);
|
||||
bin.Write((ushort)xMax);
|
||||
bin.Write((ushort)yMax);
|
||||
}
|
||||
Utility.PushColor(ConsoleColor.Green);
|
||||
Console.WriteLine("done");
|
||||
Utility.PopColor();
|
||||
bin.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
Utility.PushColor(ConsoleColor.Red);
|
||||
Console.WriteLine("Art files missing.");
|
||||
Utility.PopColor();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
469
Scripts/Commands/GenCategorization.cs
Normal file
469
Scripts/Commands/GenCategorization.cs
Normal file
@@ -0,0 +1,469 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using Server.Items;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class Categorization
|
||||
{
|
||||
private static readonly Type typeofItem = typeof(Item);
|
||||
private static readonly Type typeofMobile = typeof(Mobile);
|
||||
private static readonly Type typeofConstructable = typeof(ConstructableAttribute);
|
||||
private static CategoryEntry m_RootItems, m_RootMobiles;
|
||||
public static CategoryEntry Items
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RootItems == null)
|
||||
Load();
|
||||
|
||||
return m_RootItems;
|
||||
}
|
||||
}
|
||||
public static CategoryEntry Mobiles
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RootMobiles == null)
|
||||
Load();
|
||||
|
||||
return m_RootMobiles;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("RebuildCategorization", AccessLevel.Administrator, new CommandEventHandler(RebuildCategorization_OnCommand));
|
||||
}
|
||||
|
||||
[Usage("RebuildCategorization")]
|
||||
[Description("Rebuilds the categorization data file used by the Add command.")]
|
||||
public static void RebuildCategorization_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
CategoryEntry root = new CategoryEntry(null, "Add Menu", new CategoryEntry[] { Items, Mobiles });
|
||||
|
||||
Export(root, "Data/objects.xml", "Objects");
|
||||
|
||||
e.Mobile.SendMessage("Categorization menu rebuilt.");
|
||||
}
|
||||
|
||||
public static void RecurseFindCategories(CategoryEntry ce, ArrayList list)
|
||||
{
|
||||
list.Add(ce);
|
||||
|
||||
for (int i = 0; i < ce.SubCategories.Length; ++i)
|
||||
RecurseFindCategories(ce.SubCategories[i], list);
|
||||
}
|
||||
|
||||
public static void Export(CategoryEntry ce, string fileName, string title)
|
||||
{
|
||||
XmlTextWriter xml = new XmlTextWriter(fileName, System.Text.Encoding.UTF8);
|
||||
|
||||
xml.Indentation = 1;
|
||||
xml.IndentChar = '\t';
|
||||
xml.Formatting = Formatting.Indented;
|
||||
|
||||
xml.WriteStartDocument(true);
|
||||
|
||||
RecurseExport(xml, ce);
|
||||
|
||||
xml.Flush();
|
||||
xml.Close();
|
||||
}
|
||||
|
||||
public static void RecurseExport(XmlTextWriter xml, CategoryEntry ce)
|
||||
{
|
||||
xml.WriteStartElement("category");
|
||||
|
||||
xml.WriteAttributeString("title", ce.Title);
|
||||
|
||||
ArrayList subCats = new ArrayList(ce.SubCategories);
|
||||
|
||||
subCats.Sort(new CategorySorter());
|
||||
|
||||
for (int i = 0; i < subCats.Count; ++i)
|
||||
RecurseExport(xml, (CategoryEntry)subCats[i]);
|
||||
|
||||
ce.Matched.Sort(new CategorySorter());
|
||||
|
||||
for (int i = 0; i < ce.Matched.Count; ++i)
|
||||
{
|
||||
CategoryTypeEntry cte = (CategoryTypeEntry)ce.Matched[i];
|
||||
|
||||
xml.WriteStartElement("object");
|
||||
|
||||
xml.WriteAttributeString("type", cte.Type.ToString());
|
||||
|
||||
object obj = cte.Object;
|
||||
|
||||
if (obj is Item)
|
||||
{
|
||||
Item item = (Item)obj;
|
||||
int itemID = item.ItemID;
|
||||
|
||||
if (item is BaseAddon && ((BaseAddon)item).Components.Count == 1)
|
||||
itemID = ((AddonComponent)(((BaseAddon)item).Components[0])).ItemID;
|
||||
|
||||
if (itemID > TileData.MaxItemValue)
|
||||
itemID = 1;
|
||||
|
||||
xml.WriteAttributeString("gfx", XmlConvert.ToString(itemID));
|
||||
|
||||
int hue = item.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
hue = 0;
|
||||
|
||||
if (hue != 0)
|
||||
xml.WriteAttributeString("hue", XmlConvert.ToString(hue));
|
||||
|
||||
item.Delete();
|
||||
}
|
||||
else if (obj is Mobile)
|
||||
{
|
||||
Mobile mob = (Mobile)obj;
|
||||
|
||||
int itemID = ShrinkTable.Lookup(mob, 1);
|
||||
|
||||
xml.WriteAttributeString("gfx", XmlConvert.ToString(itemID));
|
||||
|
||||
int hue = mob.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
hue = 0;
|
||||
|
||||
if (hue != 0)
|
||||
xml.WriteAttributeString("hue", XmlConvert.ToString(hue));
|
||||
|
||||
mob.Delete();
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
ArrayList types = new ArrayList();
|
||||
|
||||
AddTypes(Core.Assembly, types);
|
||||
|
||||
for (int i = 0; i < ScriptCompiler.Assemblies.Length; ++i)
|
||||
AddTypes(ScriptCompiler.Assemblies[i], types);
|
||||
|
||||
m_RootItems = Load(types, "Data/items.cfg");
|
||||
m_RootMobiles = Load(types, "Data/mobiles.cfg");
|
||||
}
|
||||
|
||||
private static CategoryEntry Load(ArrayList types, string config)
|
||||
{
|
||||
CategoryLine[] lines = CategoryLine.Load(config);
|
||||
|
||||
if (lines.Length > 0)
|
||||
{
|
||||
int index = 0;
|
||||
CategoryEntry root = new CategoryEntry(null, lines, ref index);
|
||||
|
||||
Fill(root, types);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
return new CategoryEntry();
|
||||
}
|
||||
|
||||
private static bool IsConstructable(Type type)
|
||||
{
|
||||
if (!type.IsSubclassOf(typeofItem) && !type.IsSubclassOf(typeofMobile))
|
||||
return false;
|
||||
|
||||
ConstructorInfo ctor = type.GetConstructor(Type.EmptyTypes);
|
||||
|
||||
return (ctor != null && ctor.IsDefined(typeofConstructable, false));
|
||||
}
|
||||
|
||||
private static void AddTypes(Assembly asm, ArrayList types)
|
||||
{
|
||||
Type[] allTypes = asm.GetTypes();
|
||||
|
||||
for (int i = 0; i < allTypes.Length; ++i)
|
||||
{
|
||||
Type type = allTypes[i];
|
||||
|
||||
if (type.IsAbstract)
|
||||
continue;
|
||||
|
||||
if (IsConstructable(type))
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Fill(CategoryEntry root, ArrayList list)
|
||||
{
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
Type type = (Type)list[i];
|
||||
CategoryEntry match = GetDeepestMatch(root, type);
|
||||
|
||||
if (match == null)
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
match.Matched.Add(new CategoryTypeEntry(type));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CategoryEntry GetDeepestMatch(CategoryEntry root, Type type)
|
||||
{
|
||||
if (!root.IsMatch(type))
|
||||
return null;
|
||||
|
||||
for (int i = 0; i < root.SubCategories.Length; ++i)
|
||||
{
|
||||
CategoryEntry check = GetDeepestMatch(root.SubCategories[i], type);
|
||||
|
||||
if (check != null)
|
||||
return check;
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
public class CategorySorter : IComparer
|
||||
{
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
string a = null, b = null;
|
||||
|
||||
if (x is CategoryEntry)
|
||||
a = ((CategoryEntry)x).Title;
|
||||
else if (x is CategoryTypeEntry)
|
||||
a = ((CategoryTypeEntry)x).Type.Name;
|
||||
|
||||
if (y is CategoryEntry)
|
||||
b = ((CategoryEntry)y).Title;
|
||||
else if (y is CategoryTypeEntry)
|
||||
b = ((CategoryTypeEntry)y).Type.Name;
|
||||
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
|
||||
if (a == null)
|
||||
return 1;
|
||||
|
||||
if (b == null)
|
||||
return -1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryTypeEntry
|
||||
{
|
||||
private readonly Type m_Type;
|
||||
private readonly object m_Object;
|
||||
public CategoryTypeEntry(Type type)
|
||||
{
|
||||
this.m_Type = type;
|
||||
this.m_Object = Activator.CreateInstance(type);
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Type;
|
||||
}
|
||||
}
|
||||
public object Object
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Object;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryEntry
|
||||
{
|
||||
private readonly string m_Title;
|
||||
private readonly Type[] m_Matches;
|
||||
private readonly CategoryEntry[] m_SubCategories;
|
||||
private readonly CategoryEntry m_Parent;
|
||||
private readonly ArrayList m_Matched;
|
||||
public CategoryEntry()
|
||||
{
|
||||
this.m_Title = "(empty)";
|
||||
this.m_Matches = new Type[0];
|
||||
this.m_SubCategories = new CategoryEntry[0];
|
||||
this.m_Matched = new ArrayList();
|
||||
}
|
||||
|
||||
public CategoryEntry(CategoryEntry parent, string title, CategoryEntry[] subCats)
|
||||
{
|
||||
this.m_Parent = parent;
|
||||
this.m_Title = title;
|
||||
this.m_SubCategories = subCats;
|
||||
this.m_Matches = new Type[0];
|
||||
this.m_Matched = new ArrayList();
|
||||
}
|
||||
|
||||
public CategoryEntry(CategoryEntry parent, CategoryLine[] lines, ref int index)
|
||||
{
|
||||
this.m_Parent = parent;
|
||||
|
||||
string text = lines[index].Text;
|
||||
|
||||
int start = text.IndexOf('(');
|
||||
|
||||
if (start < 0)
|
||||
throw new FormatException(String.Format("Input string not correctly formatted ('{0}')", text));
|
||||
|
||||
this.m_Title = text.Substring(0, start).Trim();
|
||||
|
||||
int end = text.IndexOf(')', ++start);
|
||||
|
||||
if (end < start)
|
||||
throw new FormatException(String.Format("Input string not correctly formatted ('{0}')", text));
|
||||
|
||||
text = text.Substring(start, end - start);
|
||||
string[] split = text.Split(';');
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
for (int i = 0; i < split.Length; ++i)
|
||||
{
|
||||
Type type = ScriptCompiler.FindTypeByName(split[i].Trim());
|
||||
|
||||
if (type == null)
|
||||
Console.WriteLine("Match type not found ('{0}')", split[i].Trim());
|
||||
else
|
||||
list.Add(type);
|
||||
}
|
||||
|
||||
this.m_Matches = (Type[])list.ToArray(typeof(Type));
|
||||
list.Clear();
|
||||
|
||||
int ourIndentation = lines[index].Indentation;
|
||||
|
||||
++index;
|
||||
|
||||
while (index < lines.Length && lines[index].Indentation > ourIndentation)
|
||||
list.Add(new CategoryEntry(this, lines, ref index));
|
||||
|
||||
this.m_SubCategories = (CategoryEntry[])list.ToArray(typeof(CategoryEntry));
|
||||
list.Clear();
|
||||
|
||||
this.m_Matched = list;
|
||||
}
|
||||
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Title;
|
||||
}
|
||||
}
|
||||
public Type[] Matches
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Matches;
|
||||
}
|
||||
}
|
||||
public CategoryEntry Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Parent;
|
||||
}
|
||||
}
|
||||
public CategoryEntry[] SubCategories
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SubCategories;
|
||||
}
|
||||
}
|
||||
public ArrayList Matched
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Matched;
|
||||
}
|
||||
}
|
||||
public bool IsMatch(Type type)
|
||||
{
|
||||
bool isMatch = false;
|
||||
|
||||
for (int i = 0; !isMatch && i < this.m_Matches.Length; ++i)
|
||||
isMatch = (type == this.m_Matches[i] || type.IsSubclassOf(this.m_Matches[i]));
|
||||
|
||||
return isMatch;
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryLine
|
||||
{
|
||||
private readonly int m_Indentation;
|
||||
private readonly string m_Text;
|
||||
public CategoryLine(string input)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < input.Length; ++index)
|
||||
{
|
||||
if (Char.IsLetter(input, index))
|
||||
break;
|
||||
}
|
||||
|
||||
if (index >= input.Length)
|
||||
throw new FormatException(String.Format("Input string not correctly formatted ('{0}')", input));
|
||||
|
||||
this.m_Indentation = index;
|
||||
this.m_Text = input.Substring(index);
|
||||
}
|
||||
|
||||
public int Indentation
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Indentation;
|
||||
}
|
||||
}
|
||||
public string Text
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Text;
|
||||
}
|
||||
}
|
||||
public static CategoryLine[] Load(string path)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using (StreamReader ip = new StreamReader(path))
|
||||
{
|
||||
string line;
|
||||
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
list.Add(new CategoryLine(line));
|
||||
}
|
||||
}
|
||||
|
||||
return (CategoryLine[])list.ToArray(typeof(CategoryLine));
|
||||
}
|
||||
}
|
||||
}
|
||||
194
Scripts/Commands/GenTeleporter.cs
Normal file
194
Scripts/Commands/GenTeleporter.cs
Normal file
@@ -0,0 +1,194 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Items;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
class Location : IComparable
|
||||
{
|
||||
public int X;
|
||||
public int Y;
|
||||
public int Z;
|
||||
public Map Map;
|
||||
public Location(int x, int y, int z, Map m)
|
||||
{
|
||||
X = x;
|
||||
Y = y;
|
||||
Z = z;
|
||||
Map = m;
|
||||
}
|
||||
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (!(obj is Location))
|
||||
return GetHashCode().CompareTo(obj.GetHashCode());
|
||||
|
||||
Location l = (Location)obj;
|
||||
if (l.Map.MapID != Map.MapID)
|
||||
return l.Map.MapID - Map.MapID;
|
||||
if (l.X != X)
|
||||
return l.X - X;
|
||||
if (l.Y != Y)
|
||||
return l.Y - Y;
|
||||
return l.Z - Z;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
string hashString = String.Format("{0}-{1}-{2}-{3}",
|
||||
X, Y, Z, Map.MapID);
|
||||
return hashString.GetHashCode();
|
||||
}
|
||||
}
|
||||
class TelDef
|
||||
{
|
||||
public Location Source;
|
||||
public Location Destination;
|
||||
public bool Back;
|
||||
public TelDef(Location s, Location d, bool b)
|
||||
{
|
||||
Source = s;
|
||||
Destination = d;
|
||||
Back = b;
|
||||
}
|
||||
}
|
||||
public class GenTeleporter
|
||||
{
|
||||
private static string m_Path = Path.Combine("Data", "teleporters.csv");
|
||||
private static char[] m_Sep = { ',' };
|
||||
|
||||
public GenTeleporter()
|
||||
{
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("TelGen", AccessLevel.Administrator, new CommandEventHandler(GenTeleporter_OnCommand));
|
||||
CommandSystem.Register("TelGenDelete", AccessLevel.Administrator, new CommandEventHandler(TelGenDelete_OnCommand));
|
||||
}
|
||||
|
||||
private static void TelGenDelete_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
WeakEntityCollection.Delete("tel");
|
||||
}
|
||||
|
||||
[Usage("TelGen")]
|
||||
[Description("Generates world/dungeon teleporters for all facets.")]
|
||||
public static void GenTeleporter_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
e.Mobile.SendMessage("Generating teleporters, please wait.");
|
||||
|
||||
TeleportersCreator c = new TeleportersCreator();
|
||||
|
||||
StreamReader reader = new StreamReader(m_Path);
|
||||
|
||||
string line;
|
||||
int lineNum = 0;
|
||||
while((line = reader.ReadLine()) != null)
|
||||
{
|
||||
++lineNum;
|
||||
line = line.Trim();
|
||||
if (line.StartsWith("#"))
|
||||
continue;
|
||||
string[] parts = line.Split(m_Sep);
|
||||
if(parts.Length != 9)
|
||||
{
|
||||
e.Mobile.SendMessage(33, String.Format("Bad teleporter definition on line {0}", lineNum));
|
||||
continue;
|
||||
}
|
||||
try
|
||||
{
|
||||
c.CreateTeleporter(
|
||||
int.Parse(parts[0]),
|
||||
int.Parse(parts[1]),
|
||||
int.Parse(parts[2]),
|
||||
int.Parse(parts[4]),
|
||||
int.Parse(parts[5]),
|
||||
int.Parse(parts[6]),
|
||||
Map.Parse(parts[3]),
|
||||
Map.Parse(parts[7]),
|
||||
bool.Parse(parts[8])
|
||||
);
|
||||
}
|
||||
catch (FormatException)
|
||||
{
|
||||
e.Mobile.SendMessage(33, String.Format("Bad number format on line {0}", lineNum));
|
||||
}
|
||||
catch(ArgumentException ex)
|
||||
{
|
||||
e.Mobile.SendMessage(33, String.Format("Argument Execption {0} on line {1}", ex.Message, lineNum));
|
||||
}
|
||||
}
|
||||
reader.Close();
|
||||
|
||||
e.Mobile.SendMessage("Teleporter generating complete.");
|
||||
}
|
||||
|
||||
public class TeleportersCreator
|
||||
{
|
||||
private static readonly Queue m_Queue = new Queue();
|
||||
private int m_Count;
|
||||
public TeleportersCreator()
|
||||
{
|
||||
}
|
||||
|
||||
public static bool FindTeleporter(Map map, Point3D p)
|
||||
{
|
||||
IPooledEnumerable eable = map.GetItemsInRange(p, 0);
|
||||
|
||||
foreach (Item item in eable)
|
||||
{
|
||||
if (item is Teleporter && !(item is KeywordTeleporter) && !(item is SkillTeleporter))
|
||||
{
|
||||
int delta = item.Z - p.Z;
|
||||
|
||||
if (delta >= -12 && delta <= 12)
|
||||
m_Queue.Enqueue(item);
|
||||
}
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
while (m_Queue.Count > 0)
|
||||
((Item)m_Queue.Dequeue()).Delete();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void CreateTeleporter(Point3D pointLocation, Point3D pointDestination, Map mapLocation, Map mapDestination, bool back)
|
||||
{
|
||||
if (!FindTeleporter(mapLocation, pointLocation))
|
||||
{
|
||||
this.m_Count++;
|
||||
|
||||
Teleporter tel = new Teleporter(pointDestination, mapDestination);
|
||||
WeakEntityCollection.Add("tel", tel);
|
||||
|
||||
tel.MoveToWorld(pointLocation, mapLocation);
|
||||
}
|
||||
|
||||
if (back && !FindTeleporter(mapDestination, pointDestination))
|
||||
{
|
||||
this.m_Count++;
|
||||
|
||||
Teleporter telBack = new Teleporter(pointLocation, mapLocation);
|
||||
WeakEntityCollection.Add("tel", telBack);
|
||||
|
||||
telBack.MoveToWorld(pointDestination, mapDestination);
|
||||
}
|
||||
}
|
||||
|
||||
public void CreateTeleporter(int xLoc, int yLoc, int zLoc, int xDest, int yDest, int zDest, Map map, bool back)
|
||||
{
|
||||
this.CreateTeleporter(new Point3D(xLoc, yLoc, zLoc), new Point3D(xDest, yDest, zDest), map, map, back);
|
||||
}
|
||||
|
||||
public void CreateTeleporter(int xLoc, int yLoc, int zLoc, int xDest, int yDest, int zDest, Map mapLocation, Map mapDestination, bool back)
|
||||
{
|
||||
this.CreateTeleporter(new Point3D(xLoc, yLoc, zLoc), new Point3D(xDest, yDest, zDest), mapLocation, mapDestination, back);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
220
Scripts/Commands/GenerateGameDocs.cs
Normal file
220
Scripts/Commands/GenerateGameDocs.cs
Normal file
@@ -0,0 +1,220 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Runtime;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public static class GenerateGameDocs
|
||||
{
|
||||
private static CsvFile csv;
|
||||
|
||||
private delegate void ProcessObject(object obj);
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("GenGameDocs", AccessLevel.GameMaster, new CommandEventHandler(GenGameDocs_OnCommand));
|
||||
}
|
||||
|
||||
private static void GenGameDocs_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
csv = new CsvFile();
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(t => t.GetTypes())
|
||||
.Where(t => t.IsClass && t.Namespace == "Server.Mobiles" && typeof(Mobiles.BaseCreature).IsAssignableFrom(t))
|
||||
.ToList()
|
||||
.ForEach(t => ConsumeType(t, HandleBaseCreature));
|
||||
csv.Write("Creatures.csv");
|
||||
|
||||
csv = new CsvFile();
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(t => t.GetTypes())
|
||||
.Where(t => t.IsClass && t.Namespace == "Server.Items" && typeof(Items.BaseWeapon).IsAssignableFrom(t))
|
||||
.ToList()
|
||||
.ForEach(t => ConsumeType(t, HandleBaseWeapon));
|
||||
csv.Write("Weapons.csv");
|
||||
|
||||
csv = new CsvFile();
|
||||
AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(t => t.GetTypes())
|
||||
.Where(t => t.IsClass && t.Namespace == "Server.Items" && typeof(Items.BaseArmor).IsAssignableFrom(t))
|
||||
.ToList()
|
||||
.ForEach(t => ConsumeType(t, HandleBaseArmor));
|
||||
csv.Write("Armor.csv");
|
||||
}
|
||||
|
||||
private static void HandleBaseArmor(object obj)
|
||||
{
|
||||
Items.BaseArmor arm = obj as Items.BaseArmor;
|
||||
if (arm == null)
|
||||
return;
|
||||
|
||||
csv.AddRow();
|
||||
csv.AddValue("Type", arm.GetType().Name);
|
||||
csv.AddValue("Name", arm.Name);
|
||||
csv.AddValue("Is Artifact?", arm.IsArtifact);
|
||||
csv.AddValue("Pysical Resist", arm.PhysicalResistance);
|
||||
csv.AddValue("Fire Resist", arm.FireResistance);
|
||||
csv.AddValue("Cold Resist", arm.ColdResistance);
|
||||
csv.AddValue("Poison Resist", arm.PoisonResistance);
|
||||
csv.AddValue("Energy Resist", arm.EnergyResistance);
|
||||
csv.AddValue("DCI", arm.Attributes.DefendChance);
|
||||
|
||||
}
|
||||
|
||||
private static void HandleBaseWeapon(object obj)
|
||||
{
|
||||
Items.BaseWeapon wep = obj as Items.BaseWeapon;
|
||||
if (wep == null)
|
||||
return;
|
||||
|
||||
csv.AddRow();
|
||||
csv.AddValue("Type", wep.GetType().Name);
|
||||
csv.AddValue("Name", wep.Name);
|
||||
csv.AddValue("Is Artifact?", wep.IsArtifact);
|
||||
csv.AddValue("Str Requirement", wep.StrRequirement);
|
||||
csv.AddValue("Dex Requirement", wep.DexRequirement);
|
||||
csv.AddValue("Int Requirement", wep.IntRequirement);
|
||||
csv.AddValue("Skill", wep.Skill);
|
||||
csv.AddValue("Race", wep.RequiredRace);
|
||||
csv.AddValue("Speed", wep.MlSpeed);
|
||||
csv.AddValue("Min Damage", wep.MinDamage);
|
||||
csv.AddValue("Max Damage", wep.MaxDamage);
|
||||
}
|
||||
|
||||
private static void HandleBaseCreature(object obj)
|
||||
{
|
||||
Mobiles.BaseCreature creature = obj as Mobiles.BaseCreature;
|
||||
if (creature == null)
|
||||
return;
|
||||
|
||||
Server.Items.BambooFlute flute = new Items.BambooFlute();
|
||||
|
||||
csv.AddRow();
|
||||
csv.AddValue("Type", creature.GetType().Name);
|
||||
csv.AddValue("Name", creature.Name);
|
||||
csv.AddValue("Str", creature.Str);
|
||||
csv.AddValue("Dex", creature.Dex);
|
||||
csv.AddValue("Int", creature.Int);
|
||||
csv.AddValue("Hits", creature.HitsMax);
|
||||
csv.AddValue("Stam", creature.StamMax);
|
||||
csv.AddValue("Mana", creature.ManaMax);
|
||||
csv.AddValue("Physical Resist", creature.PhysicalResistance);
|
||||
csv.AddValue("Fire Resist", creature.FireResistance);
|
||||
csv.AddValue("Cold Resist", creature.ColdResistance);
|
||||
csv.AddValue("Poison Resist", creature.PoisonResistance);
|
||||
csv.AddValue("Energy Resist", creature.EnergyResistance);
|
||||
csv.AddValue("Physical Damage", creature.PhysicalDamage);
|
||||
csv.AddValue("Fire Damage", creature.FireDamage);
|
||||
csv.AddValue("Cold Damage", creature.ColdDamage);
|
||||
csv.AddValue("Poison Damage", creature.PoisonDamage);
|
||||
csv.AddValue("Energy Damage", creature.EnergyDamage);
|
||||
csv.AddValue("Taming Difficulty", creature.CurrentTameSkill);
|
||||
csv.AddValue("Barding Difficulty", flute.GetDifficultyFor(creature));
|
||||
csv.AddValue("TMap Level", creature.TreasureMapLevel);
|
||||
csv.AddValue("Wrestling Skill", creature.Skills.Wrestling.Base);
|
||||
}
|
||||
|
||||
private static void ConsumeType(Type t, ProcessObject proc)
|
||||
{
|
||||
ConstructorInfo ctor = t.GetConstructor(new Type[] { });
|
||||
if (ctor == null)
|
||||
return;
|
||||
|
||||
object obj;
|
||||
try
|
||||
{
|
||||
obj = ctor.Invoke(new object[] { });
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
return;
|
||||
|
||||
proc(obj);
|
||||
}
|
||||
|
||||
private class CsvFile
|
||||
{
|
||||
private List<Dictionary<String, String>> rows = new List<Dictionary<string, string>>();
|
||||
private Dictionary<String, String> currentRow = null;
|
||||
private HashSet<String> headerSet = new HashSet<string>();
|
||||
private List<String> allHeaders = new List<string>();
|
||||
|
||||
public CsvFile()
|
||||
{
|
||||
}
|
||||
|
||||
public void AddRow()
|
||||
{
|
||||
currentRow = new Dictionary<String, String>();
|
||||
rows.Add(currentRow);
|
||||
}
|
||||
|
||||
public void AddValue(String name, object value)
|
||||
{
|
||||
if (name == null)
|
||||
return;
|
||||
|
||||
String v = "";
|
||||
if (value != null)
|
||||
v = value.ToString();
|
||||
|
||||
currentRow.Add(name, v.ToString());
|
||||
if (headerSet.Contains(name))
|
||||
return;
|
||||
headerSet.Add(name);
|
||||
allHeaders.Add(name);
|
||||
}
|
||||
|
||||
public void Write(String path)
|
||||
{
|
||||
StreamWriter outf = new StreamWriter(path);
|
||||
bool first;
|
||||
|
||||
first = true;
|
||||
foreach(String header in allHeaders)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
outf.Write(String.Format("\"{0}\"", header));
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
outf.Write(String.Format(",\"{0}\"", header));
|
||||
}
|
||||
}
|
||||
outf.WriteLine("");
|
||||
|
||||
foreach(Dictionary<String, String> row in rows)
|
||||
{
|
||||
first = true;
|
||||
foreach (String header in allHeaders)
|
||||
{
|
||||
String value = "";
|
||||
row.TryGetValue(header, out value);
|
||||
if (first)
|
||||
{
|
||||
outf.Write(String.Format("\"{0}\"", value));
|
||||
first = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
outf.Write(String.Format(",\"{0}\"", value));
|
||||
}
|
||||
}
|
||||
outf.WriteLine("");
|
||||
}
|
||||
|
||||
outf.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Scripts/Commands/Generic/Commands/BaseCommand.cs
Normal file
237
Scripts/Commands/Generic/Commands/BaseCommand.cs
Normal file
@@ -0,0 +1,237 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public enum ObjectTypes
|
||||
{
|
||||
Both,
|
||||
Items,
|
||||
Mobiles,
|
||||
All
|
||||
}
|
||||
|
||||
public abstract class BaseCommand
|
||||
{
|
||||
private readonly ArrayList m_Responses;
|
||||
private readonly ArrayList m_Failures;
|
||||
private string[] m_Commands;
|
||||
private AccessLevel m_AccessLevel;
|
||||
private CommandSupport m_Implementors;
|
||||
private ObjectTypes m_ObjectTypes;
|
||||
private bool m_ListOptimized;
|
||||
private string m_Usage;
|
||||
private string m_Description;
|
||||
public BaseCommand()
|
||||
{
|
||||
this.m_Responses = new ArrayList();
|
||||
this.m_Failures = new ArrayList();
|
||||
}
|
||||
|
||||
public bool ListOptimized
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ListOptimized;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ListOptimized = value;
|
||||
}
|
||||
}
|
||||
public string[] Commands
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Commands;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Commands = value;
|
||||
}
|
||||
}
|
||||
public string Usage
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Usage;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Usage = value;
|
||||
}
|
||||
}
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Description;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Description = value;
|
||||
}
|
||||
}
|
||||
public AccessLevel AccessLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_AccessLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_AccessLevel = value;
|
||||
}
|
||||
}
|
||||
public ObjectTypes ObjectTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ObjectTypes;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_ObjectTypes = value;
|
||||
}
|
||||
}
|
||||
public CommandSupport Supports
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Implementors;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Implementors = value;
|
||||
}
|
||||
}
|
||||
public static bool IsAccessible(Mobile from, object obj)
|
||||
{
|
||||
if (from.AccessLevel >= AccessLevel.Administrator || obj == null)
|
||||
return true;
|
||||
|
||||
Mobile mob;
|
||||
|
||||
if (obj is Mobile)
|
||||
mob = (Mobile)obj;
|
||||
else if (obj is Item)
|
||||
mob = ((Item)obj).RootParent as Mobile;
|
||||
else
|
||||
mob = null;
|
||||
|
||||
if (mob == null || mob == from || from.AccessLevel > mob.AccessLevel)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public virtual void ExecuteList(CommandEventArgs e, ArrayList list)
|
||||
{
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
this.Execute(e, list[i]);
|
||||
}
|
||||
|
||||
public virtual void Execute(CommandEventArgs e, object obj)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool ValidateArgs(BaseCommandImplementor impl, CommandEventArgs e)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddResponse(string message)
|
||||
{
|
||||
for (int i = 0; i < this.m_Responses.Count; ++i)
|
||||
{
|
||||
MessageEntry entry = (MessageEntry)this.m_Responses[i];
|
||||
|
||||
if (entry.m_Message == message)
|
||||
{
|
||||
++entry.m_Count;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_Responses.Count == 10)
|
||||
return;
|
||||
|
||||
this.m_Responses.Add(new MessageEntry(message));
|
||||
}
|
||||
|
||||
public void AddResponse(Gump gump)
|
||||
{
|
||||
this.m_Responses.Add(gump);
|
||||
}
|
||||
|
||||
public void LogFailure(string message)
|
||||
{
|
||||
for (int i = 0; i < this.m_Failures.Count; ++i)
|
||||
{
|
||||
MessageEntry entry = (MessageEntry)this.m_Failures[i];
|
||||
|
||||
if (entry.m_Message == message)
|
||||
{
|
||||
++entry.m_Count;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_Failures.Count == 10)
|
||||
return;
|
||||
|
||||
this.m_Failures.Add(new MessageEntry(message));
|
||||
}
|
||||
|
||||
public void Flush(Mobile from, bool flushToLog)
|
||||
{
|
||||
if (this.m_Responses.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < this.m_Responses.Count; ++i)
|
||||
{
|
||||
object obj = this.m_Responses[i];
|
||||
|
||||
if (obj is MessageEntry)
|
||||
{
|
||||
from.SendMessage(((MessageEntry)obj).ToString());
|
||||
|
||||
if (flushToLog)
|
||||
CommandLogging.WriteLine(from, ((MessageEntry)obj).ToString());
|
||||
}
|
||||
else if (obj is Gump)
|
||||
{
|
||||
from.SendGump((Gump)obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < this.m_Failures.Count; ++i)
|
||||
from.SendMessage(((MessageEntry)this.m_Failures[i]).ToString());
|
||||
}
|
||||
|
||||
this.m_Responses.Clear();
|
||||
this.m_Failures.Clear();
|
||||
}
|
||||
|
||||
private class MessageEntry
|
||||
{
|
||||
public readonly string m_Message;
|
||||
public int m_Count;
|
||||
public MessageEntry(string message)
|
||||
{
|
||||
this.m_Message = message;
|
||||
this.m_Count = 1;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (this.m_Count > 1)
|
||||
return String.Format("{0} ({1})", this.m_Message, this.m_Count);
|
||||
|
||||
return this.m_Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1282
Scripts/Commands/Generic/Commands/Commands.cs
Normal file
1282
Scripts/Commands/Generic/Commands/Commands.cs
Normal file
File diff suppressed because it is too large
Load Diff
205
Scripts/Commands/Generic/Commands/DesignInsert.cs
Normal file
205
Scripts/Commands/Generic/Commands/DesignInsert.cs
Normal file
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Multis;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class DesignInsertCommand : BaseCommand
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
TargetCommands.Register(new DesignInsertCommand());
|
||||
}
|
||||
|
||||
public DesignInsertCommand()
|
||||
{
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Supports = CommandSupport.Single | CommandSupport.Area;
|
||||
this.Commands = new string[] { "DesignInsert" };
|
||||
this.ObjectTypes = ObjectTypes.Items;
|
||||
this.Usage = "DesignInsert [allItems=false]";
|
||||
this.Description = "Inserts multiple targeted items into a customizable house's design.";
|
||||
}
|
||||
|
||||
#region Single targeting mode
|
||||
public override void Execute(CommandEventArgs e, object obj)
|
||||
{
|
||||
Target t = new DesignInsertTarget(new List<HouseFoundation>(), (e.Length < 1 || !e.GetBoolean(0)));
|
||||
t.Invoke(e.Mobile, obj);
|
||||
}
|
||||
|
||||
private class DesignInsertTarget : Target
|
||||
{
|
||||
private readonly List<HouseFoundation> m_Foundations;
|
||||
private readonly bool m_StaticsOnly;
|
||||
|
||||
public DesignInsertTarget(List<HouseFoundation> foundations, bool staticsOnly)
|
||||
: base(-1, false, TargetFlags.None)
|
||||
{
|
||||
this.m_Foundations = foundations;
|
||||
this.m_StaticsOnly = staticsOnly;
|
||||
}
|
||||
|
||||
protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType)
|
||||
{
|
||||
if (this.m_Foundations.Count != 0)
|
||||
{
|
||||
from.SendMessage("Your changes have been committed. Updating...");
|
||||
|
||||
foreach (HouseFoundation house in this.m_Foundations)
|
||||
house.Delta(ItemDelta.Update);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnTarget(Mobile from, object obj)
|
||||
{
|
||||
HouseFoundation house;
|
||||
DesignInsertResult result = ProcessInsert(obj as Item, this.m_StaticsOnly, out house);
|
||||
|
||||
switch ( result )
|
||||
{
|
||||
case DesignInsertResult.Valid:
|
||||
{
|
||||
if (this.m_Foundations.Count == 0)
|
||||
from.SendMessage("The item has been inserted into the house design. Press ESC when you are finished.");
|
||||
else
|
||||
from.SendMessage("The item has been inserted into the house design.");
|
||||
|
||||
if (!this.m_Foundations.Contains(house))
|
||||
this.m_Foundations.Add(house);
|
||||
|
||||
break;
|
||||
}
|
||||
case DesignInsertResult.InvalidItem:
|
||||
{
|
||||
from.SendMessage("That cannot be inserted. Try again.");
|
||||
break;
|
||||
}
|
||||
case DesignInsertResult.NotInHouse:
|
||||
case DesignInsertResult.OutsideHouseBounds:
|
||||
{
|
||||
from.SendMessage("That item is not inside a customizable house. Try again.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
from.Target = new DesignInsertTarget(this.m_Foundations, this.m_StaticsOnly);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Area targeting mode
|
||||
public override void ExecuteList(CommandEventArgs e, ArrayList list)
|
||||
{
|
||||
e.Mobile.SendGump(new WarningGump(1060637, 30720, String.Format("You are about to insert {0} objects. This cannot be undone without a full server revert.<br><br>Continue?", list.Count), 0xFFC000, 420, 280, new WarningGumpCallback(OnConfirmCallback), new object[] { e, list, (e.Length < 1 || !e.GetBoolean(0)) }));
|
||||
this.AddResponse("Awaiting confirmation...");
|
||||
}
|
||||
|
||||
private void OnConfirmCallback(Mobile from, bool okay, object state)
|
||||
{
|
||||
object[] states = (object[])state;
|
||||
CommandEventArgs e = (CommandEventArgs)states[0];
|
||||
ArrayList list = (ArrayList)states[1];
|
||||
bool staticsOnly = (bool)states[2];
|
||||
|
||||
bool flushToLog = false;
|
||||
|
||||
if (okay)
|
||||
{
|
||||
List<HouseFoundation> foundations = new List<HouseFoundation>();
|
||||
flushToLog = (list.Count > 20);
|
||||
|
||||
for (int i = 0; i < list.Count; ++i)
|
||||
{
|
||||
HouseFoundation house;
|
||||
DesignInsertResult result = ProcessInsert(list[i] as Item, staticsOnly, out house);
|
||||
|
||||
switch ( result )
|
||||
{
|
||||
case DesignInsertResult.Valid:
|
||||
{
|
||||
this.AddResponse("The item has been inserted into the house design.");
|
||||
|
||||
if (!foundations.Contains(house))
|
||||
foundations.Add(house);
|
||||
|
||||
break;
|
||||
}
|
||||
case DesignInsertResult.InvalidItem:
|
||||
{
|
||||
this.LogFailure("That cannot be inserted.");
|
||||
break;
|
||||
}
|
||||
case DesignInsertResult.NotInHouse:
|
||||
case DesignInsertResult.OutsideHouseBounds:
|
||||
{
|
||||
this.LogFailure("That item is not inside a customizable house.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (HouseFoundation house in foundations)
|
||||
house.Delta(ItemDelta.Update);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AddResponse("Command aborted.");
|
||||
}
|
||||
|
||||
this.Flush(from, flushToLog);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public enum DesignInsertResult
|
||||
{
|
||||
Valid,
|
||||
InvalidItem,
|
||||
NotInHouse,
|
||||
OutsideHouseBounds
|
||||
}
|
||||
|
||||
public static DesignInsertResult ProcessInsert(Item item, bool staticsOnly, out HouseFoundation house)
|
||||
{
|
||||
house = null;
|
||||
|
||||
if (item == null || item is BaseMulti || item is HouseSign || (staticsOnly && !(item is Static)))
|
||||
return DesignInsertResult.InvalidItem;
|
||||
|
||||
house = BaseHouse.FindHouseAt(item) as HouseFoundation;
|
||||
|
||||
if (house == null)
|
||||
return DesignInsertResult.NotInHouse;
|
||||
|
||||
int x = item.X - house.X;
|
||||
int y = item.Y - house.Y;
|
||||
int z = item.Z - house.Z;
|
||||
|
||||
if (!TryInsertIntoState(house.CurrentState, item.ItemID, x, y, z))
|
||||
return DesignInsertResult.OutsideHouseBounds;
|
||||
|
||||
TryInsertIntoState(house.DesignState, item.ItemID, x, y, z);
|
||||
item.Delete();
|
||||
|
||||
return DesignInsertResult.Valid;
|
||||
}
|
||||
|
||||
private static bool TryInsertIntoState(DesignState state, int itemID, int x, int y, int z)
|
||||
{
|
||||
MultiComponentList mcl = state.Components;
|
||||
|
||||
if (x < mcl.Min.X || y < mcl.Min.Y || x > mcl.Max.X || y > mcl.Max.Y)
|
||||
return false;
|
||||
|
||||
mcl.Add(itemID, x, y, z);
|
||||
state.OnRevised();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
557
Scripts/Commands/Generic/Commands/Interface.cs
Normal file
557
Scripts/Commands/Generic/Commands/Interface.cs
Normal file
@@ -0,0 +1,557 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Server.Gumps;
|
||||
using Server.Network;
|
||||
using Server.Targets;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class InterfaceCommand : BaseCommand
|
||||
{
|
||||
public InterfaceCommand()
|
||||
{
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Supports = CommandSupport.Complex | CommandSupport.Simple;
|
||||
this.Commands = new string[] { "Interface" };
|
||||
this.ObjectTypes = ObjectTypes.Both;
|
||||
this.Usage = "Interface [view <properties ...>]";
|
||||
this.Description = "Opens an interface to interact with matched objects. Generally used with condition arguments.";
|
||||
this.ListOptimized = true;
|
||||
}
|
||||
|
||||
public override void ExecuteList(CommandEventArgs e, ArrayList list)
|
||||
{
|
||||
if (list.Count > 0)
|
||||
{
|
||||
List<string> columns = new List<string>();
|
||||
|
||||
columns.Add("Object");
|
||||
|
||||
if (e.Length > 0)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
if (Insensitive.Equals(e.GetString(0), "view"))
|
||||
++offset;
|
||||
|
||||
while (offset < e.Length)
|
||||
columns.Add(e.GetString(offset++));
|
||||
}
|
||||
|
||||
e.Mobile.SendGump(new InterfaceGump(e.Mobile, columns.ToArray(), list, 0, null));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AddResponse("No matching objects found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class InterfaceGump : BaseGridGump
|
||||
{
|
||||
private const int EntriesPerPage = 15;
|
||||
private readonly Mobile m_From;
|
||||
private readonly string[] m_Columns;
|
||||
private readonly ArrayList m_List;
|
||||
private readonly int m_Page;
|
||||
private readonly object m_Select;
|
||||
public InterfaceGump(Mobile from, string[] columns, ArrayList list, int page, object select)
|
||||
: base(30, 30)
|
||||
{
|
||||
this.m_From = from;
|
||||
|
||||
this.m_Columns = columns;
|
||||
|
||||
this.m_List = list;
|
||||
this.m_Page = page;
|
||||
|
||||
this.m_Select = select;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
this.AddNewPage();
|
||||
|
||||
if (this.m_Page > 0)
|
||||
this.AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
|
||||
else
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
this.AddEntryHtml(40 + (this.m_Columns.Length * 130) - 20 + ((this.m_Columns.Length - 2) * this.OffsetSize), this.Center(String.Format("Page {0} of {1}", this.m_Page + 1, (this.m_List.Count + EntriesPerPage - 1) / EntriesPerPage)));
|
||||
|
||||
if ((this.m_Page + 1) * EntriesPerPage < this.m_List.Count)
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
|
||||
else
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
if (this.m_Columns.Length > 1)
|
||||
{
|
||||
this.AddNewLine();
|
||||
|
||||
for (int i = 0; i < this.m_Columns.Length; ++i)
|
||||
{
|
||||
if (i > 0 && this.m_List.Count > 0)
|
||||
{
|
||||
object obj = this.m_List[0];
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
string failReason = null;
|
||||
PropertyInfo[] chain = Properties.GetPropertyInfoChain(this.m_From, obj.GetType(), this.m_Columns[i], PropertyAccess.Read, ref failReason);
|
||||
|
||||
if (chain != null && chain.Length > 0)
|
||||
{
|
||||
this.m_Columns[i] = "";
|
||||
|
||||
for (int j = 0; j < chain.Length; ++j)
|
||||
{
|
||||
if (j > 0)
|
||||
this.m_Columns[i] += '.';
|
||||
|
||||
this.m_Columns[i] += chain[j].Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.AddEntryHtml(130 + (i == 0 ? 40 : 0), this.m_Columns[i]);
|
||||
}
|
||||
|
||||
this.AddEntryHeader(20);
|
||||
}
|
||||
|
||||
for (int i = this.m_Page * EntriesPerPage, line = 0; line < EntriesPerPage && i < this.m_List.Count; ++i, ++line)
|
||||
{
|
||||
this.AddNewLine();
|
||||
|
||||
object obj = this.m_List[i];
|
||||
bool isDeleted = false;
|
||||
|
||||
if (obj is Item)
|
||||
{
|
||||
Item item = (Item)obj;
|
||||
|
||||
if (!(isDeleted = item.Deleted))
|
||||
this.AddEntryHtml(40 + 130, item.GetType().Name);
|
||||
}
|
||||
else if (obj is Mobile)
|
||||
{
|
||||
Mobile mob = (Mobile)obj;
|
||||
|
||||
if (!(isDeleted = mob.Deleted))
|
||||
this.AddEntryHtml(40 + 130, mob.Name);
|
||||
}
|
||||
|
||||
if (isDeleted)
|
||||
{
|
||||
this.AddEntryHtml(40 + 130, "(deleted)");
|
||||
|
||||
for (int j = 1; j < this.m_Columns.Length; ++j)
|
||||
this.AddEntryHtml(130, "---");
|
||||
|
||||
this.AddEntryHeader(20);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 1; j < this.m_Columns.Length; ++j)
|
||||
{
|
||||
object src = obj;
|
||||
|
||||
string value;
|
||||
string failReason = "";
|
||||
|
||||
PropertyInfo[] chain = Properties.GetPropertyInfoChain(this.m_From, src.GetType(), this.m_Columns[j], PropertyAccess.Read, ref failReason);
|
||||
|
||||
if (chain == null || chain.Length == 0)
|
||||
{
|
||||
value = "---";
|
||||
}
|
||||
else
|
||||
{
|
||||
PropertyInfo p = Properties.GetPropertyInfo(ref src, chain, ref failReason);
|
||||
|
||||
if (p == null)
|
||||
value = "---";
|
||||
else
|
||||
value = PropertiesGump.ValueToString(src, p);
|
||||
}
|
||||
|
||||
this.AddEntryHtml(130, value);
|
||||
}
|
||||
|
||||
bool isSelected = (this.m_Select != null && obj == this.m_Select);
|
||||
|
||||
this.AddEntryButton(20, (isSelected ? 9762 : ArrowRightID1), (isSelected ? 9763 : ArrowRightID2), 3 + i, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
}
|
||||
|
||||
this.FinishPage();
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
switch ( info.ButtonID )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if (this.m_Page > 0)
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page - 1, this.m_Select));
|
||||
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if ((this.m_Page + 1) * EntriesPerPage < this.m_List.Count)
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page + 1, this.m_Select));
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
int v = info.ButtonID - 3;
|
||||
|
||||
if (v >= 0 && v < this.m_List.Count)
|
||||
{
|
||||
object obj = this.m_List[v];
|
||||
|
||||
if (!BaseCommand.IsAccessible(this.m_From, obj))
|
||||
{
|
||||
this.m_From.SendMessage("That is not accessible.");
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Select));
|
||||
break;
|
||||
}
|
||||
|
||||
if (obj is Item && !((Item)obj).Deleted)
|
||||
this.m_From.SendGump(new InterfaceItemGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, (Item)obj));
|
||||
else if (obj is Mobile && !((Mobile)obj).Deleted)
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, (Mobile)obj));
|
||||
else
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Select));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class InterfaceItemGump : BaseGridGump
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly string[] m_Columns;
|
||||
private readonly ArrayList m_List;
|
||||
private readonly int m_Page;
|
||||
private readonly Item m_Item;
|
||||
public InterfaceItemGump(Mobile from, string[] columns, ArrayList list, int page, Item item)
|
||||
: base(30, 30)
|
||||
{
|
||||
this.m_From = from;
|
||||
|
||||
this.m_Columns = columns;
|
||||
|
||||
this.m_List = list;
|
||||
this.m_Page = page;
|
||||
|
||||
this.m_Item = item;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
this.AddNewPage();
|
||||
|
||||
this.AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
|
||||
this.AddEntryHtml(160, this.m_Item.GetType().Name);
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Properties");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Delete");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Go there");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Move to target");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Bring to pack");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.FinishPage();
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Item.Deleted)
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
return;
|
||||
}
|
||||
else if (!BaseCommand.IsAccessible(this.m_From, this.m_Item))
|
||||
{
|
||||
this.m_From.SendMessage("That is no longer accessible.");
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( info.ButtonID )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
break;
|
||||
}
|
||||
case 2: // Properties
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceItemGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
this.m_From.SendGump(new PropertiesGump(this.m_From, this.m_Item));
|
||||
break;
|
||||
}
|
||||
case 3: // Delete
|
||||
{
|
||||
CommandLogging.WriteLine(this.m_From, "{0} {1} deleting {2}", this.m_From.AccessLevel, CommandLogging.Format(this.m_From), CommandLogging.Format(this.m_Item));
|
||||
this.m_Item.Delete();
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
break;
|
||||
}
|
||||
case 4: // Go there
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceItemGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
this.InvokeCommand(String.Format("Go {0}", this.m_Item.Serial.Value));
|
||||
break;
|
||||
}
|
||||
case 5: // Move to target
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceItemGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
this.m_From.Target = new MoveTarget(this.m_Item);
|
||||
break;
|
||||
}
|
||||
case 6: // Bring to pack
|
||||
{
|
||||
Mobile owner = this.m_Item.RootParent as Mobile;
|
||||
|
||||
if (owner != null && (owner.Map != null && owner.Map != Map.Internal) && !BaseCommand.IsAccessible(this.m_From, owner) /* !m_From.CanSee( owner )*/)
|
||||
{
|
||||
this.m_From.SendMessage("You can not get what you can not see.");
|
||||
}
|
||||
else if (owner != null && (owner.Map == null || owner.Map == Map.Internal) && owner.Hidden && owner.AccessLevel >= this.m_From.AccessLevel)
|
||||
{
|
||||
this.m_From.SendMessage("You can not get what you can not see.");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceItemGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Item));
|
||||
this.m_From.AddToBackpack(this.m_Item);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeCommand(string ip)
|
||||
{
|
||||
CommandSystem.Handle(this.m_From, String.Format("{0}{1}", CommandSystem.Prefix, ip));
|
||||
}
|
||||
}
|
||||
|
||||
public class InterfaceMobileGump : BaseGridGump
|
||||
{
|
||||
private readonly Mobile m_From;
|
||||
private readonly string[] m_Columns;
|
||||
private readonly ArrayList m_List;
|
||||
private readonly int m_Page;
|
||||
private readonly Mobile m_Mobile;
|
||||
public InterfaceMobileGump(Mobile from, string[] columns, ArrayList list, int page, Mobile mob)
|
||||
: base(30, 30)
|
||||
{
|
||||
this.m_From = from;
|
||||
|
||||
this.m_Columns = columns;
|
||||
|
||||
this.m_List = list;
|
||||
this.m_Page = page;
|
||||
|
||||
this.m_Mobile = mob;
|
||||
|
||||
this.Render();
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
this.AddNewPage();
|
||||
|
||||
this.AddEntryButton(20, ArrowLeftID1, ArrowLeftID2, 1, ArrowLeftWidth, ArrowLeftHeight);
|
||||
this.AddEntryHtml(160, this.m_Mobile.Name);
|
||||
this.AddEntryHeader(20);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Properties");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 2, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
if (!this.m_Mobile.Player)
|
||||
{
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Delete");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 3, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
|
||||
if (this.m_Mobile != this.m_From)
|
||||
{
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Go to there");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 4, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Bring them here");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 5, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Move to target");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 6, ArrowRightWidth, ArrowRightHeight);
|
||||
|
||||
if (this.m_From == this.m_Mobile || this.m_From.AccessLevel > this.m_Mobile.AccessLevel)
|
||||
{
|
||||
this.AddNewLine();
|
||||
if (this.m_Mobile.Alive)
|
||||
{
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Kill");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 7, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Resurrect");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 8, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_Mobile.NetState != null)
|
||||
{
|
||||
this.AddNewLine();
|
||||
this.AddEntryHtml(20 + this.OffsetSize + 160, "Client");
|
||||
this.AddEntryButton(20, ArrowRightID1, ArrowRightID2, 9, ArrowRightWidth, ArrowRightHeight);
|
||||
}
|
||||
|
||||
this.FinishPage();
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (this.m_Mobile.Deleted)
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
return;
|
||||
}
|
||||
else if (!BaseCommand.IsAccessible(this.m_From, this.m_Mobile))
|
||||
{
|
||||
this.m_From.SendMessage("That is no longer accessible.");
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( info.ButtonID )
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
break;
|
||||
}
|
||||
case 2: // Properties
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
this.m_From.SendGump(new PropertiesGump(this.m_From, this.m_Mobile));
|
||||
break;
|
||||
}
|
||||
case 3: // Delete
|
||||
{
|
||||
if (!this.m_Mobile.Player)
|
||||
{
|
||||
CommandLogging.WriteLine(this.m_From, "{0} {1} deleting {2}", this.m_From.AccessLevel, CommandLogging.Format(this.m_From), CommandLogging.Format(this.m_Mobile));
|
||||
this.m_Mobile.Delete();
|
||||
this.m_From.SendGump(new InterfaceGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 4: // Go there
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
this.InvokeCommand(String.Format("Go {0}", this.m_Mobile.Serial.Value));
|
||||
break;
|
||||
}
|
||||
case 5: // Bring them here
|
||||
{
|
||||
if (this.m_From.Map == null || this.m_From.Map == Map.Internal)
|
||||
{
|
||||
this.m_From.SendMessage("You cannot bring that person here.");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
this.m_Mobile.MoveToWorld(this.m_From.Location, this.m_From.Map);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 6: // Move to target
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
this.m_From.Target = new MoveTarget(this.m_Mobile);
|
||||
break;
|
||||
}
|
||||
case 7: // Kill
|
||||
{
|
||||
if (this.m_From == this.m_Mobile || this.m_From.AccessLevel > this.m_Mobile.AccessLevel)
|
||||
this.m_Mobile.Kill();
|
||||
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
|
||||
break;
|
||||
}
|
||||
case 8: // Res
|
||||
{
|
||||
if (this.m_From == this.m_Mobile || this.m_From.AccessLevel > this.m_Mobile.AccessLevel)
|
||||
{
|
||||
this.m_Mobile.PlaySound(0x214);
|
||||
this.m_Mobile.FixedEffect(0x376A, 10, 16);
|
||||
|
||||
this.m_Mobile.Resurrect();
|
||||
}
|
||||
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
|
||||
break;
|
||||
}
|
||||
case 9: // Client
|
||||
{
|
||||
this.m_From.SendGump(new InterfaceMobileGump(this.m_From, this.m_Columns, this.m_List, this.m_Page, this.m_Mobile));
|
||||
|
||||
if (this.m_Mobile.NetState != null)
|
||||
this.m_From.SendGump(new ClientGump(this.m_From, this.m_Mobile.NetState));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InvokeCommand(string ip)
|
||||
{
|
||||
CommandSystem.Handle(this.m_From, String.Format("{0}{1}", CommandSystem.Prefix, ip));
|
||||
}
|
||||
}
|
||||
}
|
||||
198
Scripts/Commands/Generic/Extensions/BaseExtension.cs
Normal file
198
Scripts/Commands/Generic/Extensions/BaseExtension.cs
Normal file
@@ -0,0 +1,198 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public delegate BaseExtension ExtensionConstructor();
|
||||
|
||||
public sealed class ExtensionInfo
|
||||
{
|
||||
private static readonly Dictionary<string, ExtensionInfo> m_Table = new Dictionary<string, ExtensionInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||
private readonly int m_Order;
|
||||
private readonly string m_Name;
|
||||
private readonly int m_Size;
|
||||
private readonly ExtensionConstructor m_Constructor;
|
||||
public ExtensionInfo(int order, string name, int size, ExtensionConstructor constructor)
|
||||
{
|
||||
this.m_Name = name;
|
||||
this.m_Size = size;
|
||||
|
||||
this.m_Order = order;
|
||||
|
||||
this.m_Constructor = constructor;
|
||||
}
|
||||
|
||||
public static Dictionary<string, ExtensionInfo> Table
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Table;
|
||||
}
|
||||
}
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Order;
|
||||
}
|
||||
}
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Name;
|
||||
}
|
||||
}
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Size;
|
||||
}
|
||||
}
|
||||
public bool IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Size >= 0);
|
||||
}
|
||||
}
|
||||
public ExtensionConstructor Constructor
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Constructor;
|
||||
}
|
||||
}
|
||||
public static void Register(ExtensionInfo ext)
|
||||
{
|
||||
m_Table[ext.m_Name] = ext;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Extensions : List<BaseExtension>
|
||||
{
|
||||
public Extensions()
|
||||
{
|
||||
}
|
||||
|
||||
public static Extensions Parse(Mobile from, ref string[] args)
|
||||
{
|
||||
Extensions parsed = new Extensions();
|
||||
|
||||
int size = args.Length;
|
||||
|
||||
Type baseType = null;
|
||||
|
||||
for (int i = args.Length - 1; i >= 0; --i)
|
||||
{
|
||||
ExtensionInfo extInfo = null;
|
||||
|
||||
if (!ExtensionInfo.Table.TryGetValue(args[i], out extInfo))
|
||||
continue;
|
||||
|
||||
if (extInfo.IsFixedSize && i != (size - extInfo.Size - 1))
|
||||
throw new Exception("Invalid extended argument count.");
|
||||
|
||||
BaseExtension ext = extInfo.Constructor();
|
||||
|
||||
ext.Parse(from, args, i + 1, size - i - 1);
|
||||
|
||||
if (ext is WhereExtension)
|
||||
baseType = (ext as WhereExtension).Conditional.Type;
|
||||
|
||||
parsed.Add(ext);
|
||||
|
||||
size = i;
|
||||
}
|
||||
|
||||
parsed.Sort(delegate(BaseExtension a, BaseExtension b)
|
||||
{
|
||||
return (a.Order - b.Order);
|
||||
});
|
||||
|
||||
AssemblyEmitter emitter = null;
|
||||
|
||||
foreach (BaseExtension update in parsed)
|
||||
update.Optimize(from, baseType, ref emitter);
|
||||
|
||||
if (size != args.Length)
|
||||
{
|
||||
string[] old = args;
|
||||
args = new string[size];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
args[i] = old[i];
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
public bool IsValid(object obj)
|
||||
{
|
||||
for (int i = 0; i < this.Count; ++i)
|
||||
{
|
||||
if (!this[i].IsValid(obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Filter(ArrayList list)
|
||||
{
|
||||
for (int i = 0; i < this.Count; ++i)
|
||||
this[i].Filter(list);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BaseExtension
|
||||
{
|
||||
public abstract ExtensionInfo Info { get; }
|
||||
public string Name
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Name;
|
||||
}
|
||||
}
|
||||
public int Size
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Size;
|
||||
}
|
||||
}
|
||||
public bool IsFixedSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.IsFixedSize;
|
||||
}
|
||||
}
|
||||
public int Order
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.Info.Order;
|
||||
}
|
||||
}
|
||||
public virtual void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool IsValid(object obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public virtual void Filter(ArrayList list)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,549 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public interface IConditional
|
||||
{
|
||||
bool Verify(object obj);
|
||||
}
|
||||
|
||||
public interface ICondition
|
||||
{
|
||||
// Invoked during the constructor
|
||||
void Construct(TypeBuilder typeBuilder, ILGenerator il, int index);
|
||||
|
||||
// Target object will be loaded on the stack
|
||||
void Compile(MethodEmitter emitter);
|
||||
}
|
||||
|
||||
public sealed class TypeCondition : ICondition
|
||||
{
|
||||
public static TypeCondition Default = new TypeCondition();
|
||||
|
||||
void ICondition.Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
}
|
||||
|
||||
void ICondition.Compile(MethodEmitter emitter)
|
||||
{
|
||||
// The object was safely cast to be the conditionals type
|
||||
// If it's null, then the type cast didn't work...
|
||||
emitter.LoadNull();
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PropertyValue
|
||||
{
|
||||
private readonly Type m_Type;
|
||||
private object m_Value;
|
||||
private FieldInfo m_Field;
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Type;
|
||||
}
|
||||
}
|
||||
|
||||
public object Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Value;
|
||||
}
|
||||
}
|
||||
|
||||
public FieldInfo Field
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Field;
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasField
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Field != null);
|
||||
}
|
||||
}
|
||||
|
||||
public PropertyValue(Type type, object value)
|
||||
{
|
||||
this.m_Type = type;
|
||||
this.m_Value = value;
|
||||
}
|
||||
|
||||
public void Load(MethodEmitter method)
|
||||
{
|
||||
if (this.m_Field != null)
|
||||
{
|
||||
method.LoadArgument(0);
|
||||
method.LoadField(this.m_Field);
|
||||
}
|
||||
else if (this.m_Value == null)
|
||||
{
|
||||
method.LoadNull(this.m_Type);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.m_Value is int)
|
||||
method.Load((int)this.m_Value);
|
||||
else if (this.m_Value is long)
|
||||
method.Load((long)this.m_Value);
|
||||
else if (this.m_Value is float)
|
||||
method.Load((float)this.m_Value);
|
||||
else if (this.m_Value is double)
|
||||
method.Load((double)this.m_Value);
|
||||
else if (this.m_Value is char)
|
||||
method.Load((char)this.m_Value);
|
||||
else if (this.m_Value is bool)
|
||||
method.Load((bool)this.m_Value);
|
||||
else if (this.m_Value is string)
|
||||
method.Load((string)this.m_Value);
|
||||
else if (this.m_Value is Enum)
|
||||
method.Load((Enum)this.m_Value);
|
||||
else
|
||||
throw new InvalidOperationException("Unrecognized comparison value.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Acquire(TypeBuilder typeBuilder, ILGenerator il, string fieldName)
|
||||
{
|
||||
if (this.m_Value is string)
|
||||
{
|
||||
string toParse = (string)this.m_Value;
|
||||
|
||||
if (!this.m_Type.IsValueType && toParse == "null")
|
||||
{
|
||||
this.m_Value = null;
|
||||
}
|
||||
else if (this.m_Type == typeof(string))
|
||||
{
|
||||
if (toParse == @"@""null""")
|
||||
toParse = "null";
|
||||
|
||||
this.m_Value = toParse;
|
||||
}
|
||||
else if (this.m_Type.IsEnum)
|
||||
{
|
||||
this.m_Value = Enum.Parse(this.m_Type, toParse, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodInfo parseMethod = null;
|
||||
object[] parseArgs = null;
|
||||
|
||||
MethodInfo parseNumber = this.m_Type.GetMethod(
|
||||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[] { typeof(string), typeof(NumberStyles) },
|
||||
null);
|
||||
|
||||
if (parseNumber != null)
|
||||
{
|
||||
NumberStyles style = NumberStyles.Integer;
|
||||
|
||||
if (Insensitive.StartsWith(toParse, "0x"))
|
||||
{
|
||||
style = NumberStyles.HexNumber;
|
||||
toParse = toParse.Substring(2);
|
||||
}
|
||||
|
||||
parseMethod = parseNumber;
|
||||
parseArgs = new object[] { toParse, style };
|
||||
}
|
||||
else
|
||||
{
|
||||
MethodInfo parseGeneral = this.m_Type.GetMethod(
|
||||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[] { typeof(string) },
|
||||
null);
|
||||
|
||||
parseMethod = parseGeneral;
|
||||
parseArgs = new object[] { toParse };
|
||||
}
|
||||
|
||||
if (parseMethod != null)
|
||||
{
|
||||
this.m_Value = parseMethod.Invoke(null, parseArgs);
|
||||
|
||||
if (!this.m_Type.IsPrimitive)
|
||||
{
|
||||
this.m_Field = typeBuilder.DefineField(
|
||||
fieldName,
|
||||
this.m_Type,
|
||||
FieldAttributes.Private | FieldAttributes.InitOnly);
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
il.Emit(OpCodes.Ldstr, toParse);
|
||||
|
||||
if (parseArgs.Length == 2) // dirty evil hack :-(
|
||||
il.Emit(OpCodes.Ldc_I4, (int)parseArgs[1]);
|
||||
|
||||
il.Emit(OpCodes.Call, parseMethod);
|
||||
il.Emit(OpCodes.Stfld, this.m_Field);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
String.Format(
|
||||
"Unable to convert string \"{0}\" into type '{1}'.",
|
||||
this.m_Value,
|
||||
this.m_Type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class PropertyCondition : ICondition
|
||||
{
|
||||
protected Property m_Property;
|
||||
protected bool m_Not;
|
||||
|
||||
public PropertyCondition(Property property, bool not)
|
||||
{
|
||||
this.m_Property = property;
|
||||
this.m_Not = not;
|
||||
}
|
||||
|
||||
public abstract void Construct(TypeBuilder typeBuilder, ILGenerator il, int index);
|
||||
|
||||
public abstract void Compile(MethodEmitter emitter);
|
||||
}
|
||||
|
||||
public enum StringOperator
|
||||
{
|
||||
Equal,
|
||||
NotEqual,
|
||||
|
||||
Contains,
|
||||
|
||||
StartsWith,
|
||||
EndsWith
|
||||
}
|
||||
|
||||
public sealed class StringCondition : PropertyCondition
|
||||
{
|
||||
private readonly StringOperator m_Operator;
|
||||
private readonly PropertyValue m_Value;
|
||||
|
||||
private readonly bool m_IgnoreCase;
|
||||
|
||||
public StringCondition(Property property, bool not, StringOperator op, object value, bool ignoreCase)
|
||||
: base(property, not)
|
||||
{
|
||||
this.m_Operator = op;
|
||||
this.m_Value = new PropertyValue(property.Type, value);
|
||||
|
||||
this.m_IgnoreCase = ignoreCase;
|
||||
}
|
||||
|
||||
public override void Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
this.m_Value.Acquire(typeBuilder, il, "v" + index);
|
||||
}
|
||||
|
||||
public override void Compile(MethodEmitter emitter)
|
||||
{
|
||||
bool inverse = false;
|
||||
|
||||
string methodName;
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case StringOperator.Equal:
|
||||
methodName = "Equals";
|
||||
break;
|
||||
case StringOperator.NotEqual:
|
||||
methodName = "Equals";
|
||||
inverse = true;
|
||||
break;
|
||||
case StringOperator.Contains:
|
||||
methodName = "Contains";
|
||||
break;
|
||||
case StringOperator.StartsWith:
|
||||
methodName = "StartsWith";
|
||||
break;
|
||||
case StringOperator.EndsWith:
|
||||
methodName = "EndsWith";
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid string comparison operator.");
|
||||
}
|
||||
|
||||
if (this.m_IgnoreCase || methodName == "Equals")
|
||||
{
|
||||
Type type = (this.m_IgnoreCase ? typeof(Insensitive) : typeof(String));
|
||||
|
||||
emitter.BeginCall(
|
||||
type.GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new Type[]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(string)
|
||||
},
|
||||
null));
|
||||
|
||||
emitter.Chain(this.m_Property);
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
emitter.FinishCall();
|
||||
}
|
||||
else
|
||||
{
|
||||
Label notNull = emitter.CreateLabel();
|
||||
Label moveOn = emitter.CreateLabel();
|
||||
|
||||
LocalBuilder temp = emitter.AcquireTemp(this.m_Property.Type);
|
||||
|
||||
emitter.Chain(this.m_Property);
|
||||
|
||||
emitter.StoreLocal(temp);
|
||||
emitter.LoadLocal(temp);
|
||||
|
||||
emitter.BranchIfTrue(notNull);
|
||||
|
||||
emitter.Load(false);
|
||||
emitter.Pop();
|
||||
emitter.Branch(moveOn);
|
||||
|
||||
emitter.MarkLabel(notNull);
|
||||
emitter.LoadLocal(temp);
|
||||
|
||||
emitter.BeginCall(
|
||||
typeof(string).GetMethod(
|
||||
methodName,
|
||||
BindingFlags.Public | BindingFlags.Instance,
|
||||
null,
|
||||
new Type[]
|
||||
{
|
||||
typeof(string)
|
||||
},
|
||||
null));
|
||||
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
emitter.FinishCall();
|
||||
|
||||
emitter.MarkLabel(moveOn);
|
||||
}
|
||||
|
||||
if (this.m_Not != inverse)
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public enum ComparisonOperator
|
||||
{
|
||||
Equal,
|
||||
NotEqual,
|
||||
Greater,
|
||||
GreaterEqual,
|
||||
Lesser,
|
||||
LesserEqual
|
||||
}
|
||||
|
||||
public sealed class ComparisonCondition : PropertyCondition
|
||||
{
|
||||
private readonly ComparisonOperator m_Operator;
|
||||
private readonly PropertyValue m_Value;
|
||||
|
||||
public ComparisonCondition(Property property, bool not, ComparisonOperator op, object value)
|
||||
: base(property, not)
|
||||
{
|
||||
this.m_Operator = op;
|
||||
this.m_Value = new PropertyValue(property.Type, value);
|
||||
}
|
||||
|
||||
public override void Construct(TypeBuilder typeBuilder, ILGenerator il, int index)
|
||||
{
|
||||
this.m_Value.Acquire(typeBuilder, il, "v" + index);
|
||||
}
|
||||
|
||||
public override void Compile(MethodEmitter emitter)
|
||||
{
|
||||
emitter.Chain(this.m_Property);
|
||||
|
||||
bool inverse = false;
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(1, delegate()
|
||||
{
|
||||
this.m_Value.Load(emitter);
|
||||
});
|
||||
|
||||
if (couldCompare)
|
||||
{
|
||||
emitter.Load(0);
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Greater:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
break;
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Lesser:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
break;
|
||||
case ComparisonOperator.LesserEqual:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
inverse = true;
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid comparison operator.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This type is -not- comparable
|
||||
// We can only support == and != operations
|
||||
this.m_Value.Load(emitter);
|
||||
|
||||
switch ( this.m_Operator )
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
case ComparisonOperator.Greater:
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
case ComparisonOperator.Lesser:
|
||||
case ComparisonOperator.LesserEqual:
|
||||
throw new InvalidOperationException("Property does not support relational comparisons.");
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operator.");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.m_Not != inverse)
|
||||
emitter.LogicalNot();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConditionalCompiler
|
||||
{
|
||||
public static IConditional Compile(AssemblyEmitter assembly, Type objectType, ICondition[] conditions, int index)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__conditional" + index,
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
for (int i = 0; i < conditions.Length; ++i)
|
||||
conditions[i].Construct(typeBuilder, il, i);
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IConditional));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Verify",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(bool),
|
||||
/* params */ new Type[] { typeof(object) });
|
||||
|
||||
LocalBuilder obj = emitter.CreateLocal(objectType);
|
||||
LocalBuilder eq = emitter.CreateLocal(typeof(bool));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(obj);
|
||||
|
||||
Label done = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < conditions.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(eq);
|
||||
|
||||
emitter.BranchIfFalse(done);
|
||||
}
|
||||
|
||||
emitter.LoadLocal(obj);
|
||||
|
||||
conditions[i].Compile(emitter);
|
||||
|
||||
emitter.StoreLocal(eq);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(done);
|
||||
|
||||
emitter.LoadLocal(eq);
|
||||
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IConditional).GetMethod(
|
||||
"Verify",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type conditionalType = typeBuilder.CreateType();
|
||||
|
||||
return (IConditional)Activator.CreateInstance(conditionalType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public static class DistinctCompiler
|
||||
{
|
||||
public static IComparer Compile(AssemblyEmitter assembly, Type objectType, Property[] props)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__distinct",
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IComparer));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Compare",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
LocalBuilder a = emitter.CreateLocal(objectType);
|
||||
LocalBuilder b = emitter.CreateLocal(objectType);
|
||||
|
||||
LocalBuilder v = emitter.CreateLocal(typeof(int));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(a);
|
||||
|
||||
emitter.LoadArgument(2);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(b);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.StoreLocal(v);
|
||||
|
||||
Label end = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < props.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(v);
|
||||
emitter.BranchIfTrue(end); // if ( v != 0 ) return v;
|
||||
}
|
||||
|
||||
Property prop = props[i];
|
||||
|
||||
emitter.LoadLocal(a);
|
||||
emitter.Chain(prop);
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(1, delegate()
|
||||
{
|
||||
emitter.LoadLocal(b);
|
||||
emitter.Chain(prop);
|
||||
});
|
||||
|
||||
if (!couldCompare)
|
||||
throw new InvalidOperationException("Property is not comparable.");
|
||||
|
||||
emitter.StoreLocal(v);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(end);
|
||||
|
||||
emitter.LoadLocal(v);
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IComparer).GetMethod(
|
||||
"Compare",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region IEqualityComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IEqualityComparer<object>));
|
||||
|
||||
#region Equals
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Equals",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(bool),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_0);
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_1);
|
||||
emitter.Generator.Emit(OpCodes.Ldarg_2);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Call, compareMethod);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ldc_I4_0);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ceq);
|
||||
|
||||
emitter.Generator.Emit(OpCodes.Ret);
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IEqualityComparer<object>).GetMethod(
|
||||
"Equals",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region GetHashCode
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "GetHashCode",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object) });
|
||||
|
||||
LocalBuilder obj = emitter.CreateLocal(objectType);
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(obj);
|
||||
|
||||
for (int i = 0; i < props.Length; ++i)
|
||||
{
|
||||
Property prop = props[i];
|
||||
|
||||
emitter.LoadLocal(obj);
|
||||
emitter.Chain(prop);
|
||||
|
||||
Type active = emitter.Active;
|
||||
|
||||
MethodInfo getHashCode = active.GetMethod("GetHashCode", Type.EmptyTypes);
|
||||
|
||||
if (getHashCode == null)
|
||||
getHashCode = typeof(object).GetMethod("GetHashCode", Type.EmptyTypes);
|
||||
|
||||
if (active != typeof(int))
|
||||
{
|
||||
if (!active.IsValueType)
|
||||
{
|
||||
LocalBuilder value = emitter.AcquireTemp(active);
|
||||
|
||||
Label valueNotNull = emitter.CreateLabel();
|
||||
Label done = emitter.CreateLabel();
|
||||
|
||||
emitter.StoreLocal(value);
|
||||
emitter.LoadLocal(value);
|
||||
|
||||
emitter.BranchIfTrue(valueNotNull);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.Pop(typeof(int));
|
||||
|
||||
emitter.Branch(done);
|
||||
|
||||
emitter.MarkLabel(valueNotNull);
|
||||
|
||||
emitter.LoadLocal(value);
|
||||
emitter.Call(getHashCode);
|
||||
|
||||
emitter.ReleaseTemp(value);
|
||||
|
||||
emitter.MarkLabel(done);
|
||||
}
|
||||
else
|
||||
{
|
||||
emitter.Call(getHashCode);
|
||||
}
|
||||
}
|
||||
|
||||
if (i > 0)
|
||||
emitter.Xor();
|
||||
}
|
||||
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IEqualityComparer<object>).GetMethod(
|
||||
"GetHashCode",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object)
|
||||
}));
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type comparerType = typeBuilder.CreateType();
|
||||
|
||||
return (IComparer)Activator.CreateInstance(comparerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
186
Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs
Normal file
186
Scripts/Commands/Generic/Extensions/Compilers/SortCompiler.cs
Normal file
@@ -0,0 +1,186 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class OrderInfo
|
||||
{
|
||||
private Property m_Property;
|
||||
private int m_Order;
|
||||
|
||||
public Property Property
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Property;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Property = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAscending
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Order > 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = (value ? +1 : -1);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsDescending
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Order < 0);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = (value ? -1 : +1);
|
||||
}
|
||||
}
|
||||
|
||||
public int Sign
|
||||
{
|
||||
get
|
||||
{
|
||||
return Math.Sign(this.m_Order);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Order = Math.Sign(value);
|
||||
|
||||
if (this.m_Order == 0)
|
||||
throw new InvalidOperationException("Sign cannot be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
public OrderInfo(Property property, bool isAscending)
|
||||
{
|
||||
this.m_Property = property;
|
||||
|
||||
this.IsAscending = isAscending;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SortCompiler
|
||||
{
|
||||
public static IComparer Compile(AssemblyEmitter assembly, Type objectType, OrderInfo[] orders)
|
||||
{
|
||||
TypeBuilder typeBuilder = assembly.DefineType(
|
||||
"__sort",
|
||||
TypeAttributes.Public,
|
||||
typeof(object));
|
||||
|
||||
#region Constructor
|
||||
{
|
||||
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
|
||||
MethodAttributes.Public,
|
||||
CallingConventions.Standard,
|
||||
Type.EmptyTypes);
|
||||
|
||||
ILGenerator il = ctor.GetILGenerator();
|
||||
|
||||
// : base()
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
|
||||
|
||||
// return;
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IComparer
|
||||
typeBuilder.AddInterfaceImplementation(typeof(IComparer));
|
||||
|
||||
MethodBuilder compareMethod;
|
||||
|
||||
#region Compare
|
||||
{
|
||||
MethodEmitter emitter = new MethodEmitter(typeBuilder);
|
||||
|
||||
emitter.Define(
|
||||
/* name */ "Compare",
|
||||
/* attr */ MethodAttributes.Public | MethodAttributes.Virtual,
|
||||
/* return */ typeof(int),
|
||||
/* params */ new Type[] { typeof(object), typeof(object) });
|
||||
|
||||
LocalBuilder a = emitter.CreateLocal(objectType);
|
||||
LocalBuilder b = emitter.CreateLocal(objectType);
|
||||
|
||||
LocalBuilder v = emitter.CreateLocal(typeof(int));
|
||||
|
||||
emitter.LoadArgument(1);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(a);
|
||||
|
||||
emitter.LoadArgument(2);
|
||||
emitter.CastAs(objectType);
|
||||
emitter.StoreLocal(b);
|
||||
|
||||
emitter.Load(0);
|
||||
emitter.StoreLocal(v);
|
||||
|
||||
Label end = emitter.CreateLabel();
|
||||
|
||||
for (int i = 0; i < orders.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
emitter.LoadLocal(v);
|
||||
emitter.BranchIfTrue(end); // if ( v != 0 ) return v;
|
||||
}
|
||||
|
||||
OrderInfo orderInfo = orders[i];
|
||||
|
||||
Property prop = orderInfo.Property;
|
||||
int sign = orderInfo.Sign;
|
||||
|
||||
emitter.LoadLocal(a);
|
||||
emitter.Chain(prop);
|
||||
|
||||
bool couldCompare =
|
||||
emitter.CompareTo(sign, delegate()
|
||||
{
|
||||
emitter.LoadLocal(b);
|
||||
emitter.Chain(prop);
|
||||
});
|
||||
|
||||
if (!couldCompare)
|
||||
throw new InvalidOperationException("Property is not comparable.");
|
||||
|
||||
emitter.StoreLocal(v);
|
||||
}
|
||||
|
||||
emitter.MarkLabel(end);
|
||||
|
||||
emitter.LoadLocal(v);
|
||||
emitter.Return();
|
||||
|
||||
typeBuilder.DefineMethodOverride(
|
||||
emitter.Method,
|
||||
typeof(IComparer).GetMethod(
|
||||
"Compare",
|
||||
new Type[]
|
||||
{
|
||||
typeof(object),
|
||||
typeof(object)
|
||||
}));
|
||||
|
||||
compareMethod = emitter.Method;
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
Type comparerType = typeBuilder.CreateType();
|
||||
|
||||
return (IComparer)Activator.CreateInstance(comparerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Scripts/Commands/Generic/Extensions/DistinctExtension.cs
Normal file
86
Scripts/Commands/Generic/Extensions/DistinctExtension.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class DistinctExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(30, "Distinct", -1, delegate() { return new DistinctExtension(); });
|
||||
private readonly List<Property> m_Properties;
|
||||
private IComparer m_Comparer;
|
||||
public DistinctExtension()
|
||||
{
|
||||
this.m_Properties = new List<Property>();
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new Exception("Distinct extension may only be used in combination with an object conditional.");
|
||||
|
||||
foreach (Property prop in this.m_Properties)
|
||||
{
|
||||
prop.BindTo(baseType, PropertyAccess.Read);
|
||||
prop.CheckAccess(from);
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
assembly = new AssemblyEmitter("__dynamic", false);
|
||||
|
||||
this.m_Comparer = DistinctCompiler.Compile(assembly, baseType, this.m_Properties.ToArray());
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid distinction syntax.");
|
||||
|
||||
int end = offset + size;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
string binding = arguments[offset++];
|
||||
|
||||
this.m_Properties.Add(new Property(binding));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (this.m_Comparer == null)
|
||||
throw new InvalidOperationException("The extension must first be optimized.");
|
||||
|
||||
ArrayList copy = new ArrayList(list);
|
||||
|
||||
copy.Sort(this.m_Comparer);
|
||||
|
||||
list.Clear();
|
||||
|
||||
object last = null;
|
||||
|
||||
for (int i = 0; i < copy.Count; ++i)
|
||||
{
|
||||
object obj = copy[i];
|
||||
|
||||
if (last == null || this.m_Comparer.Compare(obj, last) != 0)
|
||||
{
|
||||
list.Add(obj);
|
||||
last = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Scripts/Commands/Generic/Extensions/LimitExtension.cs
Normal file
47
Scripts/Commands/Generic/Extensions/LimitExtension.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class LimitExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(80, "Limit", 1, delegate() { return new LimitExtension(); });
|
||||
private int m_Limit;
|
||||
public LimitExtension()
|
||||
{
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public int Limit
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Limit;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
this.m_Limit = Utility.ToInt32(arguments[offset]);
|
||||
|
||||
if (this.m_Limit < 0)
|
||||
throw new Exception("Limit cannot be less than zero.");
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (list.Count > this.m_Limit)
|
||||
list.RemoveRange(this.m_Limit, list.Count - this.m_Limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
105
Scripts/Commands/Generic/Extensions/SortExtension.cs
Normal file
105
Scripts/Commands/Generic/Extensions/SortExtension.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class SortExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(40, "Order", -1, delegate() { return new SortExtension(); });
|
||||
private readonly List<OrderInfo> m_Orders;
|
||||
private IComparer m_Comparer;
|
||||
public SortExtension()
|
||||
{
|
||||
this.m_Orders = new List<OrderInfo>();
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new Exception("The ordering extension may only be used in combination with an object conditional.");
|
||||
|
||||
foreach (OrderInfo order in this.m_Orders)
|
||||
{
|
||||
order.Property.BindTo(baseType, PropertyAccess.Read);
|
||||
order.Property.CheckAccess(from);
|
||||
}
|
||||
|
||||
if (assembly == null)
|
||||
assembly = new AssemblyEmitter("__dynamic", false);
|
||||
|
||||
this.m_Comparer = SortCompiler.Compile(assembly, baseType, this.m_Orders.ToArray());
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid ordering syntax.");
|
||||
|
||||
if (Insensitive.Equals(arguments[offset], "by"))
|
||||
{
|
||||
++offset;
|
||||
--size;
|
||||
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid ordering syntax.");
|
||||
}
|
||||
|
||||
int end = offset + size;
|
||||
|
||||
while (offset < end)
|
||||
{
|
||||
string binding = arguments[offset++];
|
||||
|
||||
bool isAscending = true;
|
||||
|
||||
if (offset < end)
|
||||
{
|
||||
string next = arguments[offset];
|
||||
|
||||
switch ( next.ToLower() )
|
||||
{
|
||||
case "+":
|
||||
case "up":
|
||||
case "asc":
|
||||
case "ascending":
|
||||
isAscending = true;
|
||||
++offset;
|
||||
break;
|
||||
case "-":
|
||||
case "down":
|
||||
case "desc":
|
||||
case "descending":
|
||||
isAscending = false;
|
||||
++offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Property property = new Property(binding);
|
||||
|
||||
this.m_Orders.Add(new OrderInfo(property, isAscending));
|
||||
}
|
||||
}
|
||||
|
||||
public override void Filter(ArrayList list)
|
||||
{
|
||||
if (this.m_Comparer == null)
|
||||
throw new InvalidOperationException("The extension must first be optimized.");
|
||||
|
||||
list.Sort(this.m_Comparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Scripts/Commands/Generic/Extensions/WhereExtension.cs
Normal file
53
Scripts/Commands/Generic/Extensions/WhereExtension.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class WhereExtension : BaseExtension
|
||||
{
|
||||
public static ExtensionInfo ExtInfo = new ExtensionInfo(20, "Where", -1, delegate() { return new WhereExtension(); });
|
||||
private ObjectConditional m_Conditional;
|
||||
public WhereExtension()
|
||||
{
|
||||
}
|
||||
|
||||
public override ExtensionInfo Info
|
||||
{
|
||||
get
|
||||
{
|
||||
return ExtInfo;
|
||||
}
|
||||
}
|
||||
public ObjectConditional Conditional
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Conditional;
|
||||
}
|
||||
}
|
||||
public static void Initialize()
|
||||
{
|
||||
ExtensionInfo.Register(ExtInfo);
|
||||
}
|
||||
|
||||
public override void Optimize(Mobile from, Type baseType, ref AssemblyEmitter assembly)
|
||||
{
|
||||
if (baseType == null)
|
||||
throw new InvalidOperationException("Insanity.");
|
||||
|
||||
this.m_Conditional.Compile(ref assembly);
|
||||
}
|
||||
|
||||
public override void Parse(Mobile from, string[] arguments, int offset, int size)
|
||||
{
|
||||
if (size < 1)
|
||||
throw new Exception("Invalid condition syntax.");
|
||||
|
||||
this.m_Conditional = ObjectConditional.ParseDirect(from, arguments, offset, size);
|
||||
}
|
||||
|
||||
public override bool IsValid(object obj)
|
||||
{
|
||||
return this.m_Conditional.CheckCondition(obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class AreaCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
private static AreaCommandImplementor m_Instance;
|
||||
public AreaCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Area", "Group" };
|
||||
this.SupportRequirement = CommandSupport.Area;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Area <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate objects in a targeted area. Optional condition arguments can further restrict the set of objects.";
|
||||
|
||||
m_Instance = this;
|
||||
}
|
||||
|
||||
public static AreaCommandImplementor Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Instance;
|
||||
}
|
||||
}
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
BoundingBoxPicker.Begin(from, new BoundingBoxCallback(OnTarget), new object[] { command, args });
|
||||
}
|
||||
|
||||
public void OnTarget(Mobile from, Map map, Point3D start, Point3D end, object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
object[] states = (object[])state;
|
||||
BaseCommand command = (BaseCommand)states[0];
|
||||
string[] args = (string[])states[1];
|
||||
|
||||
Rectangle2D rect = new Rectangle2D(start.X, start.Y, end.X - start.X + 1, end.Y - start.Y + 1);
|
||||
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
IPooledEnumerable eable;
|
||||
|
||||
if (items && mobiles)
|
||||
eable = map.GetObjectsInBounds(rect);
|
||||
else if (items)
|
||||
eable = map.GetItemsInBounds(rect);
|
||||
else if (mobiles)
|
||||
eable = map.GetMobilesInBounds(rect);
|
||||
else
|
||||
return;
|
||||
|
||||
ArrayList objs = new ArrayList();
|
||||
|
||||
foreach (object obj in eable)
|
||||
{
|
||||
if (mobiles && obj is Mobile && !BaseCommand.IsAccessible(from, obj))
|
||||
continue;
|
||||
|
||||
if (ext.IsValid(obj))
|
||||
objs.Add(obj);
|
||||
}
|
||||
|
||||
eable.Free();
|
||||
|
||||
ext.Filter(objs);
|
||||
|
||||
this.RunCommand(from, objs, command, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
372
Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs
Normal file
372
Scripts/Commands/Generic/Implementors/BaseCommandImplementor.cs
Normal file
@@ -0,0 +1,372 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
[Flags]
|
||||
public enum CommandSupport
|
||||
{
|
||||
Single = 0x0001,
|
||||
Global = 0x0002,
|
||||
Online = 0x0004,
|
||||
Multi = 0x0008,
|
||||
Area = 0x0010,
|
||||
Self = 0x0020,
|
||||
Region = 0x0040,
|
||||
Contained = 0x0080,
|
||||
IPAddress = 0x0100,
|
||||
|
||||
All = Single | Global | Online | Multi | Area | Self | Region | Contained | IPAddress,
|
||||
AllMobiles = All & ~Contained,
|
||||
AllNPCs = All & ~(IPAddress | Online | Self | Contained),
|
||||
AllItems = All & ~(IPAddress | Online | Self | Region),
|
||||
|
||||
Simple = Single | Multi,
|
||||
Complex = Global | Online | Area | Region | Contained | IPAddress
|
||||
}
|
||||
|
||||
public abstract class BaseCommandImplementor
|
||||
{
|
||||
private static List<BaseCommandImplementor> m_Implementors;
|
||||
private readonly Dictionary<string, BaseCommand> m_Commands;
|
||||
private string[] m_Accessors;
|
||||
private AccessLevel m_AccessLevel;
|
||||
private CommandSupport m_SupportRequirement;
|
||||
private string m_Usage;
|
||||
private string m_Description;
|
||||
private bool m_SupportsConditionals;
|
||||
public BaseCommandImplementor()
|
||||
{
|
||||
this.m_Commands = new Dictionary<string, BaseCommand>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static List<BaseCommandImplementor> Implementors
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Implementors == null)
|
||||
{
|
||||
m_Implementors = new List<BaseCommandImplementor>();
|
||||
RegisterImplementors();
|
||||
}
|
||||
|
||||
return m_Implementors;
|
||||
}
|
||||
}
|
||||
public bool SupportsConditionals
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SupportsConditionals;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_SupportsConditionals = value;
|
||||
}
|
||||
}
|
||||
public string[] Accessors
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Accessors;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Accessors = value;
|
||||
}
|
||||
}
|
||||
public string Usage
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Usage;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Usage = value;
|
||||
}
|
||||
}
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Description;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_Description = value;
|
||||
}
|
||||
}
|
||||
public AccessLevel AccessLevel
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_AccessLevel;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_AccessLevel = value;
|
||||
}
|
||||
}
|
||||
public CommandSupport SupportRequirement
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_SupportRequirement;
|
||||
}
|
||||
set
|
||||
{
|
||||
this.m_SupportRequirement = value;
|
||||
}
|
||||
}
|
||||
public Dictionary<string, BaseCommand> Commands
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_Commands;
|
||||
}
|
||||
}
|
||||
public static void RegisterImplementors()
|
||||
{
|
||||
Register(new RegionCommandImplementor());
|
||||
Register(new GlobalCommandImplementor());
|
||||
Register(new OnlineCommandImplementor());
|
||||
Register(new SingleCommandImplementor());
|
||||
Register(new SerialCommandImplementor());
|
||||
Register(new MultiCommandImplementor());
|
||||
Register(new AreaCommandImplementor());
|
||||
Register(new SelfCommandImplementor());
|
||||
Register(new ContainedCommandImplementor());
|
||||
Register(new IPAddressCommandImplementor());
|
||||
|
||||
Register(new RangeCommandImplementor());
|
||||
Register(new ScreenCommandImplementor());
|
||||
Register(new FacetCommandImplementor());
|
||||
}
|
||||
|
||||
public static void Register(BaseCommandImplementor impl)
|
||||
{
|
||||
m_Implementors.Add(impl);
|
||||
impl.Register();
|
||||
}
|
||||
|
||||
public virtual void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
obj = null;
|
||||
}
|
||||
|
||||
public virtual void Register(BaseCommand command)
|
||||
{
|
||||
for (int i = 0; i < command.Commands.Length; ++i)
|
||||
this.m_Commands[command.Commands[i]] = command;
|
||||
}
|
||||
|
||||
public bool CheckObjectTypes(Mobile from, BaseCommand command, Extensions ext, out bool items, out bool mobiles)
|
||||
{
|
||||
items = mobiles = false;
|
||||
|
||||
ObjectConditional cond = ObjectConditional.Empty;
|
||||
|
||||
foreach (BaseExtension check in ext)
|
||||
{
|
||||
if (check is WhereExtension)
|
||||
{
|
||||
cond = (check as WhereExtension).Conditional;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool condIsItem = cond.IsItem;
|
||||
bool condIsMobile = cond.IsMobile;
|
||||
|
||||
switch ( command.ObjectTypes )
|
||||
{
|
||||
case ObjectTypes.All:
|
||||
case ObjectTypes.Both:
|
||||
{
|
||||
if (condIsItem)
|
||||
items = true;
|
||||
|
||||
if (condIsMobile)
|
||||
mobiles = true;
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Items:
|
||||
{
|
||||
if (condIsItem)
|
||||
{
|
||||
items = true;
|
||||
}
|
||||
else if (condIsMobile)
|
||||
{
|
||||
from.SendMessage("You may not use a mobile type condition for this command.");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Mobiles:
|
||||
{
|
||||
if (condIsMobile)
|
||||
{
|
||||
mobiles = true;
|
||||
}
|
||||
else if (condIsItem)
|
||||
{
|
||||
from.SendMessage("You may not use an item type condition for this command.");
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RunCommand(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
object obj = null;
|
||||
|
||||
this.Compile(from, command, ref args, ref obj);
|
||||
|
||||
this.RunCommand(from, obj, command, args);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public string GenerateArgString(string[] args)
|
||||
{
|
||||
if (args.Length == 0)
|
||||
return "";
|
||||
|
||||
// NOTE: this does not preserve the case where quotation marks are used on a single word
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
sb.Append(' ');
|
||||
|
||||
if (args[i].IndexOf(' ') >= 0)
|
||||
{
|
||||
sb.Append('"');
|
||||
sb.Append(args[i]);
|
||||
sb.Append('"');
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void RunCommand(Mobile from, object obj, BaseCommand command, string[] args)
|
||||
{
|
||||
// try
|
||||
// {
|
||||
CommandEventArgs e = new CommandEventArgs(from, command.Commands[0], this.GenerateArgString(args), args);
|
||||
|
||||
if (!command.ValidateArgs(this, e))
|
||||
return;
|
||||
|
||||
bool flushToLog = false;
|
||||
|
||||
if (obj is ArrayList)
|
||||
{
|
||||
ArrayList list = (ArrayList)obj;
|
||||
|
||||
if (list.Count > 20)
|
||||
CommandLogging.Enabled = false;
|
||||
else if (list.Count == 0)
|
||||
command.LogFailure("Nothing was found to use this command on.");
|
||||
|
||||
command.ExecuteList(e, list);
|
||||
|
||||
if (list.Count > 20)
|
||||
{
|
||||
flushToLog = true;
|
||||
CommandLogging.Enabled = true;
|
||||
}
|
||||
}
|
||||
else if (obj != null)
|
||||
{
|
||||
if (command.ListOptimized)
|
||||
{
|
||||
ArrayList list = new ArrayList();
|
||||
list.Add(obj);
|
||||
command.ExecuteList(e, list);
|
||||
}
|
||||
else
|
||||
{
|
||||
command.Execute(e, obj);
|
||||
}
|
||||
}
|
||||
|
||||
command.Flush(from, flushToLog);
|
||||
// }
|
||||
// catch ( Exception ex )
|
||||
// {
|
||||
// from.SendMessage( ex.Message );
|
||||
// }
|
||||
}
|
||||
|
||||
public virtual void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
this.RunCommand(from, command, args);
|
||||
}
|
||||
|
||||
public virtual void Execute(CommandEventArgs e)
|
||||
{
|
||||
if (e.Length >= 1)
|
||||
{
|
||||
BaseCommand command = null;
|
||||
this.m_Commands.TryGetValue(e.GetString(0), out command);
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier.");
|
||||
}
|
||||
else if (e.Mobile.AccessLevel < command.AccessLevel)
|
||||
{
|
||||
e.Mobile.SendMessage("You do not have access to that command.");
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] oldArgs = e.Arguments;
|
||||
string[] args = new string[oldArgs.Length - 1];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
args[i] = oldArgs[i + 1];
|
||||
|
||||
this.Process(e.Mobile, command, args);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("You must supply a command name.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Register()
|
||||
{
|
||||
if (this.m_Accessors == null)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < this.m_Accessors.Length; ++i)
|
||||
CommandSystem.Register(this.m_Accessors[i], this.m_AccessLevel, new CommandEventHandler(Execute));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Items;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class ContainedCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public ContainedCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Contained" };
|
||||
this.SupportRequirement = CommandSupport.Contained;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Contained <command> [condition]";
|
||||
this.Description = "Invokes the command on all child items in a targeted container. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
if (command.ValidateArgs(this, new CommandEventArgs(from, command.Commands[0], this.GenerateArgString(args), args)))
|
||||
from.BeginTarget(-1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback(OnTarget), new object[] { command, args });
|
||||
}
|
||||
|
||||
public void OnTarget(Mobile from, object targeted, object state)
|
||||
{
|
||||
if (!BaseCommand.IsAccessible(from, targeted))
|
||||
{
|
||||
from.SendMessage("That is not accessible.");
|
||||
return;
|
||||
}
|
||||
|
||||
object[] states = (object[])state;
|
||||
BaseCommand command = (BaseCommand)states[0];
|
||||
string[] args = (string[])states[1];
|
||||
|
||||
if (command.ObjectTypes == ObjectTypes.Mobiles)
|
||||
return; // sanity check
|
||||
|
||||
if (!(targeted is Container))
|
||||
{
|
||||
from.SendMessage("That is not a container.");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
if (!items)
|
||||
{
|
||||
from.SendMessage("This command only works on items.");
|
||||
return;
|
||||
}
|
||||
|
||||
Container cont = (Container)targeted;
|
||||
|
||||
Item[] found = cont.FindItemsByType(typeof(Item), true);
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
for (int i = 0; i < found.Length; ++i)
|
||||
{
|
||||
if (ext.IsValid(found[i]))
|
||||
list.Add(found[i]);
|
||||
}
|
||||
|
||||
ext.Filter(list);
|
||||
|
||||
this.RunCommand(from, list, command, args);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
from.SendMessage(e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class FacetCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public FacetCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Facet" };
|
||||
this.SupportRequirement = CommandSupport.Area;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Facet <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate objects within your facet's map bounds. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
AreaCommandImplementor impl = AreaCommandImplementor.Instance;
|
||||
|
||||
if (impl == null)
|
||||
return;
|
||||
|
||||
Map map = from.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
return;
|
||||
|
||||
impl.OnTarget(from, map, Point3D.Zero, new Point3D(map.Width - 1, map.Height - 1, 0), new object[] { command, args });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class GlobalCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public GlobalCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Global" };
|
||||
this.SupportRequirement = CommandSupport.Global;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.Administrator;
|
||||
this.Usage = "Global <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate objects in the world. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
if (items)
|
||||
{
|
||||
foreach (Item item in World.Items.Values)
|
||||
{
|
||||
if (ext.IsValid(item))
|
||||
list.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (mobiles)
|
||||
{
|
||||
foreach (Mobile mob in World.Mobiles.Values)
|
||||
{
|
||||
if (ext.IsValid(mob))
|
||||
list.Add(mob);
|
||||
}
|
||||
}
|
||||
|
||||
ext.Filter(list);
|
||||
|
||||
obj = list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class IPAddressCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public IPAddressCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "IPAddress" };
|
||||
this.SupportRequirement = CommandSupport.IPAddress;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.Administrator;
|
||||
this.Usage = "IPAddress <command> [condition]";
|
||||
this.Description = "Invokes the command on one mobile from each IP address that is logged in. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
if (!mobiles) // sanity check
|
||||
{
|
||||
command.LogFailure("This command does not support items.");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
ArrayList addresses = new ArrayList();
|
||||
|
||||
System.Collections.Generic.List<NetState> states = NetState.Instances;
|
||||
|
||||
for (int i = 0; i < states.Count; ++i)
|
||||
{
|
||||
NetState ns = (NetState)states[i];
|
||||
Mobile mob = ns.Mobile;
|
||||
|
||||
if (mob != null && !addresses.Contains(ns.Address) && ext.IsValid(mob))
|
||||
{
|
||||
list.Add(mob);
|
||||
addresses.Add(ns.Address);
|
||||
}
|
||||
}
|
||||
|
||||
ext.Filter(list);
|
||||
|
||||
obj = list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class MultiCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public MultiCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Multi", "m" };
|
||||
this.SupportRequirement = CommandSupport.Multi;
|
||||
this.AccessLevel = AccessLevel.Counselor;
|
||||
this.Usage = "Multi <command>";
|
||||
this.Description = "Invokes the command on multiple targeted objects.";
|
||||
}
|
||||
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
if (command.ValidateArgs(this, new CommandEventArgs(from, command.Commands[0], this.GenerateArgString(args), args)))
|
||||
from.BeginTarget(-1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback(OnTarget), new object[] { command, args });
|
||||
}
|
||||
|
||||
public void OnTarget(Mobile from, object targeted, object state)
|
||||
{
|
||||
object[] states = (object[])state;
|
||||
BaseCommand command = (BaseCommand)states[0];
|
||||
string[] args = (string[])states[1];
|
||||
|
||||
if (!BaseCommand.IsAccessible(from, targeted))
|
||||
{
|
||||
from.SendMessage("That is not accessible.");
|
||||
from.BeginTarget(-1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback(OnTarget), new object[] { command, args });
|
||||
return;
|
||||
}
|
||||
|
||||
switch ( command.ObjectTypes )
|
||||
{
|
||||
case ObjectTypes.Both:
|
||||
{
|
||||
if (!(targeted is Item) && !(targeted is Mobile))
|
||||
{
|
||||
from.SendMessage("This command does not work on that.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Items:
|
||||
{
|
||||
if (!(targeted is Item))
|
||||
{
|
||||
from.SendMessage("This command only works on items.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Mobiles:
|
||||
{
|
||||
if (!(targeted is Mobile))
|
||||
{
|
||||
from.SendMessage("This command only works on mobiles.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.RunCommand(from, targeted, command, args);
|
||||
|
||||
from.BeginTarget(-1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback(OnTarget), new object[] { command, args });
|
||||
}
|
||||
}
|
||||
}
|
||||
262
Scripts/Commands/Generic/Implementors/ObjectConditional.cs
Normal file
262
Scripts/Commands/Generic/Implementors/ObjectConditional.cs
Normal file
@@ -0,0 +1,262 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public sealed class ObjectConditional
|
||||
{
|
||||
private static readonly Type typeofItem = typeof(Item);
|
||||
private static readonly Type typeofMobile = typeof(Mobile);
|
||||
|
||||
private readonly Type m_ObjectType;
|
||||
|
||||
private readonly ICondition[][] m_Conditions;
|
||||
|
||||
private IConditional[] m_Conditionals;
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.m_ObjectType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsItem
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_ObjectType == null || this.m_ObjectType == typeofItem || this.m_ObjectType.IsSubclassOf(typeofItem));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsMobile
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_ObjectType == null || this.m_ObjectType == typeofMobile || this.m_ObjectType.IsSubclassOf(typeofMobile));
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly ObjectConditional Empty = new ObjectConditional(null, null);
|
||||
|
||||
public bool HasCompiled
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.m_Conditionals != null);
|
||||
}
|
||||
}
|
||||
|
||||
public void Compile(ref AssemblyEmitter emitter)
|
||||
{
|
||||
if (emitter == null)
|
||||
emitter = new AssemblyEmitter("__dynamic", false);
|
||||
|
||||
this.m_Conditionals = new IConditional[this.m_Conditions.Length];
|
||||
|
||||
for (int i = 0; i < this.m_Conditionals.Length; ++i)
|
||||
this.m_Conditionals[i] = ConditionalCompiler.Compile(emitter, this.m_ObjectType, this.m_Conditions[i], i);
|
||||
}
|
||||
|
||||
public bool CheckCondition(object obj)
|
||||
{
|
||||
if (this.m_ObjectType == null)
|
||||
return true; // null type means no condition
|
||||
|
||||
if (!this.HasCompiled)
|
||||
{
|
||||
AssemblyEmitter emitter = null;
|
||||
|
||||
this.Compile(ref emitter);
|
||||
}
|
||||
|
||||
for (int i = 0; i < this.m_Conditionals.Length; ++i)
|
||||
{
|
||||
if (this.m_Conditionals[i].Verify(obj))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // all conditions false
|
||||
}
|
||||
|
||||
public static ObjectConditional Parse(Mobile from, ref string[] args)
|
||||
{
|
||||
string[] conditionArgs = null;
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
{
|
||||
if (Insensitive.Equals(args[i], "where"))
|
||||
{
|
||||
string[] origArgs = args;
|
||||
|
||||
args = new string[i];
|
||||
|
||||
for (int j = 0; j < args.Length; ++j)
|
||||
args[j] = origArgs[j];
|
||||
|
||||
conditionArgs = new string[origArgs.Length - i - 1];
|
||||
|
||||
for (int j = 0; j < conditionArgs.Length; ++j)
|
||||
conditionArgs[j] = origArgs[i + j + 1];
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ParseDirect(from, conditionArgs, 0, conditionArgs.Length);
|
||||
}
|
||||
|
||||
public static ObjectConditional ParseDirect(Mobile from, string[] args, int offset, int size)
|
||||
{
|
||||
if (args == null || size == 0)
|
||||
return ObjectConditional.Empty;
|
||||
|
||||
int index = 0;
|
||||
|
||||
Type objectType = ScriptCompiler.FindTypeByName(args[offset + index], true);
|
||||
|
||||
if (objectType == null)
|
||||
throw new Exception(String.Format("No type with that name ({0}) was found.", args[offset + index]));
|
||||
|
||||
++index;
|
||||
|
||||
List<ICondition[]> conditions = new List<ICondition[]>();
|
||||
List<ICondition> current = new List<ICondition>();
|
||||
|
||||
current.Add(TypeCondition.Default);
|
||||
|
||||
while (index < size)
|
||||
{
|
||||
string cur = args[offset + index];
|
||||
|
||||
bool inverse = false;
|
||||
|
||||
if (Insensitive.Equals(cur, "not") || cur == "!")
|
||||
{
|
||||
inverse = true;
|
||||
++index;
|
||||
|
||||
if (index >= size)
|
||||
throw new Exception("Improperly formatted object conditional.");
|
||||
}
|
||||
else if (Insensitive.Equals(cur, "or") || cur == "||")
|
||||
{
|
||||
if (current.Count > 1)
|
||||
{
|
||||
conditions.Add(current.ToArray());
|
||||
|
||||
current.Clear();
|
||||
current.Add(TypeCondition.Default);
|
||||
}
|
||||
|
||||
++index;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
string binding = args[offset + index];
|
||||
index++;
|
||||
|
||||
if (index >= size)
|
||||
throw new Exception("Improperly formatted object conditional.");
|
||||
|
||||
string oper = args[offset + index];
|
||||
index++;
|
||||
|
||||
if (index >= size)
|
||||
throw new Exception("Improperly formatted object conditional.");
|
||||
|
||||
string val = args[offset + index];
|
||||
index++;
|
||||
|
||||
Property prop = new Property(binding);
|
||||
|
||||
prop.BindTo(objectType, PropertyAccess.Read);
|
||||
prop.CheckAccess(from);
|
||||
|
||||
ICondition condition = null;
|
||||
|
||||
switch ( oper )
|
||||
{
|
||||
#region Equality
|
||||
case "=":
|
||||
case "==":
|
||||
case "is":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Equal, val);
|
||||
break;
|
||||
case "!=":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.NotEqual, val);
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Relational
|
||||
case ">":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Greater, val);
|
||||
break;
|
||||
case "<":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.Lesser, val);
|
||||
break;
|
||||
case ">=":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.GreaterEqual, val);
|
||||
break;
|
||||
case "<=":
|
||||
condition = new ComparisonCondition(prop, inverse, ComparisonOperator.LesserEqual, val);
|
||||
break;
|
||||
#endregion
|
||||
|
||||
#region Strings
|
||||
case "==~":
|
||||
case "~==":
|
||||
case "=~":
|
||||
case "~=":
|
||||
case "is~":
|
||||
case "~is":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.Equal, val, true);
|
||||
break;
|
||||
case "!=~":
|
||||
case "~!=":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.NotEqual, val, true);
|
||||
break;
|
||||
case "starts":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.StartsWith, val, false);
|
||||
break;
|
||||
case "starts~":
|
||||
case "~starts":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.StartsWith, val, true);
|
||||
break;
|
||||
case "ends":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.EndsWith, val, false);
|
||||
break;
|
||||
case "ends~":
|
||||
case "~ends":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.EndsWith, val, true);
|
||||
break;
|
||||
case "contains":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.Contains, val, false);
|
||||
break;
|
||||
case "contains~":
|
||||
case "~contains":
|
||||
condition = new StringCondition(prop, inverse, StringOperator.Contains, val, true);
|
||||
break;
|
||||
#endregion
|
||||
}
|
||||
|
||||
if (condition == null)
|
||||
throw new InvalidOperationException(String.Format("Unrecognized operator (\"{0}\").", oper));
|
||||
|
||||
current.Add(condition);
|
||||
}
|
||||
|
||||
conditions.Add(current.ToArray());
|
||||
|
||||
return new ObjectConditional(objectType, conditions.ToArray());
|
||||
}
|
||||
|
||||
public ObjectConditional(Type objectType, ICondition[][] conditions)
|
||||
{
|
||||
this.m_ObjectType = objectType;
|
||||
this.m_Conditions = conditions;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class OnlineCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public OnlineCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Online" };
|
||||
this.SupportRequirement = CommandSupport.Online;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Online <command> [condition]";
|
||||
this.Description = "Invokes the command on all mobiles that are currently logged in. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
if (!mobiles) // sanity check
|
||||
{
|
||||
command.LogFailure("This command does not support items.");
|
||||
return;
|
||||
}
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
List<NetState> states = NetState.Instances;
|
||||
|
||||
for (int i = 0; i < states.Count; ++i)
|
||||
{
|
||||
NetState ns = states[i];
|
||||
Mobile mob = ns.Mobile;
|
||||
|
||||
if (mob == null)
|
||||
continue;
|
||||
|
||||
if (!BaseCommand.IsAccessible(from, mob))
|
||||
continue;
|
||||
|
||||
if (ext.IsValid(mob))
|
||||
list.Add(mob);
|
||||
}
|
||||
|
||||
ext.Filter(list);
|
||||
|
||||
obj = list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class RangeCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
private static RangeCommandImplementor m_Instance;
|
||||
public RangeCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Range" };
|
||||
this.SupportRequirement = CommandSupport.Area;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Range <range> <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate objects within a specified range of you. Optional condition arguments can further restrict the set of objects.";
|
||||
|
||||
m_Instance = this;
|
||||
}
|
||||
|
||||
public static RangeCommandImplementor Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Instance;
|
||||
}
|
||||
}
|
||||
public override void Execute(CommandEventArgs e)
|
||||
{
|
||||
if (e.Length >= 2)
|
||||
{
|
||||
int range = e.GetInt32(0);
|
||||
|
||||
if (range < 0)
|
||||
{
|
||||
e.Mobile.SendMessage("The range must not be negative.");
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseCommand command = null;
|
||||
this.Commands.TryGetValue(e.GetString(1), out command);
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier.");
|
||||
}
|
||||
else if (e.Mobile.AccessLevel < command.AccessLevel)
|
||||
{
|
||||
e.Mobile.SendMessage("You do not have access to that command.");
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] oldArgs = e.Arguments;
|
||||
string[] args = new string[oldArgs.Length - 2];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
args[i] = oldArgs[i + 2];
|
||||
|
||||
this.Process(range, e.Mobile, command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("You must supply a range and a command name.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Process(int range, Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
AreaCommandImplementor impl = AreaCommandImplementor.Instance;
|
||||
|
||||
if (impl == null)
|
||||
return;
|
||||
|
||||
Map map = from.Map;
|
||||
|
||||
if (map == null || map == Map.Internal)
|
||||
return;
|
||||
|
||||
Point3D start = new Point3D(from.X - range, from.Y - range, from.Z);
|
||||
Point3D end = new Point3D(from.X + range, from.Y + range, from.Z);
|
||||
|
||||
impl.OnTarget(from, map, start, end, new object[] { command, args });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class RegionCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public RegionCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Region" };
|
||||
this.SupportRequirement = CommandSupport.Region;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Region <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate mobiles in your current region. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
try
|
||||
{
|
||||
Extensions ext = Extensions.Parse(from, ref args);
|
||||
|
||||
bool items, mobiles;
|
||||
|
||||
if (!this.CheckObjectTypes(from, command, ext, out items, out mobiles))
|
||||
return;
|
||||
|
||||
Region reg = from.Region;
|
||||
|
||||
ArrayList list = new ArrayList();
|
||||
|
||||
if (mobiles)
|
||||
{
|
||||
foreach (Mobile mob in reg.GetMobiles())
|
||||
{
|
||||
if (!BaseCommand.IsAccessible(from, mob))
|
||||
continue;
|
||||
|
||||
if (ext.IsValid(mob))
|
||||
list.Add(mob);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
command.LogFailure("This command does not support items.");
|
||||
return;
|
||||
}
|
||||
|
||||
ext.Filter(list);
|
||||
|
||||
obj = list;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
from.SendMessage(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class ScreenCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public ScreenCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Screen" };
|
||||
this.SupportRequirement = CommandSupport.Area;
|
||||
this.SupportsConditionals = true;
|
||||
this.AccessLevel = AccessLevel.GameMaster;
|
||||
this.Usage = "Screen <command> [condition]";
|
||||
this.Description = "Invokes the command on all appropriate objects in your screen. Optional condition arguments can further restrict the set of objects.";
|
||||
}
|
||||
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
RangeCommandImplementor impl = RangeCommandImplementor.Instance;
|
||||
|
||||
if (impl == null)
|
||||
return;
|
||||
|
||||
impl.Process(18, from, command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class SelfCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public SelfCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Self" };
|
||||
this.SupportRequirement = CommandSupport.Self;
|
||||
this.AccessLevel = AccessLevel.Counselor;
|
||||
this.Usage = "Self <command>";
|
||||
this.Description = "Invokes the command on the commanding player.";
|
||||
}
|
||||
|
||||
public override void Compile(Mobile from, BaseCommand command, ref string[] args, ref object obj)
|
||||
{
|
||||
if (command.ObjectTypes == ObjectTypes.Items)
|
||||
return; // sanity check
|
||||
|
||||
obj = from;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class SerialCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public SerialCommandImplementor()
|
||||
{
|
||||
this.Accessors = new string[] { "Serial" };
|
||||
this.SupportRequirement = CommandSupport.Single;
|
||||
this.AccessLevel = AccessLevel.Counselor;
|
||||
this.Usage = "Serial <serial> <command>";
|
||||
this.Description = "Invokes the command on a single object by serial.";
|
||||
}
|
||||
|
||||
public override void Execute(CommandEventArgs e)
|
||||
{
|
||||
if (e.Length >= 2)
|
||||
{
|
||||
Serial serial = e.GetInt32(0);
|
||||
|
||||
object obj = null;
|
||||
|
||||
if (serial.IsItem)
|
||||
obj = World.FindItem(serial);
|
||||
else if (serial.IsMobile)
|
||||
obj = World.FindMobile(serial);
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
e.Mobile.SendMessage("That is not a valid serial.");
|
||||
}
|
||||
else
|
||||
{
|
||||
BaseCommand command = null;
|
||||
this.Commands.TryGetValue(e.GetString(1), out command);
|
||||
|
||||
if (command == null)
|
||||
{
|
||||
e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier.");
|
||||
}
|
||||
else if (e.Mobile.AccessLevel < command.AccessLevel)
|
||||
{
|
||||
e.Mobile.SendMessage("You do not have access to that command.");
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ( command.ObjectTypes )
|
||||
{
|
||||
case ObjectTypes.Both:
|
||||
{
|
||||
if (!(obj is Item) && !(obj is Mobile))
|
||||
{
|
||||
e.Mobile.SendMessage("This command does not work on that.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Items:
|
||||
{
|
||||
if (!(obj is Item))
|
||||
{
|
||||
e.Mobile.SendMessage("This command only works on items.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Mobiles:
|
||||
{
|
||||
if (!(obj is Mobile))
|
||||
{
|
||||
e.Mobile.SendMessage("This command only works on mobiles.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string[] oldArgs = e.Arguments;
|
||||
string[] args = new string[oldArgs.Length - 2];
|
||||
|
||||
for (int i = 0; i < args.Length; ++i)
|
||||
args[i] = oldArgs[i + 2];
|
||||
|
||||
this.RunCommand(e.Mobile, obj, command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("You must supply an object serial and a command name.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using Server.Targeting;
|
||||
|
||||
namespace Server.Commands.Generic
|
||||
{
|
||||
public class SingleCommandImplementor : BaseCommandImplementor
|
||||
{
|
||||
public SingleCommandImplementor()
|
||||
{
|
||||
Accessors = new string[] { "Single" };
|
||||
SupportRequirement = CommandSupport.Single;
|
||||
AccessLevel = AccessLevel.Counselor;
|
||||
Usage = "Single <command>";
|
||||
Description = "Invokes the command on a single targeted object. This is the same as just invoking the command directly.";
|
||||
}
|
||||
|
||||
public override void Register(BaseCommand command)
|
||||
{
|
||||
base.Register(command);
|
||||
|
||||
for (int i = 0; i < command.Commands.Length; ++i)
|
||||
CommandSystem.Register(command.Commands[i], command.AccessLevel, new CommandEventHandler(Redirect));
|
||||
}
|
||||
|
||||
public void Redirect(CommandEventArgs e)
|
||||
{
|
||||
BaseCommand command = null;
|
||||
|
||||
this.Commands.TryGetValue(e.Command, out command);
|
||||
|
||||
if (command == null)
|
||||
e.Mobile.SendMessage("That is either an invalid command name or one that does not support this modifier.");
|
||||
else if (e.Mobile.AccessLevel < command.AccessLevel)
|
||||
e.Mobile.SendMessage("You do not have access to that command.");
|
||||
else if (command.ValidateArgs(this, e))
|
||||
this.Process(e.Mobile, command, e.Arguments);
|
||||
}
|
||||
|
||||
public override void Process(Mobile from, BaseCommand command, string[] args)
|
||||
{
|
||||
if (command.ValidateArgs(this, new CommandEventArgs(from, command.Commands[0], this.GenerateArgString(args), args)))
|
||||
from.BeginTarget(-1, command.ObjectTypes == ObjectTypes.All, TargetFlags.None, new TargetStateCallback(OnTarget), new object[] { command, args });
|
||||
}
|
||||
|
||||
public void OnTarget(Mobile from, object targeted, object state)
|
||||
{
|
||||
if (!BaseCommand.IsAccessible(from, targeted))
|
||||
{
|
||||
from.SendLocalizedMessage(500447); // That is not accessible.
|
||||
return;
|
||||
}
|
||||
|
||||
object[] states = (object[])state;
|
||||
BaseCommand command = (BaseCommand)states[0];
|
||||
string[] args = (string[])states[1];
|
||||
|
||||
switch ( command.ObjectTypes )
|
||||
{
|
||||
case ObjectTypes.Both:
|
||||
{
|
||||
if (!(targeted is Item) && !(targeted is Mobile))
|
||||
{
|
||||
from.SendMessage("This command does not work on that.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Items:
|
||||
{
|
||||
if (!(targeted is Item))
|
||||
{
|
||||
from.SendMessage("This command only works on items.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ObjectTypes.Mobiles:
|
||||
{
|
||||
if (!(targeted is Mobile))
|
||||
{
|
||||
from.SendMessage("This command only works on mobiles.");
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.RunCommand(from, targeted, command, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user