#region References using System; using System.Collections.Generic; using Server.Items; using Server.Spells; using Server.Spells.Ninjitsu; #endregion namespace Server.Mobiles { public class NinjaAI : MeleeAI { private DateTime m_NextCastTime; private DateTime m_NextRanged; public NinjaAI(BaseCreature bc) : base(bc) { m_NextCastTime = DateTime.UtcNow; } private void TryPerformHide() { if (!m_Mobile.Alive || m_Mobile.Deleted) return; if (!m_Mobile.Hidden && Core.TickCount - m_Mobile.NextSkillTime >= 0) { var chance = 0.05; if (m_Mobile.Hits < 20) chance = 0.10; if (m_Mobile.Poisoned) chance = 0.01; if (Utility.RandomDouble() < chance) HideSelf(); } } private void HideSelf() { Effects.SendLocationParticles( EffectItem.Create(m_Mobile.Location, m_Mobile.Map, EffectItem.DefaultDuration), 0x3728, 10, 10, 2023); m_Mobile.PlaySound(0x22F); m_Mobile.Hidden = true; m_Mobile.UseSkill(SkillName.Stealth); } public virtual SpecialMove GetHiddenSpecialMove() { var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value; if (skill < 40) return null; if (skill >= 60) { //return .5 > Utility.RandomDouble() ? new SupriseAttack() : new Backstab(); return .5 > Utility.RandomDouble() ? SpellRegistry.GetSpecialMove(504) : SpellRegistry.GetSpecialMove(505); } return SpellRegistry.GetSpecialMove(505); //new Backstab(); } public virtual SpecialMove GetSpecialMove() { var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value; if (skill < 40) return null; var avail = 1; if (skill >= 85) avail = 3; else if (skill >= 80) avail = 2; switch (Utility.Random(avail)) { case 0: return SpellRegistry.GetSpecialMove(500); //new FocusAttack(); case 1: return SpellRegistry.GetSpecialMove(503); //new KiAttack(); case 2: return SpellRegistry.GetSpecialMove(501); //new DeathStrike(); } return null; } public void DoRangedAttack() { var c = m_Mobile.Combatant as Mobile; if (c == null) return; var list = new List(); var d = (int)m_Mobile.GetDistanceToSqrt(c.Location); foreach (var item in m_Mobile.Items) if (item is INinjaWeapon && ((INinjaWeapon)item).UsesRemaining > 0 && d >= ((INinjaWeapon)item).WeaponMinRange && d <= ((INinjaWeapon)item).WeaponMaxRange) list.Add(item as INinjaWeapon); if (m_Mobile.Backpack != null) { foreach (var item in m_Mobile.Backpack.Items) if (item is INinjaWeapon && ((INinjaWeapon)item).UsesRemaining > 0 && d >= ((INinjaWeapon)item).WeaponMinRange && d <= ((INinjaWeapon)item).WeaponMaxRange) list.Add(item as INinjaWeapon); } if (list.Count > 0) { var toUse = list[Utility.Random(list.Count)]; if (toUse != null) NinjaWeapon.Shoot(m_Mobile, c, toUse); } ColUtility.Free(list); m_NextRanged = DateTime.UtcNow + TimeSpan.FromSeconds(Utility.RandomMinMax(30, 120)); } public override bool DoActionWander() { base.DoActionWander(); if (m_Mobile.Combatant == null) TryPerformHide(); return true; } public override bool DoActionCombat() { base.DoActionCombat(); if (m_Mobile.Combatant == null) return true; var special = SpecialMove.GetCurrentMove(m_Mobile); if (special == null && m_NextCastTime < DateTime.UtcNow && 0.05 > Utility.RandomDouble()) { if (0.05 > Utility.RandomDouble()) { new MirrorImage(m_Mobile, null).Cast(); } else { if (m_Mobile.Hidden) special = GetHiddenSpecialMove(); else special = GetSpecialMove(); if (special != null) { SpecialMove.SetCurrentMove(m_Mobile, special); m_NextCastTime = DateTime.UtcNow + GetCastDelay(); } } } if (m_NextRanged < DateTime.UtcNow && 0.08 > Utility.RandomDouble()) DoRangedAttack(); return true; } public override bool DoActionFlee() { base.DoActionFlee(); TryPerformHide(); return true; } public TimeSpan GetCastDelay() { var skill = (int)m_Mobile.Skills[SkillName.Ninjitsu].Value; if (skill >= 85) return TimeSpan.FromSeconds(15); if (skill > 40) return TimeSpan.FromSeconds(30); return TimeSpan.FromSeconds(45); } } }