Reorganizes Project (#41)

This commit is contained in:
Kamron Batman 2019-08-02 18:13:40 -07:00 • committed by GitHub
parent 08bf44af9a
commit 3614a66aee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3499 changed files with 79 additions and 55 deletions

View file

@ -0,0 +1,107 @@
using Server.Mobiles;
namespace Server.Factions
{
public class FactionWarHorse : BaseMount
{
public const int SilverPrice = 500;
public const int GoldPrice = 3000;
private Faction m_Faction;
public FactionWarHorse(Faction faction = null)
: base("a war horse", 0xE2, 0x3EA0, AIType.AI_Melee, FightMode.Aggressor, 10, 1, 0.2, 0.4)
{
BaseSoundID = 0xA8;
SetStr(400);
SetDex(125);
SetInt(51, 55);
SetHits(240);
SetMana(0);
SetDamage(5, 8);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 40, 50);
SetResistance(ResistanceType.Fire, 30, 40);
SetResistance(ResistanceType.Cold, 30, 40);
SetResistance(ResistanceType.Poison, 30, 40);
SetResistance(ResistanceType.Energy, 30, 40);
SetSkill(SkillName.MagicResist, 25.1, 30.0);
SetSkill(SkillName.Tactics, 29.3, 44.0);
SetSkill(SkillName.Wrestling, 29.3, 44.0);
Fame = 300;
Karma = 300;
Tamable = true;
ControlSlots = 1;
Faction = faction;
}
public FactionWarHorse(Serial serial) : base(serial)
{
}
public override string CorpseName => "a war horse corpse";
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public Faction Faction
{
get => m_Faction;
set
{
m_Faction = value;
Body = m_Faction?.Definition.WarHorseBody ?? 0xE2;
ItemID = m_Faction?.Definition.WarHorseItem ?? 0x3EA0;
}
}
public override FoodType FavoriteFood => FoodType.FruitsAndVegies | FoodType.GrainsAndHay;
public override void OnDoubleClick(Mobile from)
{
PlayerState pl = PlayerState.Find(from);
if (pl == null)
from.SendLocalizedMessage(1010366); // You cannot mount a faction war horse!
else if (pl.Faction != Faction)
from.SendLocalizedMessage(1010367); // You cannot ride an opposing faction's war horse!
else if (pl.Rank.Rank < 2)
from.SendLocalizedMessage(
1010368); // You must achieve a faction rank of at least two before riding a war horse!
else
base.OnDoubleClick(from);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
Faction.WriteReference(writer, m_Faction);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
Faction = Faction.ReadReference(reader);
break;
}
}
}
}
}

View file

