Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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++;
}
}
}
}

View 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);
}
}
}

View 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
View 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;
}
}
}
}

View 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.
}
}
}
}
}

View 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;
}
}
}

View 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);
}
}
}

View 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
View 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);
}
}
}

View 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;
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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);
}
}
}
}
}

View 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;
}
*/

View 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();
}
}
}
}

View 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
View 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);
}
}
}
}

View 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;
}
}
}
}

View 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);
}
}
}
}
}

View 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);
}
}
}
}
}
}

View 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!
}
}
}
}

View 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);
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}
}

View 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
}
}
}

View 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);
}
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}
}

View 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();
}
}
}
}

View 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);
}
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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;
}
}
}

View 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
}
}

View 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);
}
}
}
}
}

View 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);
}
}
}
}

View 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;
}
}
}
}

View 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;
}
}
}

View 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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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();
}
}
}

View 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;
}
}
}

View 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();
}
}
}

View 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();
}
}
}
}

View 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;
* */
}
}
}

View 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;
}
}
}

View 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
View 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;
}
}
}
}

View 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
View 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));
}
}
}

View 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);
}
}
}
}
}

View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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
View 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
{ }
}
}
}
}

View 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
View 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();
}
}
}
}

View 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();
}
}
}
}

View 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));
}
}
}

View 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);
}
}
}
}

View 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();
}
}
}
}

View 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;
}
}
}
}

File diff suppressed because it is too large Load Diff

View 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;
}
}
}

View 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));
}
}
}

View 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)
{
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}
}

View 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);
}
}
}

View 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;
}
}
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View 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);
}
}
}

View File

@@ -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);
}
}
}
}

View 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));
}
}
}

View File

@@ -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);
}
}
}
}
}

View File

@@ -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 });
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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 });
}
}
}

View 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;
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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 });
}
}
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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.");
}
}
}
}

View File

@@ -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