#W# Source and Scripts added. Added Scripts/Settings.cs to expose some basic tweak able settings.

This commit is contained in:
WarrentyExpired 2026-08-06 11:06:05 -04:00
parent b51c58f514
commit 3045c83799
3512 changed files with 627673 additions and 0 deletions

View file

@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Targeting;
namespace Server.Targets
{
public class AIControlMobileTarget : Target
{
private List<BaseAI> m_List;
private OrderType m_Order;
public OrderType Order {
get {
return m_Order;
}
}
public AIControlMobileTarget( BaseAI ai, OrderType order ) : base( -1, false, ( order == OrderType.Attack ? TargetFlags.Harmful : TargetFlags.None ) )
{
m_List = new List<BaseAI>();
m_Order = order;
AddAI( ai );
}
public void AddAI( BaseAI ai )
{
if ( !m_List.Contains( ai ) )
m_List.Add( ai );
}
protected override void OnTarget( Mobile from, object o )
{
if ( o is Mobile ) {
Mobile m = (Mobile)o;
for ( int i = 0; i < m_List.Count; ++i )
m_List[i].EndPickTarget( from, m, m_Order );
}
}
}
}

View file

@ -0,0 +1,157 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
// Ideas
// When you run on animals the panic
// When if ( distance < 8 && Utility.RandomDouble() * Math.Sqrt( (8 - distance) / 6 ) >= incoming.Skills[SkillName.AnimalTaming].Value )
// More your close, the more it can panic
/*
* AnimalHunterAI, AnimalHidingAI, AnimalDomesticAI...
*
*/
namespace Server.Mobiles
{
public class AnimalAI : BaseAI
{
public AnimalAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
// Old:
#if false
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
{
m_Mobile.DebugSay( "There is something near, I go away" );
Action = ActionType.Backoff;
}
else if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null )
{
m_Mobile.DebugSay( "I am hurt or being attacked, I flee" );
Action = ActionType.Flee;
}
else
{
base.DoActionWander();
}
return true;
#endif
// New, only flee @ 10%
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee ) // Less than 10% health
{
m_Mobile.DebugSay( "I am low on health!" );
Action = ActionType.Flee;
}
else if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone.." );
Action = ActionType.Wander;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
else
{
if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I cannot find {0}", combatant.Name );
Action = ActionType.Wander;
return true;
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
}
if ( !m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee )
{
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( hitPercent < 0.1 )
{
m_Mobile.DebugSay( "I am low on health!" );
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionBackoff()
{
double hitPercent = (double)m_Mobile.Hits / m_Mobile.HitsMax;
if ( !m_Mobile.Summoned && !m_Mobile.Controlled && hitPercent < 0.1 && m_Mobile.CanFlee ) // Less than 10% health
{
Action = ActionType.Flee;
}
else
{
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false , true))
{
if ( WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2) )
{
m_Mobile.DebugSay( "Well, here I am safe" );
Action = ActionType.Wander;
}
}
else
{
m_Mobile.DebugSay( "I have lost my focus, lets relax" );
Action = ActionType.Wander;
}
}
return true;
}
public override bool DoActionFlee()
{
AcquireFocusMob(m_Mobile.RangePerception * 2, m_Mobile.FightMode, true, false, true);
if ( m_Mobile.FocusMob == null )
m_Mobile.FocusMob = m_Mobile.Combatant;
return base.DoActionFlee();
}
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Mobiles;
using Server.Items;
namespace Server.Mobiles
{
public class ArcherAI : BaseAI
{
public ArcherAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true))
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0} and I will attack", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
return base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
if ( m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted || !m_Mobile.Combatant.Alive || m_Mobile.Combatant.IsDeadBondedPet )
{
m_Mobile.DebugSay("My combatant is deleted");
Action = ActionType.Guard;
return true;
}
if (Core.TickCount - m_Mobile.LastMoveTime > 1000)
{
if (WalkMobileRange(m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.Weapon.MaxRange))
{
// Be sure to face the combatant
m_Mobile.Direction = m_Mobile.GetDirectionTo(m_Mobile.Combatant.Location);
}
else
{
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am still not in range of {0}", m_Mobile.Combatant.Name);
if ( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have lost {0}", m_Mobile.Combatant.Name);
m_Mobile.Combatant = null;
Action = ActionType.Guard;
return true;
}
}
}
}
// When we have no ammo, we flee
Container pack = m_Mobile.Backpack;
if ( pack == null || pack.FindItemByType( typeof( Arrow ) ) == null )
{
Action = ActionType.Flee;
return true;
}
// At 20% we should check if we must leave
if ( m_Mobile.Hits < m_Mobile.HitsMax*20/100 && m_Mobile.CanFlee )
{
bool bFlee = false;
// if my current hits are more than my opponent, i don't care
if ( m_Mobile.Combatant != null && m_Mobile.Hits < m_Mobile.Combatant.Hits)
{
int iDiff = m_Mobile.Combatant.Hits - m_Mobile.Hits;
if ( Utility.Random(0, 100) > 10 + iDiff) // 10% to flee + the diff of hits
{
bFlee = true;
}
}
else if ( m_Mobile.Combatant != null && m_Mobile.Hits >= m_Mobile.Combatant.Hits)
{
if ( Utility.Random(0, 100) > 10 ) // 10% to flee
{
bFlee = true;
}
}
if (bFlee)
{
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
}
}