@ -0,0 +1,528 @@
using System;
using System.Collections.Generic;
using Server.Factions.AI;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Factions
{
public abstract class BaseFactionGuard : BaseCreature
{
private const int ListenRange = 12;
private static Type[] m_StrongPotions =
{
typeof(GreaterHealPotion), typeof(GreaterHealPotion), typeof(GreaterHealPotion),
typeof(GreaterCurePotion), typeof(GreaterCurePotion), typeof(GreaterCurePotion),
typeof(GreaterStrengthPotion), typeof(GreaterStrengthPotion),
typeof(GreaterAgilityPotion), typeof(GreaterAgilityPotion),
typeof(TotalRefreshPotion), typeof(TotalRefreshPotion),
typeof(GreaterExplosionPotion)
};
private static Type[] m_WeakPotions =
{
typeof(HealPotion), typeof(HealPotion), typeof(HealPotion),
typeof(CurePotion), typeof(CurePotion), typeof(CurePotion),
typeof(StrengthPotion), typeof(StrengthPotion),
typeof(AgilityPotion), typeof(AgilityPotion),
typeof(RefreshPotion), typeof(RefreshPotion),
typeof(ExplosionPotion)
};
private Faction m_Faction;
private DateTime m_OrdersEnd;
private Town m_Town;
public BaseFactionGuard(string title) : base(AIType.AI_Melee, FightMode.Closest, 10, 1, 0.2, 0.4)
{
Orders = new Orders(this);
Title = title;
RangeHome = 6;
}
public BaseFactionGuard(Serial serial) : base(serial)
{
}
public override bool BardImmune => true;
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public Faction Faction
{
get => m_Faction;
set
{
Unregister();
m_Faction = value;
Register();
}
}
public Orders Orders{ get; private set; }
[CommandProperty(AccessLevel.GameMaster, AccessLevel.Administrator)]
public Town Town
{
get => m_Town;
set
{
Unregister();
m_Town = value;
Register();
}
}
public abstract GuardAI GuardAI{ get; }
protected override BaseAI ForcedAI => new FactionGuardAI(this);
public override TimeSpan ReacquireDelay => TimeSpan.FromSeconds(2.0);
public override bool ClickTitle => false;
public void Register()
{
if (m_Town != null && m_Faction != null)
m_Town.RegisterGuard(this);
}
public void Unregister()
{
m_Town?.UnregisterGuard(this);
}
public override bool IsEnemy(Mobile m)
{
Faction ourFaction = m_Faction;
Faction theirFaction = Faction.Find(m);
if (theirFaction == null && m is BaseFactionGuard guard)
theirFaction = guard.Faction;
if (ourFaction != null && theirFaction != null && ourFaction != theirFaction)
{
ReactionType reactionType = Orders.GetReaction(theirFaction).Type;
if (reactionType == ReactionType.Attack)
return true;
List<AggressorInfo> list = m.Aggressed;
for (int i = 0; i < list.Count; ++i)
{
AggressorInfo ai = list[i];
if (ai.Defender is BaseFactionGuard bf && bf.Faction == ourFaction)
return true;
}
}
return false;
}
public override void OnMovement(Mobile m, Point3D oldLocation)
{
if (m.Player && m.Alive && InRange(m, 10) && !InRange(oldLocation, 10) && InLOS(m) &&
Orders.GetReaction(Faction.Find(m)).Type == ReactionType.Warn)
{
Direction = GetDirectionTo(m);
string warning = null;
switch (Utility.Random(6))
{
case 0:
warning =
"I warn you, {0}, you would do well to leave this area before someone shows you the world of gray.";
break;
case 1:
warning = "It would be wise to leave this area, {0}, lest your head become my commanders' trophy.";
break;
case 2:
warning =
"You are bold, {0}, for one of the meager {1}. Leave now, lest you be taught the taste of dirt.";
break;
case 3:
warning = "Your presence here is an insult, {0}. Be gone now, knave.";
break;
case 4:
warning = "Dost thou wish to be hung by your toes, {0}? Nay? Then come no closer.";
break;
case 5:
warning = "Hey, {0}. Yeah, you. Get out of here before I beat you with a stick.";
break;
}
Faction faction = Faction.Find(m);
Say(warning, m.Name, faction == null ? "civilians" : faction.Definition.FriendlyName);
}
}
public override bool HandlesOnSpeech(Mobile from)
{
if (InRange(from, ListenRange))
return true;
return base.HandlesOnSpeech(from);
}
private void ChangeReaction(Faction faction, ReactionType type)
{
if (faction == null)
{
switch (type)
{
case ReactionType.Ignore:
Say(1005179);
break; // Civilians will now be ignored.
case ReactionType.Warn:
Say(1005180);
break; // Civilians will now be warned of their impending deaths.
case ReactionType.Attack: return;
}
}
else
{
TextDefinition def = null;
switch (type)
{
case ReactionType.Ignore:
def = faction.Definition.GuardIgnore;
break;
case ReactionType.Warn:
def = faction.Definition.GuardWarn;
break;
case ReactionType.Attack:
def = faction.Definition.GuardAttack;
break;
}
if (def != null && def.Number > 0)
Say(def.Number);
else if (def?.String != null)
Say(def.String);
}
Orders.SetReaction(faction, type);
}
private bool WasNamed(string speech)
{
string name = Name;
return name != null && Insensitive.StartsWith(speech, name);
}
public override void OnSpeech(SpeechEventArgs e)
{
base.OnSpeech(e);
Mobile from = e.Mobile;
if (!e.Handled && InRange(from, ListenRange) && from.Alive)
{
if (e.HasKeyword(0xE6) && (Insensitive.Equals(e.Speech, "orders") || WasNamed(e.Speech))) // *orders*
{
if (m_Town == null || !m_Town.IsSheriff(from))
{
Say(1042189); // I don't work for you!
}
else if (Town.FromRegion(Region) == m_Town)
{
Say(1042180); // Your orders, sire?
m_OrdersEnd = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
}
}
else if (DateTime.UtcNow < m_OrdersEnd)
{
if (m_Town?.IsSheriff(from) != true || Town.FromRegion(Region) != m_Town)
return;
m_OrdersEnd = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
bool understood = true;
ReactionType newType = 0;
if (Insensitive.Contains(e.Speech, "attack"))
newType = ReactionType.Attack;
else if (Insensitive.Contains(e.Speech, "warn"))
newType = ReactionType.Warn;
else if (Insensitive.Contains(e.Speech, "ignore"))
newType = ReactionType.Ignore;
else
understood = false;
if (understood)
{
understood = false;
if (Insensitive.Contains(e.Speech, "civil"))
{
ChangeReaction(null, newType);
understood = true;
}
List<Faction> factions = Faction.Factions;
for (int i = 0; i < factions.Count; ++i)
{
Faction faction = factions[i];
if (faction != m_Faction && Insensitive.Contains(e.Speech, faction.Definition.Keyword))
{
ChangeReaction(faction, newType);
understood = true;
}
}
}
else if (Insensitive.Contains(e.Speech, "patrol"))
{
Home = Location;
RangeHome = 6;
Combatant = null;
Orders.Movement = MovementType.Patrol;
Say(1005146); // This spot looks like it needs protection! I shall guard it with my life.
understood = true;
}
else if (Insensitive.Contains(e.Speech, "follow"))
{
Home = Location;
RangeHome = 6;
Combatant = null;
Orders.Follow = from;
Orders.Movement = MovementType.Follow;
Say(1005144); // Yes, Sire.
understood = true;
}
if (!understood)
Say(1042183); // I'm sorry, I don't understand your orders...
}
}
}
public override void GetProperties(ObjectPropertyList list)
{
base.GetProperties(list);
if (m_Faction != null && Map == Faction.Facet)
list.Add(1060846, m_Faction.Definition.PropName); // Guard: ~1_val~
}
public override void OnSingleClick(Mobile from)
{
if (m_Faction != null && Map == Faction.Facet)
{
string text = string.Concat("(Guard, ", m_Faction.Definition.FriendlyName, ")");
int hue = Faction.Find(from) == m_Faction ? 98 : 38;
PrivateOverheadMessage(MessageType.Label, hue, true, text, from.NetState);
}
base.OnSingleClick(from);
}
public virtual void GenerateRandomHair()
{
Utility.AssignRandomHair(this);
Utility.AssignRandomFacialHair(this, HairHue);
}
public void PackStrongPotions(int min, int max)
{
PackStrongPotions(Utility.RandomMinMax(min, max));
}
public void PackStrongPotions(int count)
{
for (int i = 0; i < count; ++i)
PackStrongPotion();
}
public void PackStrongPotion()
{
PackItem(Loot.Construct(m_StrongPotions));
}
public void PackWeakPotions(int min, int max)
{
PackWeakPotions(Utility.RandomMinMax(min, max));
}
public void PackWeakPotions(int count)
{
for (int i = 0; i < count; ++i)
PackWeakPotion();
}
public void PackWeakPotion()
{
PackItem(Loot.Construct(m_WeakPotions));
}
public Item Immovable(Item item)
{
item.Movable = false;
return item;
}
public Item Newbied(Item item)
{
item.LootType = LootType.Newbied;
return item;
}
public Item Rehued(Item item, int hue)
{
item.Hue = hue;
return item;
}
public Item Layered(Item item, Layer layer)
{
item.Layer = layer;
return item;
}
public Item Resourced(BaseWeapon weapon, CraftResource resource)
{
weapon.Resource = resource;
return weapon;
}
public Item Resourced(BaseArmor armor, CraftResource resource)
{
armor.Resource = resource;
return armor;
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
Unregister();
}
public override void OnDeath(Container c)
{
base.OnDeath(c);
c.Delete();
}
public virtual void GenerateBody(bool isFemale, bool randomHair)
{
Hue = Race.Human.RandomSkinHue();
if (isFemale)
{
Female = true;
Body = 401;
Name = NameList.RandomName("female");
}
else
{
Female = false;
Body = 400;
Name = NameList.RandomName("male");
}
if (randomHair)
GenerateRandomHair();
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
Faction.WriteReference(writer, m_Faction);
Town.WriteReference(writer, m_Town);
Orders.Serialize(writer);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
m_Faction = Faction.ReadReference(reader);
m_Town = Town.ReadReference(reader);
Orders = new Orders(this, reader);
Timer.DelayCall(TimeSpan.Zero, Register);
}
}
public class VirtualMount : IMount
{
private VirtualMountItem m_Item;
public VirtualMount(VirtualMountItem item)
{
m_Item = item;
}
Mobile IMount.Rider
{
get => m_Item.Rider;
set { }
}
public virtual void OnRiderDamaged(int amount, Mobile from, bool willKill)
{
}
}
public class VirtualMountItem : Item, IMountItem
{
private VirtualMount m_Mount;
public VirtualMountItem(Mobile mob) : base(0x3EA0)
{
Layer = Layer.Mount;
Rider = mob;
m_Mount = new VirtualMount(this);
}
public VirtualMountItem(Serial serial) : base(serial)
{
m_Mount = new VirtualMount(this);
}
public Mobile Rider{ get; private set; }
public IMount Mount => m_Mount;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(Rider);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
Rider = reader.ReadMobile();
if (Rider == null)
Delete();
}
}
}

View file

