using Server.Gumps; using Server.Mobiles; using Server.Network; using Server.Targeting; using System; using System.Collections.Generic; using System.Linq; namespace Server.Spells.SkillMasteries { public enum TrainingType { Empowerment, Berserk, ConsumeDamage, AsOne } public class CombatTrainingSpell : SkillMasterySpell { private static readonly SpellInfo m_Info = new SpellInfo( "Combat Training", "", -1, 9002 ); public override double UpKeep { get { double taming = Caster.Skills[CastSkill].Base; double lore = Caster.Skills[SkillName.AnimalLore].Base; bool asone = SpellType == TrainingType.AsOne; double skillvalue = (taming + (lore / 2)); int mastery_base = 12; if (skillvalue < 150) mastery_base = 12; if (skillvalue < 165) mastery_base = 10; if (skillvalue < 180) mastery_base = 8; if (skillvalue >= 180) mastery_base = 6; return asone ? mastery_base * 2 : mastery_base; } } public override double RequiredSkill => 90; public override int RequiredMana => 40; public override bool PartyEffects => false; public override SkillName CastSkill => SkillName.AnimalTaming; public override bool CheckManaBeforeCast => !HasSpell(Caster, GetType()); public TrainingType SpellType { get; set; } private int _Phase; private int _DamageTaken; private bool _Expired; public int Phase { get { return _Phase; } set { _Phase = value; } } public int DamageTaken { get { return _DamageTaken; } set { _DamageTaken = value; } } public CombatTrainingSpell(Mobile caster, Item scroll) : base(caster, scroll, m_Info) { } public override bool Cast() { CombatTrainingSpell spell = GetSpell(Caster, typeof(CombatTrainingSpell)) as CombatTrainingSpell; if (spell != null) { spell.Expire(); return false; } return base.Cast(); } public override bool CheckCast() { if (Caster is PlayerMobile && ((PlayerMobile)Caster).AllFollowers == null || ((PlayerMobile)Caster).AllFollowers.Count == 0) { Caster.SendLocalizedMessage(1156112); // This ability requires you to have pets. return false; } return base.CheckCast(); } public override void SendCastEffect() { base.SendCastEffect(); Caster.PrivateOverheadMessage(MessageType.Regular, 0x35, false, "You ready your pet for combat, increasing its battle effectiveness!", Caster.NetState); } public override void OnCast() { Caster.Target = new InternalTarget(this); } public void OnSelected(TrainingType type, Mobile target) { if (!CheckSequence() || (type == TrainingType.AsOne && Caster is PlayerMobile && ((PlayerMobile)Caster).AllFollowers.Where(mob => mob != target).Count() == 0)) { FinishSequence(); return; } SpellType = type; Target = target; _Phase = 0; BeginTimer(); Target.FixedParticles(0x373A, 10, 80, 5018, 0, 0, EffectLayer.Waist); BuffInfo.AddBuff(Caster, new BuffInfo(BuffIcon.CombatTraining, 1155933, 1156107, string.Format("{0}\t{1}\t{2}", SpellType.ToString(), Target.Name, ScaleUpkeep().ToString()))); //You train ~2_NAME~ to use ~1_SKILLNAME~.
Mana Upkeep: ~3_COST~ FinishSequence(); } public override void EndEffects() { BuffInfo.RemoveBuff(Caster, BuffIcon.CombatTraining); Caster.SendSound(0x1ED); _Expired = true; } protected override void DoEffects() { Caster.FixedParticles(0x376A, 10, 30, 5052, 1261, 0, EffectLayer.LeftFoot, 0); Caster.DisruptiveAction(); } public override bool OnTick() { if (Target == null || Target.IsDeadBondedPet /* || Target.Map != Caster.Map*/) { Expire(); return false; } return base.OnTick(); } public double DamageMod { get { if (Target == null || SpellType == TrainingType.AsOne) return 0.0; double dam = _DamageTaken / (Target.HitsMax * .66); if (dam > 1.0) dam = 1.0; return dam; } } private void EndPhase1() { if (_Expired) return; _Phase = 2; Server.Timer.DelayCall(TimeSpan.FromSeconds(SpellType == TrainingType.Berserk ? 8 : 10), EndPhase2); } private void EndPhase2() { if (_Expired) return; _DamageTaken = 0; _Phase = 0; if (SpellType == TrainingType.Berserk) { AddRageCooldown(Target); } } public static void CheckDamage(Mobile attacker, Mobile defender, DamageType type, ref int damage) { if (defender is BaseCreature && (((BaseCreature)defender).Controlled || ((BaseCreature)defender).Summoned)) { CombatTrainingSpell spell = GetSpell(sp => sp.Target == defender); if (spell != null) { int storedDamage = damage; switch (spell.SpellType) { case TrainingType.Empowerment: break; case TrainingType.Berserk: if (InRageCooldown(defender)) { return; } if (spell.Phase > 1) { damage = damage - (int)(damage * spell.DamageMod); defender.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0); } break; case TrainingType.ConsumeDamage: if (spell.Phase < 2) { defender.SendDamagePacket(attacker, damage); damage = 0; } break; case TrainingType.AsOne: if (((BaseCreature)defender).GetMaster() is PlayerMobile) { PlayerMobile pm = ((BaseCreature)defender).GetMaster() as PlayerMobile; List list = pm.AllFollowers.Where(m => (m == defender || m.InRange(defender.Location, 3)) && m.CanBeHarmful(attacker)).ToList(); if (list.Count > 0) { damage = damage / list.Count; foreach (Mobile m in list.Where(mob => mob != defender)) { m.Damage(damage, attacker, true, false); } } ColUtility.Free(list); } return; } if (spell.Phase < 2) { if (spell.Phase != 1) { spell.Phase = 1; if (spell.SpellType != TrainingType.AsOne && (spell.SpellType != TrainingType.Berserk || !InRageCooldown(defender))) { Server.Timer.DelayCall(TimeSpan.FromSeconds(5), spell.EndPhase1); } } if (spell.DamageTaken == 0) defender.FixedEffect(0x3779, 10, 30, 1743, 0); spell.DamageTaken += storedDamage; } } } else if (attacker is BaseCreature && (((BaseCreature)attacker).Controlled || ((BaseCreature)attacker).Summoned)) { CombatTrainingSpell spell = GetSpell(sp => sp.Target == attacker); if (spell != null) { switch (spell.SpellType) { case TrainingType.Empowerment: if (spell.Phase > 1) { damage = damage + (int)(damage * spell.DamageMod); attacker.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0); } break; case TrainingType.Berserk: case TrainingType.ConsumeDamage: case TrainingType.AsOne: break; } } } } public static void OnCreatureHit(Mobile attacker, Mobile defender, ref int damage) { if (attacker is BaseCreature && (((BaseCreature)attacker).Controlled || ((BaseCreature)attacker).Summoned)) { CombatTrainingSpell spell = GetSpell(sp => sp.Target == attacker); if (spell != null) { switch (spell.SpellType) { case TrainingType.Empowerment: break; case TrainingType.Berserk: if (spell.Phase > 1) { damage = damage + (int)(damage * spell.DamageMod); attacker.FixedParticles(0x376A, 10, 30, 5052, 1261, 7, EffectLayer.LeftFoot, 0); } break; case TrainingType.ConsumeDamage: case TrainingType.AsOne: break; } } } } public static int RegenBonus(Mobile m) { if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned)) { CombatTrainingSpell spell = GetSpell(sp => sp.Target == m); if (spell != null && spell.SpellType == TrainingType.ConsumeDamage && spell.Phase > 1) { return (int)(30.0 * spell.DamageMod); } } return 0; } public static int GetHitChanceBonus(Mobile m) { if (m is BaseCreature && (((BaseCreature)m).Controlled || ((BaseCreature)m).Summoned)) { CombatTrainingSpell spell = GetSpell(sp => sp.Target == m); if (spell != null && spell.SpellType == TrainingType.ConsumeDamage && spell.Phase > 1) { return (int)(45 * spell.DamageMod); } } return 0; } public class InternalTarget : Target { public CombatTrainingSpell Spell { get; set; } public InternalTarget(CombatTrainingSpell spell) : base(8, false, TargetFlags.None) { Spell = spell; } protected override void OnTarget(Mobile from, object targeted) { if (targeted is Engines.Despise.DespiseCreature) { return; } if (targeted is BaseCreature && ((BaseCreature)targeted).GetMaster() == from && from.Spell == Spell) { Spell.Caster.FixedEffect(0x3779, 10, 20, 1270, 0); Spell.Caster.SendSound(0x64E); int taming = (int)from.Skills[SkillName.AnimalTaming].Value; int lore = (int)from.Skills[SkillName.AnimalLore].Value; from.CheckTargetSkill(SkillName.AnimalTaming, (BaseCreature)targeted, taming - 25, taming + 25); from.CheckTargetSkill(SkillName.AnimalLore, (BaseCreature)targeted, lore - 25, lore + 25); from.CloseGump(typeof(ChooseTrainingGump)); from.SendGump(new ChooseTrainingGump(from, (BaseCreature)targeted, Spell)); } } protected override void OnTargetCancel(Mobile from, TargetCancelType cancelType) { from.SendLocalizedMessage(1156110); // Your ability was canceled. Spell.FinishSequence(); } } public static void AddRageCooldown(Mobile m) { if (_RageCooldown == null) _RageCooldown = new Dictionary(); _RageCooldown[m] = Server.Timer.DelayCall(TimeSpan.FromSeconds(60), EndRageCooldown, m); } public static bool InRageCooldown(Mobile m) { return _RageCooldown != null && _RageCooldown.ContainsKey(m); } public static void EndRageCooldown(Mobile m) { if (_RageCooldown != null && _RageCooldown.ContainsKey(m)) { _RageCooldown.Remove(m); } } public static Dictionary _RageCooldown; } public class ChooseTrainingGump : Gump { public CombatTrainingSpell Spell { get; private set; } public Mobile Caster { get; private set; } public BaseCreature Target { get; private set; } public const int Hue = 0x07FF; public ChooseTrainingGump(Mobile caster, BaseCreature target, CombatTrainingSpell spell) : base(100, 100) { Spell = spell; Caster = caster; Target = target; AddBackground(0, 0, 260, 187, 3600); AddAlphaRegion(10, 10, 240, 167); AddImageTiled(220, 15, 30, 162, 10464); AddHtmlLocalized(20, 20, 150, 16, 1156113, Hue, false, false); // Select Training int y = 40; if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 1)) { AddButton(20, y, 9762, 9763, 1, GumpButtonType.Reply, 0); AddHtmlLocalized(43, y, 150, 16, 1156109, Hue, false, false); // Empowerment y += 20; } if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 2)) { AddButton(20, y, 9762, 9763, 2, GumpButtonType.Reply, 0); AddHtmlLocalized(43, y, 150, 16, 1153271, Hue, false, false); // Berserk y += 20; } if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 3)) { AddButton(20, y, 9762, 9763, 3, GumpButtonType.Reply, 0); AddHtmlLocalized(43, y, 150, 16, 1156108, Hue, false, false); // Consume Damage y += 20; } if (MasteryInfo.HasLearned(caster, SkillName.AnimalTaming, 1)) { AddButton(20, y, 9762, 9763, 4, GumpButtonType.Reply, 0); AddHtmlLocalized(43, y, 150, 16, 1157544, Hue, false, false); // As One } } public override void OnResponse(NetState state, RelayInfo info) { if (info.ButtonID == 0) { Spell.FinishSequence(); state.Mobile.SendLocalizedMessage(1156110); // Your ability was canceled. return; } Spell.OnSelected((TrainingType)info.ButtonID - 1, Target); } } }