2828
Scripts/Mobiles/AI/BaseAI.cs Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,87 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
namespace Server.Mobiles
{
public class BerserkAI : BaseAI
{
public BerserkAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have No Combatant" );
if( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Closest, false, true, true) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected " + m_Mobile.FocusMob.Name + " and I will attack" );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
if( m_Mobile.Combatant == null || m_Mobile.Combatant.Deleted )
{
m_Mobile.DebugSay("My combatant is deleted");
Action = ActionType.Guard;
return true;
}
if( WalkMobileRange( m_Mobile.Combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
// Be sure to face the combatant
m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant.Location );
}
else
{
if( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay("I am still not in range of " + m_Mobile.Combatant.Name);
if( (int) m_Mobile.GetDistanceToSqrt( m_Mobile.Combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have lost " + m_Mobile.Combatant.Name );
Action = ActionType.Guard;
return true;
}
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, true, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
}
}

View file

@ -0,0 +1,176 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Spells;
using Server.Spells.First;
using Server.Spells.Second;
using Server.Spells.Fourth;
namespace Server.Mobiles
{
public class HealerAI : BaseAI
{
private static NeedDelegate m_Cure = new NeedDelegate( NeedCure );
private static NeedDelegate m_GHeal = new NeedDelegate( NeedGHeal );
private static NeedDelegate m_LHeal = new NeedDelegate( NeedLHeal );
private static NeedDelegate[] m_ACure = new NeedDelegate[] { m_Cure };
private static NeedDelegate[] m_AGHeal = new NeedDelegate[] { m_GHeal };
private static NeedDelegate[] m_ALHeal = new NeedDelegate[] { m_LHeal };
private static NeedDelegate[] m_All = new NeedDelegate[] { m_Cure, m_GHeal, m_LHeal };
public HealerAI( BaseCreature m ) : base( m )
{
}
public override bool Think()
{
if ( m_Mobile.Deleted )
return false;
Target targ = m_Mobile.Target;
if ( targ != null )
{
if ( targ is CureSpell.InternalTarget )
{
ProcessTarget( targ, m_ACure );
}
else if ( targ is GreaterHealSpell.InternalTarget )
{
ProcessTarget( targ, m_AGHeal );
}
else if ( targ is HealSpell.InternalTarget )
{
ProcessTarget( targ, m_ALHeal );
}
else
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
}
else
{
Mobile toHelp = Find( m_All );
if ( toHelp != null )
{
if ( NeedCure( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a cure", toHelp.Name );
if ( !(new CureSpell( m_Mobile, null )).Cast() )
new CureSpell( m_Mobile, null ).Cast();
}
else if ( NeedGHeal( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a greater heal", toHelp.Name );
if ( !(new GreaterHealSpell( m_Mobile, null )).Cast() )
new HealSpell( m_Mobile, null ).Cast();
}
else if ( NeedLHeal( toHelp ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} needs a lesser heal", toHelp.Name );
new HealSpell( m_Mobile, null ).Cast();
}
}
else
{
if ( AcquireFocusMob( m_Mobile.RangePerception, FightMode.Weakest, false, true, false ) )
{
WalkMobileRange( m_Mobile.FocusMob, 1, false, 4, 7 );
}
else
{
WalkRandomInHome( 3, 2, 1 );
}
}
}
return true;
}
private delegate bool NeedDelegate( Mobile m );
private void ProcessTarget( Target targ, NeedDelegate[] func )
{
Mobile toHelp = Find( func );
if ( toHelp != null )
{
if ( targ.Range != -1 && !m_Mobile.InRange( toHelp, targ.Range ) )
{
DoMove( m_Mobile.GetDirectionTo( toHelp ) | Direction.Running );
}
else
{
targ.Invoke( m_Mobile, toHelp );
}
}
else
{
targ.Cancel( m_Mobile, TargetCancelType.Canceled );
}
}
private Mobile Find( params NeedDelegate[] funcs )
{
if ( m_Mobile.Deleted )
return null;
Map map = m_Mobile.Map;
if ( map != null )
{
double prio = 0.0;
Mobile found = null;
foreach ( Mobile m in m_Mobile.GetMobilesInRange( m_Mobile.RangePerception ) )
{
if ( !m_Mobile.CanSee( m ) || !(m is BaseCreature) || ((BaseCreature)m).Team != m_Mobile.Team )
continue;
for ( int i = 0; i < funcs.Length; ++i )
{
if ( funcs[i]( m ) )
{
double val = -m_Mobile.GetDistanceToSqrt( m );
if ( found == null || val > prio )
{
prio = val;
found = m;
}
break;
}
}
}
return found;
}
return null;
}
private static bool NeedCure( Mobile m )
{
return m.Poisoned;
}
private static bool NeedGHeal( Mobile m )
{
return m.Hits < m.HitsMax - 40;
}
private static bool NeedLHeal( Mobile m )
{
return m.Hits < m.HitsMax - 10;
}
}
}

1103
Scripts/Mobiles/AI/MageAI.cs Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,183 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class MeleeAI : BaseAI
{
public MeleeAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map || !combatant.Alive || combatant.IsDeadBondedPet )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Guard;
return true;
}
if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception ) )
{
// They are somewhat far away, can we find something else?
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.Combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
else if ( !m_Mobile.InRange( combatant, m_Mobile.RangePerception * 3 ) )
{
m_Mobile.Combatant = null;
}
combatant = m_Mobile.Combatant;
if ( combatant == null )
{
m_Mobile.DebugSay( "My combatant has fled, so I am on guard" );
Action = ActionType.Guard;
return true;
}
}
/*if ( !m_Mobile.InLOS( combatant ) )
{
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.Combatant = combatant = m_Mobile.FocusMob;
m_Mobile.FocusMob = null;
}
}*/
if ( MoveTo( combatant, true, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
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;
return true;
}
else if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I cannot find {0}, so my guard is up", combatant.Name );
Action = ActionType.Guard;
return true;
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
if ( !m_Mobile.Controlled && !m_Mobile.Summoned && m_Mobile.CanFlee )
{
if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 )
{
// We are low on health, should we flee?
bool flee = false;
if ( m_Mobile.Hits < combatant.Hits )
{
// We are more hurt than them
int diff = combatant.Hits - m_Mobile.Hits;
flee = ( Utility.Random( 0, 100 ) < (10 + diff) ); // (10 + diff)% chance to flee
}
else
{
flee = Utility.Random( 0, 100 ) < 10; // 10% chance to flee
}
if ( flee )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
if ( m_Mobile.Hits > m_Mobile.HitsMax/2 )
{
m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" );
Action = ActionType.Combat;
}
else
{
m_Mobile.FocusMob = m_Mobile.Combatant;
base.DoActionFlee();
}
return true;
}
}
}

View file

@ -0,0 +1,142 @@
using System;
using Server;
using Server.Mobiles;
namespace Server
{
public class OppositionGroup
{
private Type[][] m_Types;
public OppositionGroup( Type[][] types )
{
m_Types = types;
}
public bool IsEnemy( object from, object target )
{
int fromGroup = IndexOf( from );
int targGroup = IndexOf( target );
return ( fromGroup != -1 && targGroup != -1 && fromGroup != targGroup );
}
public int IndexOf( object obj )
{
if ( obj == null )
return -1;
Type type = obj.GetType();
for ( int i = 0; i < m_Types.Length; ++i )
{
Type[] group = m_Types[i];
bool contains = false;
for ( int j = 0; !contains && j < group.Length; ++j )
contains = group[j].IsAssignableFrom( type );
if ( contains )
return i;
}
return -1;
}
private static OppositionGroup m_TerathansAndOphidians = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( TerathanAvenger ),
typeof( TerathanDrone ),
typeof( TerathanMatriarch ),
typeof( TerathanWarrior )
},
new Type[]
{
typeof( OphidianArchmage ),
typeof( OphidianKnight ),
typeof( OphidianMage ),
typeof( OphidianMatriarch ),
typeof( OphidianWarrior )
}
} );
public static OppositionGroup TerathansAndOphidians
{
get{ return m_TerathansAndOphidians; }
}
private static OppositionGroup m_SavagesAndOrcs = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( Orc ),
typeof( OrcBomber ),
typeof( OrcBrute ),
typeof( OrcCaptain ),
typeof( OrcishLord ),
typeof( OrcishMage ),
typeof( SpawnedOrcishLord )
},
new Type[]
{
typeof( Savage ),
typeof( SavageRider ),
typeof( SavageRidgeback ),
typeof( SavageShaman )
}
} );
public static OppositionGroup SavagesAndOrcs
{
get{ return m_SavagesAndOrcs; }
}
private static OppositionGroup m_FeyAndUndead = new OppositionGroup( new Type[][]
{
new Type[]
{
typeof( Centaur ),
typeof( EtherealWarrior ),
typeof( Kirin ),
typeof( LordOaks ),
typeof( Pixie ),
typeof( Silvani ),
typeof( Unicorn ),
typeof( Wisp ),
typeof( Treefellow ),
typeof( MLDryad ),
typeof( Satyr )
},
new Type[]
{
typeof( AncientLich ),
typeof( Bogle ),
typeof( LichLord ),
typeof( Shade ),
typeof( Spectre ),
typeof( Wraith ),
typeof( BoneKnight ),
typeof( Ghoul ),
typeof( Mummy ),
typeof( SkeletalKnight ),
typeof( Skeleton ),
typeof( Zombie ),
typeof( ShadowKnight ),
typeof( DarknightCreeper ),
typeof( RevenantLion ),
typeof( LadyOfTheSnow ),
typeof( RottingCorpse ),
typeof( SkeletalDragon ),
typeof( Lich )
}
} );
public static OppositionGroup FeyAndUndead
{
get{ return m_FeyAndUndead; }
}
}
}