@ -0,0 +1,758 @@
using System;
using System.Collections.Generic;
using Server.Factions.AI;
using Server.Items;
using Server.Mobiles;
using Server.Spells;
using Server.Spells.Fifth;
using Server.Spells.First;
using Server.Spells.Fourth;
using Server.Spells.Second;
using Server.Spells.Seventh;
using Server.Spells.Sixth;
using Server.Spells.Third;
using Server.Targeting;
namespace Server.Factions
{
[Flags]
public enum GuardAI
{
Bless = 0x01, // heal, cure, +stats
Curse = 0x02, // poison, -stats
Melee = 0x04, // weapons
Magic = 0x08, // damage spells
Smart = 0x10 // smart weapons/damage spells
}
public class ComboEntry
{
public ComboEntry(Type spell, int chance = 100) : this(spell, chance, TimeSpan.Zero)
{
}
public ComboEntry(Type spell, int chance, TimeSpan hold)
{
Spell = spell;
Chance = chance;
Hold = hold;
}
public Type Spell{ get; }
public TimeSpan Hold{ get; }
public int Chance{ get; }
}
public class SpellCombo
{
public static readonly SpellCombo Simple = new SpellCombo(50,
new ComboEntry(typeof(ParalyzeSpell), 20),
new ComboEntry(typeof(ExplosionSpell), 100, TimeSpan.FromSeconds(2.8)),
new ComboEntry(typeof(PoisonSpell), 30),
new ComboEntry(typeof(EnergyBoltSpell))
);
public static readonly SpellCombo Strong = new SpellCombo(90,
new ComboEntry(typeof(ParalyzeSpell), 20),
new ComboEntry(typeof(ExplosionSpell), 50, TimeSpan.FromSeconds(2.8)),
new ComboEntry(typeof(PoisonSpell), 30),
new ComboEntry(typeof(ExplosionSpell), 100, TimeSpan.FromSeconds(2.8)),
new ComboEntry(typeof(EnergyBoltSpell)),
new ComboEntry(typeof(PoisonSpell), 30),
new ComboEntry(typeof(EnergyBoltSpell))
);
public SpellCombo(int mana, params ComboEntry[] entries)
{
Mana = mana;
Entries = entries;
}
public int Mana{ get; }
public ComboEntry[] Entries{ get; }
public static Spell Process(Mobile mob, Mobile targ, ref SpellCombo combo, ref int index, ref DateTime releaseTime)
{
while (++index < combo.Entries.Length)
{
ComboEntry entry = combo.Entries[index];
if (entry.Spell == typeof(PoisonSpell) && targ.Poisoned)
continue;
if (entry.Chance > Utility.Random(100))
{
releaseTime = DateTime.UtcNow + entry.Hold;
return (Spell)Activator.CreateInstance(entry.Spell, mob, null);
}
}
combo = null;
index = -1;
return null;
}
}
public class FactionGuardAI : BaseAI
{
private const int ManaReserve = 30;
private BandageContext m_Bandage;
private DateTime m_BandageStart;
private SpellCombo m_Combo;
private int m_ComboIndex = -1;
private BaseFactionGuard m_Guard;
private DateTime m_ReleaseTarget;
public FactionGuardAI(BaseFactionGuard guard) : base(guard)
{
m_Guard = guard;
}
public bool IsDamaged => m_Guard.Hits < m_Guard.HitsMax;
public bool IsPoisoned => m_Guard.Poisoned;
public TimeSpan TimeUntilBandage
{
get
{
if (m_Bandage != null && m_Bandage.Timer == null)
m_Bandage = null;
if (m_Bandage == null)
return TimeSpan.MaxValue;
TimeSpan ts = m_BandageStart + m_Bandage.Timer.Delay - DateTime.UtcNow;
if (ts < TimeSpan.FromSeconds(-1.0))
{
m_Bandage = null;
return TimeSpan.MaxValue;
}
if (ts < TimeSpan.Zero)
ts = TimeSpan.Zero;
return ts;
}
}
public bool IsAllowed(GuardAI flag)
{
return (m_Guard.GuardAI & flag) == flag;
}
public bool DequipWeapon()
{
Container pack = m_Guard.Backpack;
if (pack == null)
return false;
if (m_Guard.Weapon is Item weapon && weapon.Parent == m_Guard && !(weapon is Fists))
{
pack.DropItem(weapon);
return true;
}
return false;
}
public bool EquipWeapon()
{
Item weapon = m_Guard.Backpack?.FindItemByType<BaseWeapon>();
return weapon != null && m_Guard.EquipItem(weapon);
}
public bool StartBandage()
{
m_Bandage = null;
if (m_Guard.Backpack?.FindItemByType<Bandage>() == null)
return false;
m_Bandage = BandageContext.BeginHeal(m_Guard, m_Guard);
m_BandageStart = DateTime.UtcNow;
return m_Bandage != null;
}
public bool UseItemByType(Type type)
{
Container pack = m_Guard.Backpack;
Item item = pack?.FindItemByType(type);
if (item == null)
return false;
bool requip = DequipWeapon();
item.OnDoubleClick(m_Guard);
if (requip)
EquipWeapon();
return true;
}
public int GetStatMod(Mobile mob, StatType type)
{
StatMod mod = mob.GetStatMod($"[Magic] {type} Offset");
if (mod == null)
return 0;
return mod.Offset;
}
public Spell RandomOffenseSpell()
{
int maxCircle = (int)((m_Guard.Skills.Magery.Value + 20.0) / (100.0 / 7.0));
if (maxCircle < 1)
maxCircle = 1;
switch (Utility.Random(maxCircle * 2))
{
case 0:
case 1: return new MagicArrowSpell(m_Guard);
case 2:
case 3: return new HarmSpell(m_Guard);
case 4:
case 5: return new FireballSpell(m_Guard);
case 6:
case 7: return new LightningSpell(m_Guard);
case 8: return new MindBlastSpell(m_Guard);
case 9: return new ParalyzeSpell(m_Guard);
case 10: return new EnergyBoltSpell(m_Guard);
case 11: return new ExplosionSpell(m_Guard);
default: return new FlameStrikeSpell(m_Guard);
}
}
public Mobile FindDispelTarget(bool activeOnly)
{
if (m_Mobile.Deleted || m_Mobile.Int < 95 || CanDispel(m_Mobile) || m_Mobile.AutoDispel)
return null;
if (activeOnly)
{
List<AggressorInfo> aggressed = m_Mobile.Aggressed;
List<AggressorInfo> aggressors = m_Mobile.Aggressors;
Mobile active = null;
double activePrio = 0.0;
Mobile comb = m_Mobile.Combatant;
if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && m_Mobile.InRange(comb, 12) &&
CanDispel(comb))
{
active = comb;
activePrio = m_Mobile.GetDistanceToSqrt(comb);
if (activePrio <= 2)
return active;
}
for (int i = 0; i < aggressed.Count; ++i)
{
AggressorInfo info = aggressed[i];
Mobile m = info.Defender;
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
{
double prio = m_Mobile.GetDistanceToSqrt(m);
if (active == null || prio < activePrio)
{
active = m;
activePrio = prio;
if (activePrio <= 2)
return active;
}
}
}
for (int i = 0; i < aggressors.Count; ++i)
{
AggressorInfo info = aggressors[i];
Mobile m = info.Attacker;
if (m != comb && m.Combatant == m_Mobile && m_Mobile.InRange(m, 12) && CanDispel(m))
{
double prio = m_Mobile.GetDistanceToSqrt(m);
if (active == null || prio < activePrio)
{
active = m;
activePrio = prio;
if (activePrio <= 2)
return active;
}
}
}
return active;
}
Map map = m_Mobile.Map;
if (map != null)
{
Mobile active = null, inactive = null;
double actPrio = 0.0, inactPrio = 0.0;
Mobile comb = m_Mobile.Combatant;
if (comb?.Deleted == false && comb.Alive && !comb.IsDeadBondedPet && CanDispel(comb))
{
active = inactive = comb;
actPrio = inactPrio = m_Mobile.GetDistanceToSqrt(comb);
}
foreach (Mobile m in m_Mobile.GetMobilesInRange(12))
if (m != m_Mobile && CanDispel(m))
{
double prio = m_Mobile.GetDistanceToSqrt(m);
if (inactive == null || prio < inactPrio)
{
inactive = m;
inactPrio = prio;
}
if ((m_Mobile.Combatant == m || m.Combatant == m_Mobile) && (active == null || prio < actPrio))
{
active = m;
actPrio = prio;
}
}
return active ?? inactive;
}
return null;
}
public bool CanDispel(Mobile m)
{
return m is BaseCreature creature && creature.Summoned && m_Mobile.CanBeHarmful(creature, false) &&
!creature.IsAnimatedDead;
}
public void RunTo(Mobile m)
{
/*if ( m.Paralyzed || m.Frozen )
{
if ( m_Mobile.InRange( m, 1 ) )
RunFrom( m );
else if ( !m_Mobile.InRange( m, m_Mobile.RangeFight > 2 ? m_Mobile.RangeFight : 2 ) && !MoveTo( m, true, 1 ) )
OnFailedMove();
}
else
{*/
if (!m_Mobile.InRange(m, m_Mobile.RangeFight))
{
if (!MoveTo(m, true, 1))
OnFailedMove();
}
else if (m_Mobile.InRange(m, m_Mobile.RangeFight - 1))
{
RunFrom(m);
}
/*}*/
}
public void RunFrom(Mobile m)
{
Run((m_Mobile.GetDirectionTo(m) - 4) & Direction.Mask);
}
public void OnFailedMove()
{
/*if ( !m_Mobile.DisallowAllMoves && 20 > Utility.Random( 100 ) && IsAllowed( GuardAI.Magic ) )
{
if ( m_Mobile.Target != null )
m_Mobile.Target.Cancel( m_Mobile, TargetCancelType.Canceled );
new TeleportSpell( m_Mobile, null ).Cast();
m_Mobile.DebugSay( "I am stuck, I'm going to try teleporting away" );
}
else*/
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
if (m_Mobile.Debug)
m_Mobile.DebugSay("My move is blocked, so I am going to attack {0}", m_Mobile.FocusMob.Name);
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
m_Mobile.DebugSay("I am stuck");
}
}
public void Run(Direction d)
{
if (m_Mobile.Spell != null && m_Mobile.Spell.IsCasting || m_Mobile.Paralyzed || m_Mobile.Frozen ||
m_Mobile.DisallowAllMoves)
return;
m_Mobile.Direction = d | Direction.Running;
if (!DoMove(m_Mobile.Direction, true))
OnFailedMove();
}
public override bool Think()
{
if (m_Mobile.Deleted)
return false;
Mobile combatant = m_Guard.Combatant;
if (combatant?.Deleted != false || !combatant.Alive || combatant.IsDeadBondedPet ||
!m_Mobile.CanSee(combatant) || !m_Mobile.CanBeHarmful(combatant, false) || combatant.Map != m_Mobile.Map)
{
// Our combatant is deleted, dead, hidden, or we cannot hurt them
// Try to find another combatant
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else
{
m_Mobile.Combatant = combatant = null;
}
}
if (combatant != null && (!m_Mobile.InLOS(combatant) || !m_Mobile.InRange(combatant, 12)))
{
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else if (!m_Mobile.InRange(combatant, 36))
{
m_Mobile.Combatant = combatant = null;
}
}
Mobile dispelTarget = FindDispelTarget(true);
if (m_Guard.Target != null && m_ReleaseTarget == DateTime.MinValue)
m_ReleaseTarget = DateTime.UtcNow + TimeSpan.FromSeconds(10.0);
if (m_Guard.Target != null && DateTime.UtcNow > m_ReleaseTarget)
{
Target targ = m_Guard.Target;
Mobile toHarm = dispelTarget ?? combatant;
if ((targ.Flags & TargetFlags.Harmful) != 0 && toHarm != null)
{
if (m_Guard.Map == toHarm.Map && (targ.Range < 0 || m_Guard.InRange(toHarm, targ.Range)) &&
m_Guard.CanSee(toHarm) && m_Guard.InLOS(toHarm))
targ.Invoke(m_Guard, toHarm);
else if ((targ as ISpellTarget)?.Spell is DispelSpell)
targ.Cancel(m_Guard, TargetCancelType.Canceled);
}
else if ((targ.Flags & TargetFlags.Beneficial) != 0)
{
targ.Invoke(m_Guard, m_Guard);
}
else
{
targ.Cancel(m_Guard, TargetCancelType.Canceled);
}
m_ReleaseTarget = DateTime.MinValue;
}
if (dispelTarget != null)
{
if (Action != ActionType.Combat)
Action = ActionType.Combat;
m_Guard.Warmode = true;
RunFrom(dispelTarget);
}
else if (combatant != null)
{
if (Action != ActionType.Combat)
Action = ActionType.Combat;
m_Guard.Warmode = true;
RunTo(combatant);
}
else if (m_Guard.Orders.Movement != MovementType.Stand)
{
Mobile toFollow = null;
if (m_Guard.Town != null && m_Guard.Orders.Movement == MovementType.Follow)
{
toFollow = m_Guard.Orders.Follow ?? m_Guard.Town.Sheriff;
}
if (toFollow != null && toFollow.Map == m_Guard.Map &&
toFollow.InRange(m_Guard, m_Guard.RangePerception * 3) &&
Town.FromRegion(toFollow.Region) == m_Guard.Town)
{
if (Action != ActionType.Combat)
Action = ActionType.Combat;
if (m_Mobile.CurrentSpeed != m_Mobile.ActiveSpeed)
m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed;
m_Guard.Warmode = true;
RunTo(toFollow);
}
else
{
if (Action != ActionType.Wander)
Action = ActionType.Wander;
if (m_Mobile.CurrentSpeed != m_Mobile.PassiveSpeed)
m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed;
m_Guard.Warmode = false;
WalkRandomInHome(2, 2, 1);
}
}
else
{
if (Action != ActionType.Wander)
Action = ActionType.Wander;
m_Guard.Warmode = false;
}
if ((IsDamaged || IsPoisoned) && m_Guard.Skills.Healing.Base > 20.0)
{
TimeSpan ts = TimeUntilBandage;
if (ts == TimeSpan.MaxValue)
StartBandage();
}
Spell spell = m_Mobile.Spell as Spell;
if (spell == null && Core.TickCount - m_Mobile.NextSpellTime >= 0)
{
DateTime toRelease = DateTime.MinValue;
if (IsPoisoned)
{
Poison p = m_Guard.Poison;
TimeSpan ts = TimeUntilBandage;
if (p != Poison.Lesser || ts == TimeSpan.MaxValue || TimeUntilBandage < TimeSpan.FromSeconds(1.5) ||
m_Guard.HitsMax - m_Guard.Hits > Utility.Random(250))
{
if (IsAllowed(GuardAI.Bless))
spell = new CureSpell(m_Guard);
else
UseItemByType(typeof(BaseCurePotion));
}
}
else if (IsDamaged && m_Guard.HitsMax - m_Guard.Hits > Utility.Random(200))
{
if (IsAllowed(GuardAI.Magic) && m_Guard.Hits * 100 / Math.Max(m_Guard.HitsMax, 1) < 10 &&
m_Guard.Home != Point3D.Zero && !Utility.InRange(m_Guard.Location, m_Guard.Home, 15) &&
m_Guard.Mana >= 11)
{
spell = new RecallSpell(m_Guard,
new RunebookEntry(m_Guard.Home, m_Guard.Map, "Guard's Home"));
}
else if (IsAllowed(GuardAI.Bless))
{
if (m_Guard.Mana >= 11 && m_Guard.Hits + 30 < m_Guard.HitsMax)
spell = new GreaterHealSpell(m_Guard);
else if (m_Guard.Hits + 10 < m_Guard.HitsMax &&
(m_Guard.Mana < 11 || m_Guard.NextCombatTime - Core.TickCount > 2000))
spell = new HealSpell(m_Guard);
}
else if (m_Guard.CanBeginAction<BaseHealPotion>())
{
UseItemByType(typeof(BaseHealPotion));
}
}
else if (dispelTarget != null &&
(IsAllowed(GuardAI.Magic) || IsAllowed(GuardAI.Bless) || IsAllowed(GuardAI.Curse)))
{
if (!dispelTarget.Paralyzed && m_Guard.Mana > ManaReserve + 20 && 40 > Utility.Random(100))
spell = new ParalyzeSpell(m_Guard);
else
spell = new DispelSpell(m_Guard);
}
if (combatant != null)
{
if (m_Combo != null)
{
if (spell == null)
{
spell = SpellCombo.Process(m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease);
}
else
{
m_Combo = null;
m_ComboIndex = -1;
}
}
else if (20 > Utility.Random(100) && IsAllowed(GuardAI.Magic))
{
if (80 > Utility.Random(100))
{
m_Combo = IsAllowed(GuardAI.Smart) ? SpellCombo.Simple : SpellCombo.Strong;
m_ComboIndex = -1;
if (m_Guard.Mana >= ManaReserve + m_Combo.Mana)
{
spell = SpellCombo.Process(m_Guard, combatant, ref m_Combo, ref m_ComboIndex, ref toRelease);
}
else
{
m_Combo = null;
if (m_Guard.Mana >= ManaReserve + 40)
spell = RandomOffenseSpell();
}
}
else if (m_Guard.Mana >= ManaReserve + 40)
{
spell = RandomOffenseSpell();
}
}
if (spell == null && 2 > Utility.Random(100) && m_Guard.Mana >= ManaReserve + 10)
{
int strMod = GetStatMod(m_Guard, StatType.Str);
int dexMod = GetStatMod(m_Guard, StatType.Dex);
int intMod = GetStatMod(m_Guard, StatType.Int);
List<Type> types = new List<Type>();
if (strMod <= 0)
types.Add(typeof(StrengthSpell));
if (dexMod <= 0 && IsAllowed(GuardAI.Melee))
types.Add(typeof(AgilitySpell));
if (intMod <= 0 && IsAllowed(GuardAI.Magic))
types.Add(typeof(CunningSpell));
if (IsAllowed(GuardAI.Bless))
{
if (types.Count > 1)
spell = new BlessSpell(m_Guard);
else if (types.Count == 1)
spell = Activator.CreateInstance(types[0], m_Guard, null) as Spell;
}
else if (types.Count > 0)
{
if (types[0] == typeof(StrengthSpell))
UseItemByType(typeof(BaseStrengthPotion));
else if (types[0] == typeof(AgilitySpell))
UseItemByType(typeof(BaseAgilityPotion));
}
}
if (spell == null && 2 > Utility.Random(100) && m_Guard.Mana >= ManaReserve + 10 &&
IsAllowed(GuardAI.Curse))
{
if (!combatant.Poisoned && 40 > Utility.Random(100))
{
spell = new PoisonSpell(m_Guard);
}
else
{
int strMod = GetStatMod(combatant, StatType.Str);
int dexMod = GetStatMod(combatant, StatType.Dex);
int intMod = GetStatMod(combatant, StatType.Int);
List<Type> types = new List<Type>();
if (strMod >= 0)
types.Add(typeof(WeakenSpell));
if (dexMod >= 0 && IsAllowed(GuardAI.Melee))
types.Add(typeof(ClumsySpell));
if (intMod >= 0 && IsAllowed(GuardAI.Magic))
types.Add(typeof(FeeblemindSpell));
if (types.Count > 1)
spell = new CurseSpell(m_Guard);
else if (types.Count == 1)
spell = (Spell)Activator.CreateInstance(types[0], m_Guard, null);
}
}
}
if (spell != null && m_Guard.HitsMax - m_Guard.Hits + 10 > Utility.Random(100))
{
Type type = null;
if (spell is GreaterHealSpell)
type = typeof(BaseHealPotion);
else if (spell is CureSpell)
type = typeof(BaseCurePotion);
else if (spell is StrengthSpell)
type = typeof(BaseStrengthPotion);
else if (spell is AgilitySpell)
type = typeof(BaseAgilityPotion);
if (type == typeof(BaseHealPotion) && !m_Guard.CanBeginAction(type))
type = null;
if (type != null && m_Guard.Target == null && UseItemByType(type))
{
if (spell is GreaterHealSpell)
{
if (m_Guard.Hits + 30 > m_Guard.HitsMax && m_Guard.Hits + 10 < m_Guard.HitsMax)
spell = new HealSpell(m_Guard);
}
else
{
spell = null;
}
}
}
else if (spell == null && m_Guard.Stam < m_Guard.StamMax / 3 && IsAllowed(GuardAI.Melee))
{
UseItemByType(typeof(BaseRefreshPotion));
}
if (spell?.Cast() != true)
EquipWeapon();
}
else if (spell?.State == SpellState.Sequencing)
{
EquipWeapon();
}
return true;
}
}
}

