CODE |
using System; using System.Collections; using Server; using Server.Targeting; using Server.Spells; using Server.Spells.Ninjitsu; using Server.Network; using Server.Items; namespace Server.Mobiles { public class NinjaAI : BaseAI { public override bool Think() { try { if( m_Mobile.Deleted ) return false; if( CheckFlee() ) return true; switch( Action ) { case ActionType.Wander: m_Mobile.OnActionWander(); return DoActionWander(); case ActionType.Combat: m_Mobile.OnActionCombat(); return DoActionCombat(); case ActionType.Guard: m_Mobile.OnActionGuard(); return DoActionGuard(); case ActionType.Flee: m_Mobile.OnActionFlee(); return DoActionFlee(); case ActionType.Interact: m_Mobile.OnActionInteract(); return DoActionInteract(); case ActionType.Backoff: m_Mobile.OnActionBackoff(); return DoActionBackoff(); default: return false; } } catch ( Exception e ) { Console.WriteLine( "Catched Exception from EliteNinja when " + Action.ToString() ); Console.WriteLine( e.ToString() ); return false; } } private static double shadowJumpChance = 0.3; private static double mirrorChance = 0.4; private static double kiChance = 0.5; private static double focusChance = 0.5; private static double hideChance = 0.1; private static double turnOrHideChance = 0.05; private static double comboChance = 0.7; public NinjaAI( BaseCreature m ) : base( m ) { } private double MagnitudeBySkill() { return (m_Mobile.Skills[ SkillName.Ninjitsu ].Value/1000.0); } private bool CanUseAbility( double limit, int mana, double chance ) { if ( m_Mobile.Skills[ SkillName.Ninjitsu ].Value >= limit && m_Mobile.Mana >= mana ) { if ( (chance + MagnitudeBySkill()) >= Utility.RandomDouble() ) { return true; } } return false; } private static int[] m_Bodies = new int[] { 0x84, 0x7A, 0xF6, 0x19, 0xDC, 0xDA, 0x51, 0x15, 0xD9, 0xC9, 0xEE, 0xCD }; private static int[] m_Offsets = new int[] { 0, 0, -1,-1, 0,-1, 1,-1, -1, 0, 1, 0, -1,-1, 0, 1, 1, 1, }; private void ChangeForm( int body ) { m_Mobile.FixedEffect( 0x37C4, 10, 42, 4, 3 ); m_Mobile.BodyMod = body; } // Shadowjump private bool PerformShadowjump( Mobile toTarget ) { if ( m_Mobile.Skills[ SkillName.Ninjitsu ].Value < 50.0 ) { return false; } if ( toTarget != null ) { Map map = m_Mobile.Map; if ( map == null ) { return false; } int px, py, ioffset = 0; px = toTarget.X; py = toTarget.Y; if ( Action == ActionType.Flee ) { double outerradius = m_Mobile.Skills[ SkillName.Ninjitsu ].Value/10.0; double radiusoffset = 2.0; // random point for direction vector int rpx = Utility.Random( 40 ) - 20 + toTarget.X; int rpy = Utility.Random( 40 ) - 20 + toTarget.Y; // get vector int dx = rpx - toTarget.X; int dy = rpy - toTarget.Y; // get vector's length double l = Math.Sqrt( (double) (dx*dx + dy*dy) ); if ( l == 0 ) { return false; } // normalize vector double dpx = ((double) dx)/l; double dpy = ((double) dy)/l; // move px += (int) (dpx*(outerradius - radiusoffset) + Math.Sign( dpx )*(radiusoffset + 0.5)); py += (int) (dpy*(outerradius - radiusoffset) + Math.Sign( dpy )*(radiusoffset + 0.5)); } else { ioffset = 2; } for ( int i = ioffset; i < m_Offsets.Length; i += 2 ) { int x = m_Offsets[ i ], y = m_Offsets[ i + 1 ]; Point3D p = new Point3D( px + x, py + y, 0 ); LandTarget lt = new LandTarget( p, map ); if ( m_Mobile.InLOS( lt ) && map.CanSpawnMobile( px + x, py + y, lt.Z ) && !SpellHelper.CheckMulti( p, map ) ) { m_Mobile.Location = new Point3D( lt.X, lt.Y, lt.Z ); m_Mobile.ProcessDelta(); return true; } } } return false; } private void PerformHide() { Effects.SendLocationParticles( EffectItem.Create( m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration ), 0x3728, 10, 10, 2023 ); m_Mobile.PlaySound( 0x22F ); m_Mobile.Hidden = true; } private bool PerformFocusAttack() { if ( Utility.RandomBool() && CanUseAbility( 60.0, 20, focusChance ) ) { SpecialMove.SetCurrentMove( m_Mobile, new FocusAttack() ); return true; } return false; } private bool PerformMirror() { if ( CanUseAbility( 40.0, 10, mirrorChance ) && (m_Mobile.Followers < m_Mobile.FollowersMax) ) { new MirrorImage( m_Mobile, null ).Cast(); return true; } return false; } public override bool DoActionWander() { m_Mobile.DebugSay( "I am wandering around." ); if ( turnOrHideChance > Utility.RandomDouble() && !m_Mobile.Hidden ) { if ( Utility.RandomBool() ) { if ( m_Mobile.BodyMod == 0 ) { ChangeForm( m_Bodies[ Utility.Random( m_Bodies.Length ) ] ); } else { ChangeForm( 0 ); } } else { PerformHide(); m_Mobile.UseSkill( SkillName.Stealth ); } } if ( AcquireFocusMob( m_Mobile.RangePerception, m_Mobile.FightMode, false, false, true ) ) { m_Mobile.DebugSay( "I have detected {0}, going to try and sneak up on them!", m_Mobile.FocusMob.Name ); if( m_Mobile.Hidden ) // we are hidden { if( m_Mobile.GetDistanceToSqrt( m_Mobile.FocusMob ) <= 2 ) { if ( CanUseAbility( 85.0, 30, 1.0 ) ) { SpecialMove.SetCurrentMove( m_Mobile, new DeathStrike() ); m_Mobile.Combatant = m_Mobile.FocusMob; Action = ActionType.Combat; } else { m_Mobile.Combatant = m_Mobile.FocusMob; Action = ActionType.Combat; } } else if( m_Mobile.GetDistanceToSqrt( m_Mobile.FocusMob ) <= 10 ) { //MoveTo( m_Mobile.FocusMob, true, 1 ); WalkMobileRange(m_Mobile.FocusMob, 10, true, 2, 1); } } else { m_Mobile.Combatant = m_Mobile.FocusMob; Action = ActionType.Combat; } } else return base.DoActionWander(); return true; } public override bool DoActionCombat() { if ( m_Mobile.BodyMod != 0 ) { ChangeForm( 0 ); } 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.InLOS( combatant ) ) { if ( AquireFocusMob( 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 ) ) { 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 ) { m_Mobile.DebugSay( "I cannot find {0}, so my guard is up", combatant.Name ); Action = ActionType.Guard; return true; } else { m_Mobile.DebugSay( "I should be closer to {0}", combatant.Name ); } if ( !m_Mobile.Controlled && !m_Mobile.Summoned ) { 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; if ( CanUseAbility( 50.0, 15, shadowJumpChance ) ) { PerformHide(); m_Mobile.UseSkill( SkillName.Stealth ); if ( m_Mobile.AllowedStealthSteps != 0 ) { if ( PerformShadowjump( combatant ) ) { m_Mobile.Mana -= 15; } } } } } } if ( combatant.Hits < (Utility.Random( 10 ) + 10) ) { if ( CanUseAbility( 85.0, 30, 1.0 ) ) { SpecialMove.SetCurrentMove( m_Mobile, new DeathStrike() ); return true; } } double dstToTarget = m_Mobile.GetDistanceToSqrt( combatant ); if ( dstToTarget > 2.0 && dstToTarget <= (m_Mobile.Skills[ SkillName.Ninjitsu ].Value/10.0) && m_Mobile.Mana > 45 && comboChance > (Utility.RandomDouble() + MagnitudeBySkill()) ) { PerformHide(); m_Mobile.UseSkill( SkillName.Stealth ); if ( m_Mobile.AllowedStealthSteps != 0 ) { if ( CanUseAbility( 20.0, 30, 1.0 ) ) { SpecialMove.SetCurrentMove( m_Mobile, new Backstab() ); } if ( CanUseAbility( 30.0, 20, 1.0 ) ) { SpecialMove.SetCurrentMove( m_Mobile, new SurpriseAttack() ); } PerformFocusAttack(); if ( PerformShadowjump( combatant ) ) { m_Mobile.Mana -= 15; } } return true; } if ( PerformMirror() ) { return true; } if ( CanUseAbility( 80.0, 25, kiChance ) && m_Mobile.GetDistanceToSqrt( combatant ) < 2.0 ) { SpecialMove.SetCurrentMove( m_Mobile, new KiAttack() ); return true; } PerformFocusAttack(); 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; if ( m_Mobile.FocusMob == null || m_Mobile.FocusMob.Deleted || m_Mobile.FocusMob.Map != m_Mobile.Map ) { m_Mobile.DebugSay( "I have lost im" ); Action = ActionType.Guard; return true; } if ( !m_Mobile.Hidden ) { PerformMirror(); if ( hideChance > (Utility.RandomDouble() + MagnitudeBySkill()) ) { PerformHide(); m_Mobile.UseSkill( SkillName.Stealth ); } } if ( WalkMobileRange( m_Mobile.FocusMob, 1, false, m_Mobile.RangePerception*2, m_Mobile.RangePerception*3 ) ) { m_Mobile.DebugSay( "I Have fled" ); Action = ActionType.Guard; return true; } else { m_Mobile.DebugSay( "I am fleeing!" ); } } return true; } } } |
CODE |
public Clone( Mobile caster ) : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) { m_Caster = caster; Body = caster.Body; Hue = caster.Hue; Female = caster.Female; Name = caster.Name; NameHue = caster.NameHue; Title = caster.Title; Kills = caster.Kills; HairItemID = caster.HairItemID; HairHue = caster.HairHue; FacialHairItemID = caster.FacialHairItemID; FacialHairHue = caster.FacialHairHue; for ( int i = 0; i < caster.Skills.Length; ++i ) { Skills[i].Base = caster.Skills[i].Base; Skills[i].Cap = caster.Skills[i].Cap; } for( int i = 0; i < caster.Items.Count; i++ ) { AddItem( CloneItem( caster.Items[i] ) ); } Warmode = true; Summoned = true; SummonMaster = caster; ControlOrder = OrderType.Follow; ControlTarget = caster; TimeSpan duration = TimeSpan.FromSeconds( 30 + caster.Skills.Ninjitsu.Fixed / 40 ); new UnsummonTimer( caster, this, duration ).Start(); SummonEnd = DateTime.Now + duration; MirrorImage.AddClone( m_Caster ); } |
CODE |
using System; using System.Collections.Generic; using Server; using Server.Items; using Server.Mobiles; using Server.Spells; using Server.Spells.Necromancy; using Server.Spells.Ninjitsu; namespace Server.Spells.Ninjitsu { public class MirrorImage : NinjaSpell { private static Dictionary<Mobile, int> m_CloneCount = new Dictionary<Mobile, int>(); public static bool HasClone( Mobile m ) { return m_CloneCount.ContainsKey( m ); } public static void AddClone( Mobile m ) { if ( m == null ) return; if ( m_CloneCount.ContainsKey( m ) ) m_CloneCount[m]++; else m_CloneCount[m] = 1; } public static void RemoveClone( Mobile m ) { if ( m == null ) return; if ( m_CloneCount.ContainsKey( m ) ) { m_CloneCount[m]--; if ( m_CloneCount[m] == 0 ) m_CloneCount.Remove( m ); } } private static SpellInfo m_Info = new SpellInfo( "Mirror Image", null, -1, 9002 ); public override TimeSpan CastDelayBase { get { return TimeSpan.FromSeconds( 1.5 ); } } public override double RequiredSkill{ get{ return Core.ML ? 20.0 : 40.0; } } public override int RequiredMana{ get{ return 10; } } public override bool BlockedByAnimalForm{ get{ return false; } } public MirrorImage( Mobile caster, Item scroll ) : base( caster, scroll, m_Info ) { } public override bool CheckCast() { if ( Caster.Mounted ) { Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted. return false; } else if ( (Caster.Followers + 1) > Caster.FollowersMax ) { Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers. return false; } else if( TransformationSpellHelper.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) ) { Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. return false; } return base.CheckCast(); } public override bool CheckDisturb( DisturbType type, bool firstCircle, bool resistable ) { return false; } public override void OnBeginCast() { base.OnBeginCast(); Caster.SendLocalizedMessage( 1063134 ); // You begin to summon a mirror image of yourself. } public override void OnCast() { if ( Caster.Mounted ) { Caster.SendLocalizedMessage( 1063132 ); // You cannot use this ability while mounted. } else if ( (Caster.Followers + 1) > Caster.FollowersMax ) { Caster.SendLocalizedMessage( 1063133 ); // You cannot summon a mirror image because you have too many followers. } else if( TransformationSpellHelper.UnderTransformation( Caster, typeof( HorrificBeastSpell ) ) ) { Caster.SendLocalizedMessage( 1061091 ); // You cannot cast that spell in this form. } else if ( CheckSequence() ) { Caster.FixedParticles( 0x376A, 1, 14, 0x13B5, EffectLayer.Waist ); Caster.PlaySound( 0x511 ); new Clone( Caster ).MoveToWorld( Caster.Location, Caster.Map ); } FinishSequence(); } } } namespace Server.Mobiles { public class Clone : BaseCreature { private Mobile m_Caster; public Clone( Mobile caster ) : base( AIType.AI_Melee, FightMode.None, 10, 1, 0.2, 0.4 ) { m_Caster = caster; Body = caster.Body; Hue = caster.Hue; Female = caster.Female; Name = caster.Name; NameHue = caster.NameHue; Title = caster.Title; Kills = caster.Kills; HairItemID = caster.HairItemID; HairHue = caster.HairHue; FacialHairItemID = caster.FacialHairItemID; FacialHairHue = caster.FacialHairHue; for ( int i = 0; i < caster.Skills.Length; ++i ) { Skills[i].Base = caster.Skills[i].Base; Skills[i].Cap = caster.Skills[i].Cap; } for( int i = 0; i < caster.Items.Count; i++ ) { AddItem( CloneItem( caster.Items[i] ) ); } Warmode = true; Summoned = true; SummonMaster = caster; ControlOrder = OrderType.Follow; ControlTarget = caster; TimeSpan duration = TimeSpan.FromSeconds( 30 + caster.Skills.Ninjitsu.Fixed / 40 ); new UnsummonTimer( caster, this, duration ).Start(); SummonEnd = DateTime.Now + duration; MirrorImage.AddClone( m_Caster ); } protected override BaseAI ForcedAI { get { return new CloneAI( this ); } } public override bool IsHumanInTown() { return false; } private Item CloneItem( Item item ) { Item newItem = new Item( item.ItemID ); newItem.Hue = item.Hue; newItem.Layer = item.Layer; return newItem; } public override void OnDamage( int amount, Mobile from, bool willKill ) { Delete(); } public override bool DeleteCorpseOnDeath { get { return true; } } public override void OnDelete() { Effects.SendLocationParticles( EffectItem.Create( Location, Map, EffectItem.DefaultDuration ), 0x3728, 10, 15, 5042 ); base.OnDelete(); } public override void OnAfterDelete() { MirrorImage.RemoveClone( m_Caster ); base.OnAfterDelete(); } public override bool IsDispellable { get { return false; } } public override bool Commandable { get { return false; } } public Clone( Serial serial ) : base( serial ) { } public override void Serialize( GenericWriter writer ) { base.Serialize( writer ); writer.WriteEncodedInt( 0 ); // version writer.Write( m_Caster ); } public override void Deserialize( GenericReader reader ) { base.Deserialize( reader ); int version = reader.ReadEncodedInt(); m_Caster = reader.ReadMobile(); MirrorImage.AddClone( m_Caster ); } } } namespace Server.Mobiles { public class CloneAI : BaseAI { public CloneAI( Clone m ) : base ( m ) { m.CurrentSpeed = m.ActiveSpeed; } public override bool Think() { // Clones only follow their owners Mobile master = m_Mobile.SummonMaster; if ( master != null && master.Map == m_Mobile.Map && master.InRange( m_Mobile, m_Mobile.RangePerception ) ) { int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( master ); bool bRun = (iCurrDist > 5); WalkMobileRange( master, 2, bRun, 0, 1 ); } else WalkRandom( 2, 2, 1 ); return true; } public override bool CanDetectHidden { get { return false; } } } } |
CODE | ||
using System; using System.Collections; using System.Collections.Generic; using Server; using Server.Items; using Server.Targeting; using Server.Targets; using Server.Network; using Server.Regions; using Server.ContextMenus; using Server.Engines.Quests; using Server.Engines.Quests.Necro; using MoveImpl=Server.Movement.MovementImpl; using Server.Spells; using Server.Spells.Spellweaving; using Server.Spells.Ninjitsu; namespace Server.Mobiles { public enum AIType { AI_Use_Default, AI_Melee, AI_Animal, AI_Archer, AI_Healer, AI_Vendor, AI_Mage, AI_Berserk, AI_Predator, AI_Thief, //***Start AI Update Edits AI_Necro, AI_Necromage, AI_Ninja, AI_OrcScout //***Start AI Update Edits } public enum ActionType { Wander, Combat, Guard, Flee, Backoff, Interact } public abstract class BaseAI { public Timer m_Timer; protected ActionType m_Action; private DateTime m_NextStopGuard; public BaseCreature m_Mobile; public BaseAI( BaseCreature m ) { m_Mobile = m; m_Timer = new AITimer( this ); bool activate; if( !m.PlayerRangeSensitive ) activate = true; else if( World.Loading ) activate = false; else if( m.Map == null || m.Map == Map.Internal || !m.Map.GetSector( m ).Active ) activate = false; else activate = true; if( activate ) m_Timer.Start(); Action = ActionType.Wander; } public ActionType Action { get { return m_Action; } set { m_Action = value; OnActionChanged(); } } public virtual bool WasNamed( string speech ) { string name = m_Mobile.Name; return (name != null && Insensitive.StartsWith( speech, name )); } private class InternalEntry : ContextMenuEntry { private Mobile m_From; private BaseCreature m_Mobile; private BaseAI m_AI; private OrderType m_Order; public InternalEntry( Mobile from, int number, int range, BaseCreature mobile, BaseAI ai, OrderType order ) : base( number, range ) { m_From = from; m_Mobile = mobile; m_AI = ai; m_Order = order; if( mobile.IsDeadPet && (order == OrderType.Guard || order == OrderType.Attack || order == OrderType.Transfer || order == OrderType.Drop) ) Enabled = false; } public override void OnClick() { if( !m_Mobile.Deleted && m_Mobile.Controlled && m_From.CheckAlive() ) { if( m_Mobile.IsDeadPet && (m_Order == OrderType.Guard || m_Order == OrderType.Attack || m_Order == OrderType.Transfer || m_Order == OrderType.Drop) ) return; bool isOwner = (m_From == m_Mobile.ControlMaster); bool isFriend = (!isOwner && m_Mobile.IsPetFriend( m_From )); if( !isOwner && !isFriend ) return; else if( isFriend && m_Order != OrderType.Follow && m_Order != OrderType.Stay && m_Order != OrderType.Stop ) return; switch( m_Order ) { case OrderType.Follow: case OrderType.Attack: case OrderType.Transfer: case OrderType.Friend: case OrderType.Unfriend: { if( m_Order == OrderType.Transfer && m_From.HasTrade ) m_From.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending else if( m_Order == OrderType.Friend && m_From.HasTrade ) m_From.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending else m_AI.BeginPickTarget( m_From, m_Order ); break; } case OrderType.Release: { if( m_Mobile.Summoned ) goto default; else m_From.SendGump( new Gumps.ConfirmReleaseGump( m_From, m_Mobile ) ); break; } default: { if( m_Mobile.CheckControlChance( m_From ) ) m_Mobile.ControlOrder = m_Order; break; } } } } } public virtual void GetContextMenuEntries( Mobile from, List<ContextMenuEntry> list ) { if( from.Alive && m_Mobile.Controlled && from.InRange( m_Mobile, 14 ) ) { if( from == m_Mobile.ControlMaster ) { list.Add( new InternalEntry( from, 6107, 14, m_Mobile, this, OrderType.Guard ) ); // Command: Guard list.Add( new InternalEntry( from, 6108, 14, m_Mobile, this, OrderType.Follow ) ); // Command: Follow if( m_Mobile.CanDrop ) list.Add( new InternalEntry( from, 6109, 14, m_Mobile, this, OrderType.Drop ) ); // Command: Drop list.Add( new InternalEntry( from, 6111, 14, m_Mobile, this, OrderType.Attack ) ); // Command: Kill list.Add( new InternalEntry( from, 6112, 14, m_Mobile, this, OrderType.Stop ) ); // Command: Stop list.Add( new InternalEntry( from, 6114, 14, m_Mobile, this, OrderType.Stay ) ); // Command: Stay if( !m_Mobile.Summoned ) { list.Add( new InternalEntry( from, 6110, 14, m_Mobile, this, OrderType.Friend ) ); // Add Friend list.Add( new InternalEntry( from, 6099, 14, m_Mobile, this, OrderType.Unfriend ) ); // Remove Friend list.Add( new InternalEntry( from, 6113, 14, m_Mobile, this, OrderType.Transfer ) ); // Transfer } list.Add( new InternalEntry( from, 6118, 14, m_Mobile, this, OrderType.Release ) ); // Release } else if( m_Mobile.IsPetFriend( from ) ) { list.Add( new InternalEntry( from, 6108, 14, m_Mobile, this, OrderType.Follow ) ); // Command: Follow list.Add( new InternalEntry( from, 6112, 14, m_Mobile, this, OrderType.Stop ) ); // Command: Stop list.Add( new InternalEntry( from, 6114, 14, m_Mobile, this, OrderType.Stay ) ); // Command: Stay } } } public virtual void BeginPickTarget( Mobile from, OrderType order ) { if( m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange( m_Mobile, 14 ) || from.Map != m_Mobile.Map ) return; bool isOwner = (from == m_Mobile.ControlMaster); bool isFriend = (!isOwner && m_Mobile.IsPetFriend( from )); if( !isOwner && !isFriend ) return; else if( isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop ) return; if( from.Target == null ) { if( order == OrderType.Transfer ) from.SendLocalizedMessage( 502038 ); // Click on the person to transfer ownership to. else if( order == OrderType.Friend ) from.SendLocalizedMessage( 502020 ); // Click on the player whom you wish to make a co-owner. else if( order == OrderType.Unfriend ) from.SendLocalizedMessage( 1070948 ); // Click on the player whom you wish to remove as a co-owner. from.Target = new AIControlMobileTarget( this, order ); } else if( from.Target is AIControlMobileTarget ) { AIControlMobileTarget t = (AIControlMobileTarget)from.Target; if( t.Order == order ) t.AddAI( this ); } } public virtual void OnAggressiveAction( Mobile aggressor ) { Mobile currentCombat = m_Mobile.Combatant; if( currentCombat != null && !aggressor.Hidden && currentCombat != aggressor && m_Mobile.GetDistanceToSqrt( currentCombat ) > m_Mobile.GetDistanceToSqrt( aggressor ) ) m_Mobile.Combatant = aggressor; } public virtual void EndPickTarget( Mobile from, Mobile target, OrderType order ) { if( m_Mobile.Deleted || !m_Mobile.Controlled || !from.InRange( m_Mobile, 14 ) || from.Map != m_Mobile.Map || !from.CheckAlive() ) return; bool isOwner = (from == m_Mobile.ControlMaster); bool isFriend = (!isOwner && m_Mobile.IsPetFriend( from )); if( !isOwner && !isFriend ) return; else if( isFriend && order != OrderType.Follow && order != OrderType.Stay && order != OrderType.Stop ) return; if( order == OrderType.Attack ) { if( target is BaseCreature && ((BaseCreature)target).IsScaryToPets && m_Mobile.IsScaredOfScaryThings ) { m_Mobile.SayTo( from, "Your pet refuses to attack this creature!" ); return; } if( (SolenHelper.CheckRedFriendship( from ) && (target is RedSolenInfiltratorQueen || target is RedSolenInfiltratorWarrior || target is RedSolenQueen || target is RedSolenWarrior || target is RedSolenWorker)) || (SolenHelper.CheckBlackFriendship( from ) && (target is BlackSolenInfiltratorQueen || target is BlackSolenInfiltratorWarrior || target is BlackSolenQueen || target is BlackSolenWarrior || target is BlackSolenWorker)) ) { from.SendAsciiMessage( "You can not force your pet to attack a creature you are protected from." ); return; } if( target is Factions.BaseFactionGuard ) { m_Mobile.SayTo( from, "Your pet refuses to attack the guard." ); return; } } if( m_Mobile.CheckControlChance( from ) ) { m_Mobile.ControlTarget = target; m_Mobile.ControlOrder = order; } } public virtual bool HandlesOnSpeech( Mobile from ) { if( from.AccessLevel >= AccessLevel.GameMaster ) return true; if( from.Alive && m_Mobile.Controlled && m_Mobile.Commandable && (from == m_Mobile.ControlMaster || m_Mobile.IsPetFriend( from )) ) return true; return (from.Alive && from.InRange( m_Mobile.Location, 3 ) && m_Mobile.IsHumanInTown()); } private static SkillName[] m_KeywordTable = new SkillName[] { SkillName.Parry, SkillName.Healing, SkillName.Hiding, SkillName.Stealing, SkillName.Alchemy, SkillName.AnimalLore, SkillName.ItemID, SkillName.ArmsLore, SkillName.Begging, SkillName.Blacksmith, SkillName.Fletching, SkillName.Peacemaking, SkillName.Camping, SkillName.Carpentry, SkillName.Cartography, SkillName.Cooking, SkillName.DetectHidden, SkillName.Discordance,//?? SkillName.EvalInt, SkillName.Fishing, SkillName.Provocation, SkillName.Lockpicking, SkillName.Magery, SkillName.MagicResist, SkillName.Tactics, SkillName.Snooping, SkillName.RemoveTrap, SkillName.Musicianship, SkillName.Poisoning, SkillName.Archery, SkillName.SpiritSpeak, SkillName.Tailoring, SkillName.AnimalTaming, SkillName.TasteID, SkillName.Tinkering, SkillName.Veterinary, SkillName.Forensics, SkillName.Herding, SkillName.Tracking, SkillName.Stealth, SkillName.Inscribe, SkillName.Swords, SkillName.Macing, SkillName.Fencing, SkillName.Wrestling, SkillName.Lumberjacking, SkillName.Mining, SkillName.Meditation }; public virtual void OnSpeech( SpeechEventArgs e ) { if( e.Mobile.Alive && e.Mobile.InRange( m_Mobile.Location, 3 ) && m_Mobile.IsHumanInTown() ) { if( e.HasKeyword( 0x9D ) && WasNamed( e.Speech ) ) // *move* { if( m_Mobile.Combatant != null ) { // I am too busy fighting to deal with thee! m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); } else { // Excuse me? m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501516 ); WalkRandomInHome( 2, 2, 1 ); } } else if( e.HasKeyword( 0x9E ) && WasNamed( e.Speech ) ) // *time* { if( m_Mobile.Combatant != null ) { // I am too busy fighting to deal with thee! m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); } else { int generalNumber; string exactTime; Clock.GetTime( m_Mobile, out generalNumber, out exactTime ); m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, generalNumber ); } } else if( e.HasKeyword( 0x6C ) && WasNamed( e.Speech ) ) // *train { if( m_Mobile.Combatant != null ) { // I am too busy fighting to deal with thee! m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); } else { bool foundSomething = false; Skills ourSkills = m_Mobile.Skills; Skills theirSkills = e.Mobile.Skills; for( int i = 0; i < ourSkills.Length && i < theirSkills.Length; ++i ) { Skill skill = ourSkills[i]; Skill theirSkill = theirSkills[i]; if( skill != null && theirSkill != null && skill.Base >= 60.0 && m_Mobile.CheckTeach( skill.SkillName, e.Mobile ) ) { double toTeach = skill.Base / 3.0; if( toTeach > 42.0 ) toTeach = 42.0; if( toTeach > theirSkill.Base ) { int number = 1043059 + i; if( number > 1043107 ) continue; if( !foundSomething ) m_Mobile.Say( 1043058 ); // I can train the following: m_Mobile.Say( number ); foundSomething = true; } } } if( !foundSomething ) m_Mobile.Say( 501505 ); // Alas, I cannot teach thee anything. } } else { SkillName toTrain = (SkillName)(-1); for( int i = 0; toTrain == (SkillName)(-1) && i < e.Keywords.Length; ++i ) { int keyword = e.Keywords[i]; if( keyword == 0x154 ) { toTrain = SkillName.Anatomy; } else if( keyword >= 0x6D && keyword <= 0x9C ) { int index = keyword - 0x6D; if( index >= 0 && index < m_KeywordTable.Length ) toTrain = m_KeywordTable[index]; } } if( toTrain != (SkillName)(-1) && WasNamed( e.Speech ) ) { if( m_Mobile.Combatant != null ) { // I am too busy fighting to deal with thee! m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 501482 ); } else { Skills skills = m_Mobile.Skills; Skill skill = skills[toTrain]; if( skill == null || skill.Base < 60.0 || !m_Mobile.CheckTeach( toTrain, e.Mobile ) ) { m_Mobile.Say( 501507 ); // 'Tis not something I can teach thee of. } else { m_Mobile.Teach( toTrain, e.Mobile, 0, false ); } } } } } if( m_Mobile.Controlled && m_Mobile.Commandable ) { m_Mobile.DebugSay( "Listening..." ); bool isOwner = (e.Mobile == m_Mobile.ControlMaster); bool isFriend = (!isOwner && m_Mobile.IsPetFriend( e.Mobile )); if( e.Mobile.Alive && (isOwner || isFriend) ) { m_Mobile.DebugSay( "It's from my master" ); int[] keywords = e.Keywords; string speech = e.Speech; // First, check the all* for( int i = 0; i < keywords.Length; ++i ) { int keyword = keywords[i]; switch( keyword ) { case 0x164: // all come { if( !isOwner ) break; if( m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Come; } return; } case 0x165: // all follow { BeginPickTarget( e.Mobile, OrderType.Follow ); return; } case 0x166: // all guard case 0x16B: // all guard me { if( !isOwner ) break; if( m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Guard; } return; } case 0x167: // all stop { if( m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Stop; } return; } case 0x168: // all kill case 0x169: // all attack { if( !isOwner ) break; BeginPickTarget( e.Mobile, OrderType.Attack ); return; } case 0x16C: // all follow me { if( m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = e.Mobile; m_Mobile.ControlOrder = OrderType.Follow; } return; } case 0x170: // all stay { if( m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Stay; } return; } } } // No all*, so check *command for( int i = 0; i < keywords.Length; ++i ) { int keyword = keywords[i]; switch( keyword ) { case 0x155: // *come { if( !isOwner ) break; if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Come; } return; } case 0x156: // *drop { if( !isOwner ) break; if( !m_Mobile.IsDeadPet && !m_Mobile.Summoned && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Drop; } return; } case 0x15A: // *follow { if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) BeginPickTarget( e.Mobile, OrderType.Follow ); return; } case 0x15B: // *friend { if( !isOwner ) break; if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { if( m_Mobile.Summoned ) e.Mobile.SendLocalizedMessage( 1005481 ); // Summoned creatures are loyal only to their summoners. else if( e.Mobile.HasTrade ) e.Mobile.SendLocalizedMessage( 1070947 ); // You cannot friend a pet with a trade pending else BeginPickTarget( e.Mobile, OrderType.Friend ); } return; } case 0x15C: // *guard { if( !isOwner ) break; if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Guard; } return; } case 0x15D: // *kill case 0x15E: // *attack { if( !isOwner ) break; if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) BeginPickTarget( e.Mobile, OrderType.Attack ); return; } case 0x15F: // *patrol { if( !isOwner ) break; if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Patrol; } return; } case 0x161: // *stop { if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Stop; } return; } case 0x163: // *follow me { if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = e.Mobile; m_Mobile.ControlOrder = OrderType.Follow; } return; } case 0x16D: // *release { if( !isOwner ) break; if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { if( !m_Mobile.Summoned ) { e.Mobile.SendGump( new Gumps.ConfirmReleaseGump( e.Mobile, m_Mobile ) ); } else { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Release; } } return; } case 0x16E: // *transfer { if( !isOwner ) break; if( !m_Mobile.IsDeadPet && WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { if( m_Mobile.Summoned ) e.Mobile.SendLocalizedMessage( 1005487 ); // You cannot transfer ownership of a summoned creature. else if( e.Mobile.HasTrade ) e.Mobile.SendLocalizedMessage( 1010507 ); // You cannot transfer a pet with a trade pending else BeginPickTarget( e.Mobile, OrderType.Transfer ); } return; } case 0x16F: // *stay { if( WasNamed( speech ) && m_Mobile.CheckControlChance( e.Mobile ) ) { m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.Stay; } return; } } } } } else { if( e.Mobile.AccessLevel >= AccessLevel.GameMaster ) { m_Mobile.DebugSay( "It's from a GM" ); if( m_Mobile.FindMyName( e.Speech, true ) ) { string[] str = e.Speech.Split( ' ' ); int i; for( i=0; i < str.Length; i++ ) { string word = str[i]; if( Insensitive.Equals( word, "obey" ) ) { m_Mobile.SetControlMaster( e.Mobile ); if( m_Mobile.Summoned ) m_Mobile.SummonMaster = e.Mobile; return; } } } } } } public virtual bool Think() { if( m_Mobile.Deleted ) return false; if( CheckFlee() ) return true; switch( Action ) { case ActionType.Wander: m_Mobile.OnActionWander(); return DoActionWander(); case ActionType.Combat: m_Mobile.OnActionCombat(); return DoActionCombat(); case ActionType.Guard: m_Mobile.OnActionGuard(); return DoActionGuard(); case ActionType.Flee: m_Mobile.OnActionFlee(); return DoActionFlee(); case ActionType.Interact: m_Mobile.OnActionInteract(); return DoActionInteract(); case ActionType.Backoff: m_Mobile.OnActionBackoff(); return DoActionBackoff(); default: return false; } } public virtual void OnActionChanged() { switch( Action ) { case ActionType.Wander: m_Mobile.Warmode = false; m_Mobile.Combatant = null; m_Mobile.FocusMob = null; m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; break; case ActionType.Combat: m_Mobile.Warmode = true; m_Mobile.FocusMob = null; m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; break; case ActionType.Guard: m_Mobile.Warmode = true; m_Mobile.FocusMob = null; m_Mobile.Combatant = null; m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_NextStopGuard = DateTime.Now + TimeSpan.FromSeconds( 10 ); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; break; case ActionType.Flee: m_Mobile.Warmode = true; m_Mobile.FocusMob = null; m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; break; case ActionType.Interact: m_Mobile.Warmode = false; m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; break; case ActionType.Backoff: m_Mobile.Warmode = false; m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; break; } } public virtual bool OnAtWayPoint() { return true; } public virtual bool DoActionWander() { if( CheckHerding() ) { m_Mobile.DebugSay( "Praise the shepherd!" ); } else if( m_Mobile.CurrentWayPoint != null ) { WayPoint point = m_Mobile.CurrentWayPoint; if( (point.X != m_Mobile.Location.X || point.Y != m_Mobile.Location.Y) && point.Map == m_Mobile.Map && point.Parent == null && !point.Deleted ) { m_Mobile.DebugSay( "I will move towards my waypoint." ); DoMove( m_Mobile.GetDirectionTo( m_Mobile.CurrentWayPoint ) ); } else if( OnAtWayPoint() ) { m_Mobile.DebugSay( "I will go to the next waypoint" ); m_Mobile.CurrentWayPoint = point.NextPoint; if( point.NextPoint != null && point.NextPoint.Deleted ) m_Mobile.CurrentWayPoint = point.NextPoint = point.NextPoint.NextPoint; } } else if( m_Mobile.IsAnimatedDead ) { // animated dead follow their master Mobile master = m_Mobile.SummonMaster; if( master != null && master.Map == m_Mobile.Map && master.InRange( m_Mobile, m_Mobile.RangePerception ) ) MoveTo( master, false, 1 ); else WalkRandomInHome( 2, 2, 1 ); } else if( CheckMove() ) { if( !m_Mobile.CheckIdle() ) WalkRandomInHome( 2, 2, 1 ); } if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) { m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); } return true; } public virtual bool DoActionCombat() { Mobile c = m_Mobile.Combatant; if( c == null || c.Deleted || c.Map != m_Mobile.Map || !c.Alive || c.IsDeadBondedPet ) Action = ActionType.Wander; else m_Mobile.Direction = m_Mobile.GetDirectionTo( c ); return true; } public virtual bool DoActionGuard() { if( DateTime.Now < m_NextStopGuard ) { m_Mobile.DebugSay( "I am on guard" ); //m_Mobile.Turn( Utility.Random(0, 2) - 1 ); } else { m_Mobile.DebugSay( "I stopped being on guard" ); Action = ActionType.Wander; } return true; } public virtual bool DoActionFlee() { Mobile from = m_Mobile.FocusMob; if( from == null || from.Deleted || from.Map != m_Mobile.Map ) { m_Mobile.DebugSay( "I have lost him" ); Action = ActionType.Guard; return true; } if( WalkMobileRange( from, 1, true, m_Mobile.RangePerception*2, m_Mobile.RangePerception*3 ) ) { m_Mobile.DebugSay( "I have fled" ); Action = ActionType.Guard; return true; } else { m_Mobile.DebugSay( "I am fleeing!" ); } return true; } public virtual bool DoActionInteract() { return true; } public virtual bool DoActionBackoff() { return true; } public virtual bool Obey() { if( m_Mobile.Deleted ) return false; switch( m_Mobile.ControlOrder ) { case OrderType.None: return DoOrderNone(); case OrderType.Come: return DoOrderCome(); case OrderType.Drop: return DoOrderDrop(); case OrderType.Friend: return DoOrderFriend(); case OrderType.Unfriend: return DoOrderUnfriend(); case OrderType.Guard: return DoOrderGuard(); case OrderType.Attack: return DoOrderAttack(); case OrderType.Patrol: return DoOrderPatrol(); case OrderType.Release: return DoOrderRelease(); case OrderType.Stay: return DoOrderStay(); case OrderType.Stop: return DoOrderStop(); case OrderType.Follow: return DoOrderFollow(); case OrderType.Transfer: return DoOrderTransfer(); default: return false; } } public virtual void OnCurrentOrderChanged() { if( m_Mobile.Deleted || m_Mobile.ControlMaster == null || m_Mobile.ControlMaster.Deleted ) return; switch( m_Mobile.ControlOrder ) { case OrderType.None: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.Home = m_Mobile.Location; m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Come: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Drop: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = true; m_Mobile.Combatant = null; break; case OrderType.Friend: case OrderType.Unfriend: m_Mobile.ControlMaster.RevealingAction(); break; case OrderType.Guard: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = true; m_Mobile.Combatant = null; break; case OrderType.Attack: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = true; m_Mobile.Combatant = null; break; case OrderType.Patrol: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Release: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Stay: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Stop: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Follow: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.ActiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; case OrderType.Transfer: m_Mobile.ControlMaster.RevealingAction(); m_Mobile.CurrentSpeed = m_Mobile.PassiveSpeed; m_Mobile.PlaySound( m_Mobile.GetIdleSound() ); m_Mobile.Warmode = false; m_Mobile.Combatant = null; break; } } public virtual bool DoOrderNone() { m_Mobile.DebugSay( "I have no order" ); WalkRandomInHome( 3, 2, 1 ); if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) { m_Mobile.Warmode = true; m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); } else { m_Mobile.Warmode = false; } return true; } public virtual bool DoOrderCome() { if( m_Mobile.ControlMaster != null && !m_Mobile.ControlMaster.Deleted ) { int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( m_Mobile.ControlMaster ); if( iCurrDist > m_Mobile.RangePerception ) { m_Mobile.DebugSay( "I have lost my master. I stay here" ); m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.None; } else { m_Mobile.DebugSay( "My master told me come" ); // Not exactly OSI style, but better than nothing. bool bRun = (iCurrDist > 5); if( WalkMobileRange( m_Mobile.ControlMaster, 1, bRun, 0, 1 ) ) { if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) { m_Mobile.Warmode = true; m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); } else { m_Mobile.Warmode = false; } } } } return true; } public virtual bool DoOrderDrop() { if( m_Mobile.IsDeadPet || !m_Mobile.CanDrop ) return true; m_Mobile.DebugSay( "I drop my stuff for my master" ); Container pack = m_Mobile.Backpack; if( pack != null ) { List<Item> list = pack.Items; for( int i = list.Count - 1; i >= 0; --i ) if( i < list.Count ) list[i].MoveToWorld( m_Mobile.Location, m_Mobile.Map ); } m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.None; return true; } public virtual bool CheckHerding() { Point2D target = m_Mobile.TargetLocation; if( target == Point2D.Zero ) return false; // Creature is not being herded double distance = m_Mobile.GetDistanceToSqrt( target ); if( distance < 1 || distance > 20 ) { if( distance < 1 && target.X == 1076 && target.Y == 450 && (m_Mobile is HordeMinionFamiliar) ) { PlayerMobile pm = m_Mobile.ControlMaster as PlayerMobile; if( pm != null ) { QuestSystem qs = pm.Quest; if( qs is DarkTidesQuest ) { QuestObjective obj = qs.FindObjective( typeof( FetchAbraxusScrollObjective ) ); if( obj != null && !obj.Completed ) { m_Mobile.AddToBackpack( new ScrollOfAbraxus() ); obj.Complete(); } } } } m_Mobile.TargetLocation = Point2D.Zero; return false; // At the target or too far away } DoMove( m_Mobile.GetDirectionTo( target ) ); return true; } public virtual bool DoOrderFollow() { if( CheckHerding() ) { m_Mobile.DebugSay( "Praise the shepherd!" ); } else if( m_Mobile.ControlTarget != null && !m_Mobile.ControlTarget.Deleted && m_Mobile.ControlTarget != m_Mobile ) { int iCurrDist = (int)m_Mobile.GetDistanceToSqrt( m_Mobile.ControlTarget ); if( iCurrDist > m_Mobile.RangePerception ) { m_Mobile.DebugSay( "I have lost the one to follow. I stay here" ); if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) { m_Mobile.Warmode = true; m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); } else { m_Mobile.Warmode = false; } } else { m_Mobile.DebugSay( "My master told me to follow: {0}", m_Mobile.ControlTarget.Name ); // Not exactly OSI style, but better than nothing. bool bRun = (iCurrDist > 5); if( WalkMobileRange( m_Mobile.ControlTarget, 1, bRun, 0, 1 ) ) { if( m_Mobile.Combatant != null && !m_Mobile.Combatant.Deleted && m_Mobile.Combatant.Alive && !m_Mobile.Combatant.IsDeadBondedPet ) { m_Mobile.Warmode = true; m_Mobile.Direction = m_Mobile.GetDirectionTo( m_Mobile.Combatant ); } else { m_Mobile.Warmode = false; } } } } else { m_Mobile.DebugSay( "I have nobody to follow" ); m_Mobile.ControlTarget = null; m_Mobile.ControlOrder = OrderType.None; } return true; } public virtual bool DoOrderFriend() { Mobile from = m_Mobile.ControlMaster; Mobile to = m_Mobile.ControlTarget; if( from == null || to == null || from == to || from.Deleted || to.Deleted || !to.Player ) { m_Mobile.PublicOverheadMessage( MessageType.Regular, 0x3B2, 502039 ); // *looks confused* } Erica- 01-30-2008 Hmm i am not sure what to do ArteGordon any ideas? Erica- 01-30-2008 i added this on mirror image .
now they come out red the clones but says this when you try to attack the clones , you cannot perform negative acts on your target any idea how to get it so you can attack the clones like osi. Erica- 01-30-2008 This is strange i put on cloak to be regular player i can attack the red regular ninja but cant attack his red ninja clones might be cause its his followers but cant figure out how to be able to attack his clone. koluch- 01-31-2008 *Im lookin also Erica* Testing some stuff now, will seeifI get any results ;/ Erica- 01-31-2008 Good Luck hopefully youll have better Luck then me. ArteGordon- 02-01-2008 This has to do with the way notoriety works with summoned human creatures. By default if the creature has a human body and is summoned then they will flagged as innocent and will be protected. If you want the clones to be always attackable, then override the AlwaysAttackble property in the mirror image clone class. public override bool AlwaysAttackable{ get{ return true; } } also note that the fightmode of clones is FightMode.None, so they will be passive |