View file

@ -0,0 +1,100 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
/*
* PredatorAI, its an animal that can attack
* Dont flee but dont attack if not hurt or attacked
*
*/
namespace Server.Mobiles
{
public class PredatorAI : BaseAI
{
public PredatorAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
if ( m_Mobile.Combatant != null )
{
m_Mobile.DebugSay( "I am hurt or being attacked, I kill him" );
Action = ActionType.Combat;
}
else if (AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, true, false, true))
{
m_Mobile.DebugSay( "There is something near, I go away" );
Action = ActionType.Backoff;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Wander;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
}
else
{
if ( m_Mobile.GetDistanceToSqrt( combatant ) > m_Mobile.RangePerception + 1 )
{
m_Mobile.DebugSay( "I cannot find {0}", combatant.Name );
Action = ActionType.Wander;
return true;
}
else
{
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
}
return true;
}
public override bool DoActionBackoff()
{
if ( m_Mobile.IsHurt() || m_Mobile.Combatant != null )
{
Action = ActionType.Combat;
}
else
{
if (AcquireFocusMob(m_Mobile.RangePerception * 2, FightMode.Closest, true, false , true))
{
if ( WalkMobileRange(m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception, m_Mobile.RangePerception * 2) )
{
m_Mobile.DebugSay( "Well, here I am safe" );
Action = ActionType.Wander;
}
}
else
{
m_Mobile.DebugSay( "I have lost my focus, lets relax" );
Action = ActionType.Wander;
}
}
return true;
}
}
}