View file

@ -0,0 +1,141 @@
using System.Collections.Generic;
namespace Server.Factions.AI
{
public enum ReactionType
{
Ignore,
Warn,
Attack
}
public enum MovementType
{
Stand,
Patrol,
Follow
}
public class Reaction
{
public Reaction(Faction faction, ReactionType type)
{
Faction = faction;
Type = type;
}
public Reaction(GenericReader reader)
{
int version = reader.ReadEncodedInt();
switch (version)
{
case 0:
{
Faction = Faction.ReadReference(reader);
Type = (ReactionType)reader.ReadEncodedInt();
break;
}
}
}
public Faction Faction{ get; }
public ReactionType Type{ get; set; }
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(0); // version
Faction.WriteReference(writer, Faction);
writer.WriteEncodedInt((int)Type);
}
}
public class Orders
{
private List<Reaction> m_Reactions;
public Orders(BaseFactionGuard guard)
{
Guard = guard;
m_Reactions = new List<Reaction>();
Movement = MovementType.Patrol;
}
public Orders(BaseFactionGuard guard, GenericReader reader)
{
Guard = guard;
int version = reader.ReadEncodedInt();
switch (version)
{
case 1:
{
Follow = reader.ReadMobile();
goto case 0;
}
case 0:
{
int count = reader.ReadEncodedInt();
m_Reactions = new List<Reaction>(count);
for (int i = 0; i < count; ++i)
m_Reactions.Add(new Reaction(reader));
Movement = (MovementType)reader.ReadEncodedInt();
break;
}
}
}
public BaseFactionGuard Guard{ get; }
public MovementType Movement{ get; set; }
public Mobile Follow{ get; set; }
public Reaction GetReaction(Faction faction)
{
Reaction reaction;
for (int i = 0; i < m_Reactions.Count; ++i)
{
reaction = m_Reactions[i];
if (reaction.Faction == faction)
return reaction;
}
reaction = new Reaction(faction,
faction == null || faction == Guard.Faction ? ReactionType.Ignore : ReactionType.Attack);
m_Reactions.Add(reaction);
return reaction;
}
public void SetReaction(Faction faction, ReactionType type)
{
Reaction reaction = GetReaction(faction);
reaction.Type = type;
}
public void Serialize(GenericWriter writer)
{
writer.WriteEncodedInt(1); // version
writer.Write(Follow);
writer.WriteEncodedInt(m_Reactions.Count);
for (int i = 0; i < m_Reactions.Count; ++i)
m_Reactions[i].Serialize(writer);
writer.WriteEncodedInt((int)Movement);
}
}
}

View file

@ -0,0 +1,72 @@
using Server.Items;
namespace Server.Factions
{
public class FactionBerserker : BaseFactionGuard
{
[Constructible]
public FactionBerserker() : base("the berserker")
{
GenerateBody(false, false);
SetStr(126, 150);
SetDex(61, 85);
SetInt(81, 95);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 50);
SetResistance(ResistanceType.Fire, 30, 50);
SetResistance(ResistanceType.Cold, 30, 50);
SetResistance(ResistanceType.Energy, 30, 50);
SetResistance(ResistanceType.Poison, 30, 50);
VirtualArmor = 24;
SetSkill(SkillName.Swords, 100.0, 110.0);
SetSkill(SkillName.Wrestling, 100.0, 110.0);
SetSkill(SkillName.Tactics, 100.0, 110.0);
SetSkill(SkillName.MagicResist, 100.0, 110.0);
SetSkill(SkillName.Healing, 100.0, 110.0);
SetSkill(SkillName.Anatomy, 100.0, 110.0);
SetSkill(SkillName.Magery, 100.0, 110.0);
SetSkill(SkillName.EvalInt, 100.0, 110.0);
SetSkill(SkillName.Meditation, 100.0, 110.0);
AddItem(Immovable(Rehued(new BodySash(), 1645)));
AddItem(Immovable(Rehued(new Kilt(), 1645)));
AddItem(Immovable(Rehued(new Sandals(), 1645)));
AddItem(Newbied(new DoubleAxe()));
HairItemID = 0x2047; // Afro
HairHue = 0x29;
FacialHairItemID = 0x204B; // Medium Short Beard
FacialHairHue = 0x29;
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionBerserker(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Curse | GuardAI.Bless;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,68 @@
using Server.Items;
namespace Server.Factions
{
public class FactionDeathKnight : BaseFactionGuard
{
[Constructible]
public FactionDeathKnight() : base("the death knight")
{
GenerateBody(false, false);
Hue = 1;
SetStr(126, 150);
SetDex(61, 85);
SetInt(81, 95);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 50);
SetResistance(ResistanceType.Fire, 30, 50);
SetResistance(ResistanceType.Cold, 30, 50);
SetResistance(ResistanceType.Energy, 30, 50);
SetResistance(ResistanceType.Poison, 30, 50);
VirtualArmor = 24;
SetSkill(SkillName.Swords, 100.0, 110.0);
SetSkill(SkillName.Wrestling, 100.0, 110.0);
SetSkill(SkillName.Tactics, 100.0, 110.0);
SetSkill(SkillName.MagicResist, 100.0, 110.0);
SetSkill(SkillName.Healing, 100.0, 110.0);
SetSkill(SkillName.Anatomy, 100.0, 110.0);
SetSkill(SkillName.Magery, 100.0, 110.0);
SetSkill(SkillName.EvalInt, 100.0, 110.0);
SetSkill(SkillName.Meditation, 100.0, 110.0);
Item shroud = new Item(0x204E);
shroud.Layer = Layer.OuterTorso;
AddItem(Immovable(Rehued(shroud, 1109)));
AddItem(Newbied(Rehued(new ExecutionersAxe(), 2211)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionDeathKnight(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Curse | GuardAI.Bless;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,72 @@
using Server.Items;
namespace Server.Factions
{
public class FactionDragoon : BaseFactionGuard
{
[Constructible]
public FactionDragoon() : base("the dragoon")
{
GenerateBody(false, false);
SetStr(151, 175);
SetDex(61, 85);
SetInt(151, 175);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 40, 60);
SetResistance(ResistanceType.Cold, 40, 60);
SetResistance(ResistanceType.Energy, 40, 60);
SetResistance(ResistanceType.Poison, 40, 60);
VirtualArmor = 32;
SetSkill(SkillName.Macing, 110.0, 120.0);
SetSkill(SkillName.Wrestling, 110.0, 120.0);
SetSkill(SkillName.Tactics, 110.0, 120.0);
SetSkill(SkillName.MagicResist, 110.0, 120.0);
SetSkill(SkillName.Healing, 110.0, 120.0);
SetSkill(SkillName.Anatomy, 110.0, 120.0);
SetSkill(SkillName.Magery, 110.0, 120.0);
SetSkill(SkillName.EvalInt, 110.0, 120.0);
SetSkill(SkillName.Meditation, 110.0, 120.0);
AddItem(Immovable(Rehued(new Cloak(), 1645)));
AddItem(Immovable(Rehued(new PlateChest(), 1645)));
AddItem(Immovable(Rehued(new PlateLegs(), 1109)));
AddItem(Immovable(Rehued(new PlateArms(), 1109)));
AddItem(Immovable(Rehued(new PlateGloves(), 1109)));
AddItem(Immovable(Rehued(new PlateGorget(), 1109)));
AddItem(Immovable(Rehued(new PlateHelm(), 1109)));
AddItem(Newbied(new WarHammer()));
AddItem(Immovable(Rehued(new VirtualMountItem(this), 1109)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionDragoon(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,65 @@
using Server.Items;
namespace Server.Factions
{
public class FactionHenchman : BaseFactionGuard
{
[Constructible]
public FactionHenchman() : base("the henchman")
{
GenerateBody(false, true);
SetStr(91, 115);
SetDex(61, 85);
SetInt(81, 95);
SetDamage(10, 14);
SetResistance(ResistanceType.Physical, 10, 30);
SetResistance(ResistanceType.Fire, 10, 30);
SetResistance(ResistanceType.Cold, 10, 30);
SetResistance(ResistanceType.Energy, 10, 30);
SetResistance(ResistanceType.Poison, 10, 30);
VirtualArmor = 8;
SetSkill(SkillName.Fencing, 80.0, 90.0);
SetSkill(SkillName.Wrestling, 80.0, 90.0);
SetSkill(SkillName.Tactics, 80.0, 90.0);
SetSkill(SkillName.MagicResist, 80.0, 90.0);
SetSkill(SkillName.Healing, 80.0, 90.0);
SetSkill(SkillName.Anatomy, 80.0, 90.0);
AddItem(new StuddedChest());
AddItem(new StuddedLegs());
AddItem(new StuddedArms());
AddItem(new StuddedGloves());
AddItem(new StuddedGorget());
AddItem(new Boots());
AddItem(Newbied(new Spear()));
PackItem(new Bandage(Utility.RandomMinMax(10, 20)));
PackWeakPotions(1, 4);
}
public FactionHenchman(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Melee;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,73 @@
using Server.Items;
namespace Server.Factions
{
public class FactionKnight : BaseFactionGuard
{
[Constructible]
public FactionKnight() : base("the knight")
{
GenerateBody(false, false);
SetStr(126, 150);
SetDex(61, 85);
SetInt(81, 95);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 50);
SetResistance(ResistanceType.Fire, 30, 50);
SetResistance(ResistanceType.Cold, 30, 50);
SetResistance(ResistanceType.Energy, 30, 50);
SetResistance(ResistanceType.Poison, 30, 50);
VirtualArmor = 24;
SetSkill(SkillName.Swords, 100.0, 110.0);
SetSkill(SkillName.Wrestling, 100.0, 110.0);
SetSkill(SkillName.Tactics, 100.0, 110.0);
SetSkill(SkillName.MagicResist, 100.0, 110.0);
SetSkill(SkillName.Healing, 100.0, 110.0);
SetSkill(SkillName.Anatomy, 100.0, 110.0);
SetSkill(SkillName.Magery, 100.0, 110.0);
SetSkill(SkillName.EvalInt, 100.0, 110.0);
SetSkill(SkillName.Meditation, 100.0, 110.0);
AddItem(Immovable(Rehued(new ChainChest(), 2125)));
AddItem(Immovable(Rehued(new ChainLegs(), 2125)));
AddItem(Immovable(Rehued(new ChainCoif(), 2125)));
AddItem(Immovable(Rehued(new PlateArms(), 2125)));
AddItem(Immovable(Rehued(new PlateGloves(), 2125)));
AddItem(Immovable(Rehued(new BodySash(), 1254)));
AddItem(Immovable(Rehued(new Kilt(), 1254)));
AddItem(Immovable(Rehued(new Sandals(), 1254)));
AddItem(Newbied(new Bardiche()));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionKnight(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,63 @@
using Server.Items;
namespace Server.Factions
{
public class FactionMercenary : BaseFactionGuard
{
[Constructible]
public FactionMercenary() : base("the mercenary")
{
GenerateBody(false, true);
SetStr(116, 125);
SetDex(61, 85);
SetInt(81, 95);
SetResistance(ResistanceType.Physical, 20, 40);
SetResistance(ResistanceType.Fire, 20, 40);
SetResistance(ResistanceType.Cold, 20, 40);
SetResistance(ResistanceType.Energy, 20, 40);
SetResistance(ResistanceType.Poison, 20, 40);
VirtualArmor = 16;
SetSkill(SkillName.Fencing, 90.0, 100.0);
SetSkill(SkillName.Wrestling, 90.0, 100.0);
SetSkill(SkillName.Tactics, 90.0, 100.0);
SetSkill(SkillName.MagicResist, 90.0, 100.0);
SetSkill(SkillName.Healing, 90.0, 100.0);
SetSkill(SkillName.Anatomy, 90.0, 100.0);
AddItem(new ChainChest());
AddItem(new ChainLegs());
AddItem(new RingmailArms());
AddItem(new RingmailGloves());
AddItem(new ChainCoif());
AddItem(new Boots());
AddItem(Newbied(new ShortSpear()));
PackItem(new Bandage(Utility.RandomMinMax(20, 30)));
PackStrongPotions(3, 8);
}
public FactionMercenary(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Melee | GuardAI.Smart;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,66 @@
using Server.Items;
namespace Server.Factions
{
public class FactionNecromancer : BaseFactionGuard
{
[Constructible]
public FactionNecromancer() : base("the necromancer")
{
GenerateBody(false, false);
Hue = 1;
SetStr(151, 175);
SetDex(61, 85);
SetInt(151, 175);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 40, 60);
SetResistance(ResistanceType.Cold, 40, 60);
SetResistance(ResistanceType.Energy, 40, 60);
SetResistance(ResistanceType.Poison, 40, 60);
VirtualArmor = 32;
SetSkill(SkillName.Macing, 110.0, 120.0);
SetSkill(SkillName.Wrestling, 110.0, 120.0);
SetSkill(SkillName.Tactics, 110.0, 120.0);
SetSkill(SkillName.MagicResist, 110.0, 120.0);
SetSkill(SkillName.Healing, 110.0, 120.0);
SetSkill(SkillName.Anatomy, 110.0, 120.0);
SetSkill(SkillName.Magery, 110.0, 120.0);
SetSkill(SkillName.EvalInt, 110.0, 120.0);
SetSkill(SkillName.Meditation, 110.0, 120.0);
Item shroud = new Item(0x204E);
shroud.Layer = Layer.OuterTorso;
AddItem(Immovable(Rehued(shroud, 1109)));
AddItem(Newbied(Rehued(new GnarledStaff(), 2211)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionNecromancer(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,73 @@
using Server.Items;
namespace Server.Factions
{
public class FactionPaladin : BaseFactionGuard
{
[Constructible]
public FactionPaladin() : base("the paladin")
{
GenerateBody(false, false);
SetStr(151, 175);
SetDex(61, 85);
SetInt(81, 95);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 40, 60);
SetResistance(ResistanceType.Cold, 40, 60);
SetResistance(ResistanceType.Energy, 40, 60);
SetResistance(ResistanceType.Poison, 40, 60);
VirtualArmor = 32;
SetSkill(SkillName.Swords, 110.0, 120.0);
SetSkill(SkillName.Wrestling, 110.0, 120.0);
SetSkill(SkillName.Tactics, 110.0, 120.0);
SetSkill(SkillName.MagicResist, 110.0, 120.0);
SetSkill(SkillName.Healing, 110.0, 120.0);
SetSkill(SkillName.Anatomy, 110.0, 120.0);
SetSkill(SkillName.Magery, 110.0, 120.0);
SetSkill(SkillName.EvalInt, 110.0, 120.0);
SetSkill(SkillName.Meditation, 110.0, 120.0);
AddItem(Immovable(Rehued(new PlateChest(), 2125)));
AddItem(Immovable(Rehued(new PlateLegs(), 2125)));
AddItem(Immovable(Rehued(new PlateHelm(), 2125)));
AddItem(Immovable(Rehued(new PlateGorget(), 2125)));
AddItem(Immovable(Rehued(new PlateArms(), 2125)));
AddItem(Immovable(Rehued(new PlateGloves(), 2125)));
AddItem(Immovable(Rehued(new BodySash(), 1254)));
AddItem(Immovable(Rehued(new Cloak(), 1254)));
AddItem(Newbied(new Halberd()));
AddItem(Immovable(Rehued(new VirtualMountItem(this), 1254)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionPaladin(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Melee | GuardAI.Smart | GuardAI.Curse | GuardAI.Bless;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,70 @@
using Server.Items;
namespace Server.Factions
{
public class FactionSorceress : BaseFactionGuard
{
[Constructible]
public FactionSorceress() : base("the sorceress")
{
GenerateBody(true, false);
SetStr(126, 150);
SetDex(61, 85);
SetInt(126, 150);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 30, 50);
SetResistance(ResistanceType.Fire, 30, 50);
SetResistance(ResistanceType.Cold, 30, 50);
SetResistance(ResistanceType.Energy, 30, 50);
SetResistance(ResistanceType.Poison, 30, 50);
VirtualArmor = 24;
SetSkill(SkillName.Macing, 100.0, 110.0);
SetSkill(SkillName.Wrestling, 100.0, 110.0);
SetSkill(SkillName.Tactics, 100.0, 110.0);
SetSkill(SkillName.MagicResist, 100.0, 110.0);
SetSkill(SkillName.Healing, 100.0, 110.0);
SetSkill(SkillName.Anatomy, 100.0, 110.0);
SetSkill(SkillName.Magery, 100.0, 110.0);
SetSkill(SkillName.EvalInt, 100.0, 110.0);
SetSkill(SkillName.Meditation, 100.0, 110.0);
AddItem(Immovable(Rehued(new WizardsHat(), 1325)));
AddItem(Immovable(Rehued(new Sandals(), 1325)));
AddItem(Immovable(Rehued(new LeatherGorget(), 1325)));
AddItem(Immovable(Rehued(new LeatherGloves(), 1325)));
AddItem(Immovable(Rehued(new LeatherLegs(), 1325)));
AddItem(Immovable(Rehued(new Skirt(), 1325)));
AddItem(Immovable(Rehued(new FemaleLeatherChest(), 1325)));
AddItem(Newbied(Rehued(new QuarterStaff(), 1310)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionSorceress(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Bless | GuardAI.Curse;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,67 @@
using Server.Items;
namespace Server.Factions
{
public class FactionWizard : BaseFactionGuard
{
[Constructible]
public FactionWizard() : base("the wizard")
{
GenerateBody(false, false);
SetStr(151, 175);
SetDex(61, 85);
SetInt(151, 175);
SetDamageType(ResistanceType.Physical, 100);
SetResistance(ResistanceType.Physical, 40, 60);
SetResistance(ResistanceType.Fire, 40, 60);
SetResistance(ResistanceType.Cold, 40, 60);
SetResistance(ResistanceType.Energy, 40, 60);
SetResistance(ResistanceType.Poison, 40, 60);
VirtualArmor = 32;
SetSkill(SkillName.Macing, 110.0, 120.0);
SetSkill(SkillName.Wrestling, 110.0, 120.0);
SetSkill(SkillName.Tactics, 110.0, 120.0);
SetSkill(SkillName.MagicResist, 110.0, 120.0);
SetSkill(SkillName.Healing, 110.0, 120.0);
SetSkill(SkillName.Anatomy, 110.0, 120.0);
SetSkill(SkillName.Magery, 110.0, 120.0);
SetSkill(SkillName.EvalInt, 110.0, 120.0);
SetSkill(SkillName.Meditation, 110.0, 120.0);
AddItem(Immovable(Rehued(new WizardsHat(), 1325)));
AddItem(Immovable(Rehued(new Sandals(), 1325)));
AddItem(Immovable(Rehued(new Robe(), 1310)));
AddItem(Immovable(Rehued(new LeatherGloves(), 1325)));
AddItem(Newbied(Rehued(new GnarledStaff(), 1310)));
PackItem(new Bandage(Utility.RandomMinMax(30, 40)));
PackStrongPotions(6, 12);
}
public FactionWizard(Serial serial) : base(serial)
{
}
public override GuardAI GuardAI => GuardAI.Magic | GuardAI.Smart | GuardAI.Bless | GuardAI.Curse;
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,121 @@
using System.Collections.Generic;
using Server.Mobiles;
namespace Server.Factions
{
public abstract class BaseFactionVendor : BaseVendor
{
private Faction m_Faction;
private Town m_Town;
public BaseFactionVendor(Town town, Faction faction, string title) : base(title)
{
Frozen = true;
CantWalk = true;
Female = false;
BodyValue = 400;
Name = NameList.RandomName("male");
RangeHome = 0;
m_Town = town;
m_Faction = faction;
Register();
}
public BaseFactionVendor(Serial serial) : base(serial)
{
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
public Town Town
{
get => m_Town;
set
{
Unregister();
m_Town = value;
Register();
}
}
[CommandProperty(AccessLevel.Counselor, AccessLevel.Administrator)]
public Faction Faction
{
get => m_Faction;
set
{
Unregister();
m_Faction = value;
Register();
}
}
protected override List<SBInfo> SBInfos{ get; } = new List<SBInfo>();
public void Register()
{
if (m_Town != null && m_Faction != null)
m_Town.RegisterVendor(this);
}
public override bool OnMoveOver(Mobile m)
{
if (Core.ML)
return true;
return base.OnMoveOver(m);
}
public void Unregister()
{
m_Town?.UnregisterVendor(this);
}
public override void InitSBInfo()
{
}
public override void OnAfterDelete()
{
base.OnAfterDelete();
Unregister();
}
public override bool CheckVendorAccess(Mobile from)
{
return true;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
Town.WriteReference(writer, m_Town);
Faction.WriteReference(writer, m_Faction);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_Town = Town.ReadReference(reader);
m_Faction = Faction.ReadReference(reader);
Register();
break;
}
}
Frozen = true;
}
}
}

View file

@ -0,0 +1,66 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Factions
{
public class FactionBoardVendor : BaseFactionVendor
{
public FactionBoardVendor(Town town, Faction faction) :
base(town, faction, "the LumberMan") // NOTE: title inconsistant, as OSI
{
SetSkill(SkillName.Carpentry, 85.0, 100.0);
SetSkill(SkillName.Lumberjacking, 60.0, 83.0);
}
public FactionBoardVendor(Serial serial) : base(serial)
{
}
public override void InitSBInfo()
{
SBInfos.Add(new SBFactionBoard());
}
public override void InitOutfit()
{
base.InitOutfit();
AddItem(new HalfApron());
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SBFactionBoard : SBInfo
{
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
public class InternalBuyInfo : List<GenericBuyInfo>
{
public InternalBuyInfo()
{
for (int i = 0; i < 5; ++i)
Add(new GenericBuyInfo(typeof(Board), 3, 20, 0x1BD7, 0));
}
}
public class InternalSellInfo : GenericSellInfo
{
}
}
}

View file

@ -0,0 +1,67 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Factions
{
public class FactionBottleVendor : BaseFactionVendor
{
public FactionBottleVendor(Town town, Faction faction) : base(town, faction, "the Bottle Seller")
{
SetSkill(SkillName.Alchemy, 85.0, 100.0);
SetSkill(SkillName.TasteID, 65.0, 88.0);
}
public FactionBottleVendor(Serial serial) : base(serial)
{
}
public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals;
public override void InitSBInfo()
{
SBInfos.Add(new SBFactionBottle());
}
public override void InitOutfit()
{
base.InitOutfit();
AddItem(new Robe(Utility.RandomPinkHue()));
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SBFactionBottle : SBInfo
{
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
public class InternalBuyInfo : List<GenericBuyInfo>
{
public InternalBuyInfo()
{
for (int i = 0; i < 5; ++i)
Add(new GenericBuyInfo(typeof(Bottle), 5, 20, 0xF0E, 0));
}
}
public class InternalSellInfo : GenericSellInfo
{
}
}
}

View file

@ -0,0 +1,78 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
using Server.Network;
namespace Server.Factions
{
public class FactionHorseVendor : BaseFactionVendor
{
public FactionHorseVendor(Town town, Faction faction) : base(town, faction, "the Horse Breeder")
{
SetSkill(SkillName.AnimalLore, 64.0, 100.0);
SetSkill(SkillName.AnimalTaming, 90.0, 100.0);
SetSkill(SkillName.Veterinary, 65.0, 88.0);
}
public FactionHorseVendor(Serial serial) : base(serial)
{
}
public override VendorShoeType ShoeType => Female ? VendorShoeType.ThighBoots : VendorShoeType.Boots;
public override void InitSBInfo()
{
}
public override int GetShoeHue()
{
return 0;
}
public override void InitOutfit()
{
base.InitOutfit();
AddItem(Utility.RandomBool() ? new QuarterStaff() : (Item)new ShepherdsCrook());
}
public override void VendorBuy(Mobile from)
{
if (Faction == null || Faction.Find(from, true) != Faction)
PrivateOverheadMessage(MessageType.Regular, 0x3B2, 1042201,
from.NetState); // You are not in my faction, I cannot sell you a horse!
else if (FactionGump.Exists(from))
from.SendLocalizedMessage(1042160); // You already have a faction menu open.
else if (from is PlayerMobile mobile)
mobile.SendGump(new HorseBreederGump(mobile, Faction));
}
public override void VendorSell(Mobile from)
{
}
public override bool OnBuyItems(Mobile buyer, List<BuyItemResponse> list)
{
return false;
}
public override bool OnSellItems(Mobile seller, List<SellItemResponse> list)
{
return false;
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
}

View file

@ -0,0 +1,68 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Factions
{
public class FactionOreVendor : BaseFactionVendor
{
public FactionOreVendor(Town town, Faction faction) : base(town, faction, "the Ore Man")
{
// NOTE: Skills verified
SetSkill(SkillName.Carpentry, 85.0, 100.0);
SetSkill(SkillName.Lumberjacking, 60.0, 83.0);
}
public FactionOreVendor(Serial serial) : base(serial)
{
}
public override void InitSBInfo()
{
SBInfos.Add(new SBFactionOre());
}
public override void InitOutfit()
{
base.InitOutfit();
AddItem(new HalfApron());
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SBFactionOre : SBInfo
{
private static readonly object[] m_FixedSizeArgs = { true };
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
public class InternalBuyInfo : List<GenericBuyInfo>
{
public InternalBuyInfo()
{
for (int i = 0; i < 5; ++i)
Add(new GenericBuyInfo(typeof(IronOre), 16, 20, 0x19B8, 0, m_FixedSizeArgs));
}
}
public class InternalSellInfo : GenericSellInfo
{
}
}
}

View file

@ -0,0 +1,81 @@
using System.Collections.Generic;
using Server.Items;
using Server.Mobiles;
namespace Server.Factions
{
public class FactionReagentVendor : BaseFactionVendor
{
public FactionReagentVendor(Town town, Faction faction) : base(town, faction, "the Reagent Man")
{
SetSkill(SkillName.EvalInt, 65.0, 88.0);
SetSkill(SkillName.Inscribe, 60.0, 83.0);
SetSkill(SkillName.Magery, 64.0, 100.0);
SetSkill(SkillName.Meditation, 60.0, 83.0);
SetSkill(SkillName.MagicResist, 65.0, 88.0);
SetSkill(SkillName.Wrestling, 36.0, 68.0);
}
public FactionReagentVendor(Serial serial) : base(serial)
{
}
public override VendorShoeType ShoeType => Utility.RandomBool() ? VendorShoeType.Shoes : VendorShoeType.Sandals;
public override void InitSBInfo()
{
SBInfos.Add(new SBFactionReagent());
}
public override void InitOutfit()
{
base.InitOutfit();
AddItem(new Robe(Utility.RandomBlueHue()));
AddItem(new GnarledStaff());
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
}
}
public class SBFactionReagent : SBInfo
{
public override IShopSellInfo SellInfo{ get; } = new InternalSellInfo();
public override List<GenericBuyInfo> BuyInfo{ get; } = new InternalBuyInfo();
public class InternalBuyInfo : List<GenericBuyInfo>
{
public InternalBuyInfo()
{
for (int i = 0; i < 2; ++i)
{
Add(new GenericBuyInfo(typeof(BlackPearl), 5, 20, 0xF7A, 0));
Add(new GenericBuyInfo(typeof(Bloodmoss), 5, 20, 0xF7B, 0));
Add(new GenericBuyInfo(typeof(MandrakeRoot), 3, 20, 0xF86, 0));
Add(new GenericBuyInfo(typeof(Garlic), 3, 20, 0xF84, 0));
Add(new GenericBuyInfo(typeof(Ginseng), 3, 20, 0xF85, 0));
Add(new GenericBuyInfo(typeof(Nightshade), 3, 20, 0xF88, 0));
Add(new GenericBuyInfo(typeof(SpidersSilk), 3, 20, 0xF8D, 0));
Add(new GenericBuyInfo(typeof(SulfurousAsh), 3, 20, 0xF8C, 0));
}
}
}
public class InternalSellInfo : GenericSellInfo
{
}
}
}