View file

@ -0,0 +1,228 @@
using System;
using System.Collections.Generic;
using Server;
using Server.Mobiles;
using Server.Factions;
namespace Server
{
public class SpeedInfo
{
// Should we use the new method of speeds?
private static bool Enabled = true;
private double m_ActiveSpeed;
private double m_PassiveSpeed;
private Type[] m_Types;
public double ActiveSpeed
{
get{ return m_ActiveSpeed; }
set{ m_ActiveSpeed = value; }
}
public double PassiveSpeed
{
get{ return m_PassiveSpeed; }
set{ m_PassiveSpeed = value; }
}
public Type[] Types
{
get{ return m_Types; }
set{ m_Types = value; }
}
public SpeedInfo( double activeSpeed, double passiveSpeed, Type[] types )
{
m_ActiveSpeed = activeSpeed;
m_PassiveSpeed = passiveSpeed;
m_Types = types;
}
public static bool Contains( object obj )
{
if ( !Enabled )
return false;
if ( m_Table == null )
LoadTable();
SpeedInfo sp = null;
m_Table.TryGetValue(obj.GetType(), out sp);
return ( sp != null );
}
public static bool GetSpeeds( object obj, ref double activeSpeed, ref double passiveSpeed )
{
if ( !Enabled )
return false;
if ( m_Table == null )
LoadTable();
SpeedInfo sp = null;
m_Table.TryGetValue(obj.GetType(), out sp);
if ( sp == null )
return false;
activeSpeed = sp.ActiveSpeed;
passiveSpeed = sp.PassiveSpeed;
return true;
}
private static void LoadTable()
{
m_Table = new Dictionary<Type, SpeedInfo>();
for ( int i = 0; i < m_Speeds.Length; ++i )
{
SpeedInfo info = m_Speeds[i];
Type[] types = info.Types;
for ( int j = 0; j < types.Length; ++j )
m_Table[types[j]] = info;
}
}
private static Dictionary<Type, SpeedInfo> m_Table;
private static SpeedInfo[] m_Speeds = new SpeedInfo[]
{
/* Slow */
new SpeedInfo( 0.3, 0.6, new Type[]
{
typeof( AntLion ), typeof( ArcticOgreLord ), typeof( BogThing ),
typeof( Bogle ), typeof( BoneKnight ), typeof( EarthElemental ),
typeof( Ettin ), typeof( FrostOoze ), typeof( FrostTroll ),
typeof( GazerLarva ), typeof( Ghoul ), typeof( Golem ),
typeof( HeadlessOne ), typeof( Jwilson ), typeof( Mummy ),
typeof( Ogre ), typeof( OgreLord ), typeof( PlagueBeast ),
typeof( Quagmire ), typeof( Rat ), typeof( RottingCorpse ),
typeof( Sewerrat ), typeof( Skeleton ), typeof( Slime ),
typeof( Zombie ), typeof( Walrus ), typeof( RestlessSoul ),
typeof( CrystalElemental ), typeof( DarknightCreeper ), typeof( MoundOfMaggots ),
typeof( Juggernaut ), typeof( Yamandon ), typeof( Serado )
} ),
/* Fast */
new SpeedInfo( 0.2, 0.4, new Type[]
{
typeof( LordOaks ), typeof( Silvani ), typeof( AirElemental ),
typeof( AncientWyrm ), typeof( Balron ), typeof( BladeSpirits ),
typeof( DreadSpider ), typeof( Efreet ), typeof( EtherealWarrior ),
typeof( Lich ), typeof( Nightmare ), typeof( OphidianArchmage ),
typeof( OphidianMage ), typeof( OphidianWarrior ), typeof( OphidianMatriarch ),
typeof( OphidianKnight ), typeof( PoisonElemental ), typeof( Revenant ),
typeof( SandVortex ), typeof( SavageRider ), typeof( SavageShaman ),
typeof( SnowElemental ), typeof( WhiteWyrm ), typeof( Wisp ),
typeof( DemonKnight ), typeof( GiantBlackWidow ), typeof( SummonedAirElemental ),
typeof( LesserHiryu ), typeof( Hiryu ), typeof( LadyOfTheSnow ),
typeof( RaiJu ), typeof( Ronin ), typeof( RuneBeetle ),
typeof( Changeling ),
#region ML named mobs - before Paragon speedboost
typeof( LadyJennifyr ), typeof( LadyMarai ), typeof( MasterJonath ),
typeof( MasterMikael ), typeof( MasterTheophilus ), typeof( RedDeath ),
typeof( SirPatrick ), typeof( Miasma ), typeof( Rend ),
typeof( Grobu ), typeof( Gnaw ), typeof( Guile ),
typeof( Irk ), typeof( Spite ), typeof( LadyLissith ),
typeof( LadySabrix ), typeof( Malefic ), typeof( Silk ),
typeof( Virulent )
// TODO: Where to put Lurg, Putrefier, Swoop and Pyre? They seem slower.
#endregion
} ),
/* Very Fast */
new SpeedInfo( 0.175, 0.350, new Type[]
{
typeof( Barracoon ), typeof( Mephitis ), typeof( Neira ),
typeof( Rikktor ), typeof( Semidar ), typeof( EnergyVortex ),
typeof( EliteNinja ), typeof( Pixie ), typeof( SilverSerpent ),
typeof( VorpalBunny ), typeof( FleshRenderer ), typeof( KhaldunRevenant ),
typeof( FactionDragoon ), typeof( FactionKnight ), typeof( FactionPaladin ),
typeof( FactionHenchman ), typeof( FactionMercenary ), typeof( FactionNecromancer ),
typeof( FactionSorceress ), typeof( FactionWizard ), typeof( FactionBerserker ),
typeof( FactionPaladin ), typeof( Leviathan ), typeof( FireBeetle ),
typeof( FanDancer ), typeof( FactionDeathKnight )
} ),
/* Medium */
new SpeedInfo( 0.25, 0.5, new Type[]
{
typeof( AcidElemental ), typeof( AgapiteElemental ), typeof( Alligator ),
typeof( AncientLich ), typeof( Betrayer ), typeof( Bird ),
typeof( BlackBear ), typeof( BlackSolenInfiltratorQueen ), typeof( BlackSolenInfiltratorWarrior ),
typeof( BlackSolenQueen ), typeof( BlackSolenWarrior ), typeof( BlackSolenWorker ),
typeof( BloodElemental ), typeof( Boar ), typeof( Bogling ),
typeof( BoneMagi ), typeof( Brigand ), typeof( BronzeElemental ),
typeof( BrownBear ), typeof( Bull ), typeof( BullFrog ),
typeof( Cat ), typeof( Centaur ), typeof( ChaosDaemon ),
typeof( Chicken ), typeof( GolemController ), typeof( CopperElemental ),
typeof( CopperElemental ), typeof( Cougar ), typeof( Cow ),
typeof( Cyclops ), typeof( Daemon ), typeof( DeepSeaSerpent ),
typeof( DesertOstard ), typeof( DireWolf ), typeof( Dog ),
typeof( Dolphin ), typeof( Dragon ), typeof( Drake ),
typeof( DullCopperElemental ), typeof( Eagle ), typeof( ElderGazer ),
typeof( EvilMage ), typeof( EvilMageLord ), typeof( Executioner ),
typeof( Savage ), typeof( FireElemental ), typeof( FireGargoyle ),
typeof( FireSteed ), typeof( ForestOstard ), typeof( FrenziedOstard ),
typeof( FrostSpider ), typeof( Gargoyle ), typeof( Gazer ),
typeof( IceSerpent ), typeof( GiantRat ), typeof( GiantSerpent ),
typeof( GiantSpider ), typeof( GiantToad ), typeof( Goat ),
typeof( GoldenElemental ), typeof( Gorilla ), typeof( GreatHart ),
typeof( GreyWolf ), typeof( GrizzlyBear ), typeof( Guardian ),
typeof( Harpy ), typeof( Harrower ), typeof( HellHound ),
typeof( Hind ), typeof( HordeMinion ), typeof( Horse ),
typeof( Horse ), typeof( IceElemental ), typeof( IceFiend ),
typeof( IceSnake ), typeof( Imp ), typeof( JackRabbit ),
typeof( Kirin ), typeof( Kraken ), typeof( PredatorHellCat ),
typeof( LavaLizard ), typeof( LavaSerpent ), typeof( LavaSnake ),
typeof( Lizardman ), typeof( Llama ), typeof( Mongbat ),
typeof( StrongMongbat ), typeof( MountainGoat ), typeof( Orc ),
typeof( OrcBomber ), typeof( OrcBrute ), typeof( OrcCaptain ),
typeof( OrcishLord ), typeof( OrcishMage ), typeof( PackHorse ),
typeof( PackLlama ), typeof( Panther ), typeof( Pig ),
typeof( PlagueSpawn ), typeof( PolarBear ), typeof( Rabbit ),
typeof( Ratman ), typeof( RatmanArcher ), typeof( RatmanMage ),
typeof( RedSolenInfiltratorQueen ), typeof( RedSolenInfiltratorWarrior ), typeof( RedSolenQueen ),
typeof( RedSolenWarrior ), typeof( RedSolenWorker ), typeof( RidableLlama ),
typeof( Ridgeback ), typeof( Scorpion ), typeof( SeaSerpent ),
typeof( SerpentineDragon ), typeof( Shade ), typeof( ShadowIronElemental ),
typeof( ShadowWisp ), typeof( ShadowWyrm ), typeof( Sheep ),
typeof( SilverSteed ), typeof( SkeletalDragon ), typeof( SkeletalMage ),
typeof( SkeletalMount ), typeof( HellCat ), typeof( Snake ),
typeof( SnowLeopard ), typeof( SpectralArmour ), typeof( Spectre ),
typeof( StoneGargoyle ), typeof( StoneHarpy ), typeof( SwampDragon ),
typeof( ScaledSwampDragon ), typeof( SwampTentacle ), typeof( TerathanAvenger ),
typeof( TerathanDrone ), typeof( TerathanMatriarch ), typeof( TerathanWarrior ),
typeof( TimberWolf ), typeof( Titan ), typeof( Troll ),
typeof( Unicorn ), typeof( ValoriteElemental ), typeof( VeriteElemental ),
typeof( CoMWarHorse ), typeof( MinaxWarHorse ), typeof( SLWarHorse ),
typeof( TBWarHorse ), typeof( WaterElemental ), typeof( WhippingVine ),
typeof( WhiteWolf ), typeof( Wraith ), typeof( Wyvern ),
typeof( KhaldunZealot ), typeof( KhaldunSummoner ), typeof( SavageRidgeback ),
typeof( LichLord ), typeof( SkeletalKnight ), typeof( SummonedDaemon ),
typeof( SummonedEarthElemental ), typeof( SummonedWaterElemental ), typeof( SummonedFireElemental ),
typeof( MeerWarrior ), typeof( MeerEternal ), typeof( MeerMage ),
typeof( MeerCaptain ), typeof( JukaLord ), typeof( JukaMage ),
typeof( JukaWarrior ), typeof( AbysmalHorror ), typeof( BoneDemon ),
typeof( Devourer ), typeof( FleshGolem ), typeof( Gibberling ),
typeof( GoreFiend ), typeof( Impaler ), typeof( PatchworkSkeleton ),
typeof( Ravager ), typeof( ShadowKnight ), typeof( SkitteringHopper ),
typeof( Treefellow ), typeof( VampireBat ), typeof( WailingBanshee ),
typeof( WandererOfTheVoid ), typeof( Cursed ), typeof( GrimmochDrummel ),
typeof( LysanderGathenwale ), typeof( MorgBergen ), typeof( ShadowFiend ),
typeof( SpectralArmour ), typeof( TavaraSewel ), typeof( ArcaneDaemon ),
typeof( Doppleganger ), typeof( EnslavedGargoyle ), typeof( ExodusMinion ),
typeof( ExodusOverseer ), typeof( GargoyleDestroyer ), typeof( GargoyleEnforcer ),
typeof( Moloch ), typeof( BakeKitsune ), typeof( DeathwatchBeetleHatchling ),
typeof( Kappa ), typeof( KazeKemono ), typeof( DeathwatchBeetle ),
typeof( TsukiWolf ), typeof( YomotsuElder ), typeof( YomotsuPriest ),
typeof( YomotsuWarrior ), typeof( RevenantLion ), typeof( Oni ),
typeof( Gaman ), typeof( Crane ), typeof( Beetle )
} )
};
}
}

View file

@ -0,0 +1,194 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
using Server.Items;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class ThiefAI : BaseAI
{
public ThiefAI(BaseCreature m) : base (m)
{
}
private Item m_toDisarm;
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I have no combatant" );
if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionWander();
}
return true;
}
public override bool DoActionCombat()
{
Mobile combatant = m_Mobile.Combatant;
if ( combatant == null || combatant.Deleted || combatant.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My combatant is gone, so my guard is up" );
Action = ActionType.Guard;
return true;
}
if ( WalkMobileRange( combatant, 1, true, m_Mobile.RangeFight, m_Mobile.RangeFight ) )
{
m_Mobile.Direction = m_Mobile.GetDirectionTo( combatant );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.OneHanded );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.TwoHanded );
if ( m_toDisarm != null && m_toDisarm.IsChildOf( m_Mobile.Backpack ) )
{
m_toDisarm = combatant.FindItemOnLayer( Layer.OneHanded );
if ( m_toDisarm == null )
m_toDisarm = combatant.FindItemOnLayer( Layer.TwoHanded );
}
if ( !Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills[SkillName.Wrestling].Value >= 80.0 && m_Mobile.Skills[SkillName.ArmsLore].Value >= 80.0 && m_toDisarm != null )
EventSink.InvokeDisarmRequest( new DisarmRequestEventArgs( m_Mobile ) );
if (m_toDisarm != null && m_toDisarm.IsChildOf(combatant.Backpack) && Core.TickCount - m_Mobile.NextSkillTime >= 0 && (m_toDisarm.LootType != LootType.Blessed && m_toDisarm.LootType != LootType.Newbied))
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, m_toDisarm );
}
else if (m_toDisarm == null && Core.TickCount - m_Mobile.NextSkillTime >= 0)
{
Container cpack = combatant.Backpack;
if ( cpack != null )
{
Item steala = cpack.FindItemByType( typeof ( Bandage ) );
if ( steala != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, steala );
}
Item stealb = cpack.FindItemByType( typeof ( Nightshade ) );
if ( stealb != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, stealb );
}
Item stealc = cpack.FindItemByType( typeof ( BlackPearl ) );
if ( stealc != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, stealc );
}
Item steald = cpack.FindItemByType( typeof ( MandrakeRoot ) );
if ( steald != null )
{
m_Mobile.DebugSay( "Trying to steal from combatant." );
m_Mobile.UseSkill( SkillName.Stealing );
if ( m_Mobile.Target != null )
m_Mobile.Target.Invoke( m_Mobile, steald );
}
else if ( steala == null && stealb == null && stealc == null && steald == null )
{
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
}
}
else
{
m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name );
}
if ( m_Mobile.Hits < m_Mobile.HitsMax * 20/100 && m_Mobile.CanFlee )
{
// We are low on health, should we flee?
bool flee = false;
if ( m_Mobile.Hits < combatant.Hits )
{
// We are more hurt than them
int diff = combatant.Hits - m_Mobile.Hits;
flee = ( Utility.Random( 0, 100 ) > (10 + diff) ); // (10 + diff)% chance to flee
}
else
{
flee = Utility.Random( 0, 100 ) > 10; // 10% chance to flee
}
if ( flee )
{
m_Mobile.DebugSay( "I am going to flee from {0}", combatant.Name );
Action = ActionType.Flee;
}
}
return true;
}
public override bool DoActionGuard()
{
if ( AcquireFocusMob(m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) )
{
m_Mobile.DebugSay( "I have detected {0}, attacking", m_Mobile.FocusMob.Name );
m_Mobile.Combatant = m_Mobile.FocusMob;
Action = ActionType.Combat;
}
else
{
base.DoActionGuard();
}
return true;
}
public override bool DoActionFlee()
{
if ( m_Mobile.Hits > m_Mobile.HitsMax/2 )
{
m_Mobile.DebugSay( "I am stronger now, so I will continue fighting" );
Action = ActionType.Combat;
}
else
{
m_Mobile.FocusMob = m_Mobile.Combatant;
base.DoActionFlee();
}
return true;
}
}
}

View file

@ -0,0 +1,155 @@
using System;
using System.Collections;
using Server.Targeting;
using Server.Network;
//
// This is a first simple AI
//
//
namespace Server.Mobiles
{
public class VendorAI : BaseAI
{
public VendorAI(BaseCreature m) : base (m)
{
}
public override bool DoActionWander()
{
m_Mobile.DebugSay( "I'm fine" );
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name );
m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) );
Action = ActionType.Flee;
}
else
{
if ( m_Mobile.FocusMob != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} has talked to me", m_Mobile.FocusMob.Name );
Action = ActionType.Interact;
}
else
{
m_Mobile.Warmode = false;
base.DoActionWander();
}
}
return true;
}
public override bool DoActionInteract()
{
Mobile customer = m_Mobile.FocusMob;
if ( m_Mobile.Combatant != null )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is attacking me", m_Mobile.Combatant.Name );
m_Mobile.Say( Utility.RandomList( 1005305, 501603 ) );
Action = ActionType.Flee;
return true;
}
if ( customer == null || customer.Deleted || customer.Map != m_Mobile.Map )
{
m_Mobile.DebugSay( "My customer have disapeared" );
m_Mobile.FocusMob = null;
Action = ActionType.Wander;
}
else
{
if ( customer.InRange( m_Mobile, m_Mobile.RangeFight ) )
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "I am with {0}", customer.Name );
m_Mobile.Direction = m_Mobile.GetDirectionTo( customer );
}
else
{
if ( m_Mobile.Debug )
m_Mobile.DebugSay( "{0} is gone", customer.Name );
m_Mobile.FocusMob = null;
Action = ActionType.Wander;
}
}
return true;
}
public override bool DoActionGuard()
{
m_Mobile.FocusMob = m_Mobile.Combatant;
return base.DoActionGuard();
}
public override bool HandlesOnSpeech( Mobile from )
{
if ( from.InRange( m_Mobile, 4 ) )
return true;
return base.HandlesOnSpeech( from );
}
// Temporary
public override void OnSpeech( SpeechEventArgs e )
{
base.OnSpeech( e );
Mobile from = e.Mobile;
if ( m_Mobile is BaseVendor && from.InRange( m_Mobile, Core.AOS ? 1 : 4 ) && !e.Handled )
{
if ( e.HasKeyword( 0x14D ) ) // *vendor sell*
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorSell( from );
m_Mobile.FocusMob = from;
}
else if ( e.HasKeyword( 0x3C ) ) // *vendor buy*
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorBuy( from );
m_Mobile.FocusMob = from;
}
else if ( WasNamed( e.Speech ) )
{
if ( e.HasKeyword( 0x177 ) ) // *sell*
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorSell( from );
}
else if ( e.HasKeyword( 0x171 ) ) // *buy*
{
e.Handled = true;
((BaseVendor)m_Mobile).VendorBuy( from );
}
m_Mobile.FocusMob = from;
}
}
}
}
}