Advertisement
Guest User

Untitled

a guest
Jan 23rd, 2015
363
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.67 KB | None | 0 0
  1. #region Header
  2. // **********
  3. // ServUO - Spell.cs
  4. // **********
  5. #endregion
  6.  
  7. #region References
  8. using System;
  9. using System.Collections.Generic;
  10.  
  11. using Server.Engines.ConPVP;
  12. using Server.Items;
  13. using Server.Misc;
  14. using Server.Mobiles;
  15. using Server.Network;
  16. using Server.Spells.Bushido;
  17. using Server.Spells.Necromancy;
  18. using Server.Spells.Ninjitsu;
  19. using Server.Spells.Second;
  20. using Server.Spells.Spellweaving;
  21. using Server.Targeting;
  22. #endregion
  23.  
  24. namespace Server.Spells
  25. {
  26. public abstract class Spell : ISpell
  27. {
  28. private readonly Mobile m_Caster;
  29. private readonly Item m_Scroll;
  30. private readonly SpellInfo m_Info;
  31. private SpellState m_State;
  32. private long m_StartCastTime;
  33.  
  34. public SpellState State { get { return m_State; } set { m_State = value; } }
  35. public Mobile Caster { get { return m_Caster; } }
  36. public SpellInfo Info { get { return m_Info; } }
  37. public string Name { get { return m_Info.Name; } }
  38. public string Mantra { get { return m_Info.Mantra; } }
  39. public Type[] Reagents { get { return m_Info.Reagents; } }
  40. public Item Scroll { get { return m_Scroll; } }
  41. public long StartCastTime { get { return m_StartCastTime; } }
  42.  
  43. private static readonly TimeSpan NextSpellDelay = TimeSpan.FromSeconds(0.0000);
  44. private static TimeSpan AnimateDelay = TimeSpan.FromSeconds(0.5);
  45.  
  46. public virtual SkillName CastSkill { get { return SkillName.Magery; } }
  47. public virtual SkillName DamageSkill { get { return SkillName.EvalInt; } }
  48.  
  49. public virtual bool RevealOnCast { get { return true; } }
  50. public virtual bool ClearHandsOnCast { get { return true; } }
  51. public virtual bool ShowHandMovement { get { return true; } }
  52.  
  53. public virtual bool DelayedDamage { get { return false; } }
  54.  
  55. public virtual bool DelayedDamageStacking { get { return true; } }
  56. //In reality, it's ANY delayed Damage spell Post-AoS that can't stack, but, only
  57. //Expo & Magic Arrow have enough delay and a short enough cast time to bring up
  58. //the possibility of stacking 'em. Note that a MA & an Explosion will stack, but
  59. //of course, two MA's won't.
  60.  
  61. private static readonly Dictionary<Type, DelayedDamageContextWrapper> m_ContextTable =
  62. new Dictionary<Type, DelayedDamageContextWrapper>();
  63.  
  64. private class DelayedDamageContextWrapper
  65. {
  66. private readonly Dictionary<Mobile, Timer> m_Contexts = new Dictionary<Mobile, Timer>();
  67.  
  68. public void Add(Mobile m, Timer t)
  69. {
  70. Timer oldTimer;
  71. if (m_Contexts.TryGetValue(m, out oldTimer))
  72. {
  73. oldTimer.Stop();
  74. m_Contexts.Remove(m);
  75. }
  76.  
  77. m_Contexts.Add(m, t);
  78. }
  79.  
  80. public void Remove(Mobile m)
  81. {
  82. m_Contexts.Remove(m);
  83. }
  84. }
  85.  
  86. public void StartDelayedDamageContext(Mobile m, Timer t)
  87. {
  88. if (DelayedDamageStacking)
  89. {
  90. return; //Sanity
  91. }
  92.  
  93. DelayedDamageContextWrapper contexts;
  94.  
  95. if (!m_ContextTable.TryGetValue(GetType(), out contexts))
  96. {
  97. contexts = new DelayedDamageContextWrapper();
  98. m_ContextTable.Add(GetType(), contexts);
  99. }
  100.  
  101. contexts.Add(m, t);
  102. }
  103.  
  104. public void RemoveDelayedDamageContext(Mobile m)
  105. {
  106. DelayedDamageContextWrapper contexts;
  107.  
  108. if (!m_ContextTable.TryGetValue(GetType(), out contexts))
  109. {
  110. return;
  111. }
  112.  
  113. contexts.Remove(m);
  114. }
  115.  
  116. public void HarmfulSpell(Mobile m)
  117. {
  118. if (m is BaseCreature)
  119. {
  120. ((BaseCreature)m).OnHarmfulSpell(m_Caster);
  121. }
  122. }
  123.  
  124. public Spell(Mobile caster, Item scroll, SpellInfo info)
  125. {
  126. m_Caster = caster;
  127. m_Scroll = scroll;
  128. m_Info = info;
  129. }
  130.  
  131. public virtual int GetNewAosDamage(int bonus, int dice, int sides, Mobile singleTarget)
  132. {
  133. if (singleTarget != null)
  134. {
  135. return GetNewAosDamage(bonus, dice, sides, (Caster.Player && singleTarget.Player), GetDamageScalar(singleTarget));
  136. }
  137. else
  138. {
  139. return GetNewAosDamage(bonus, dice, sides, false);
  140. }
  141. }
  142.  
  143. public virtual int GetNewAosDamage(int bonus, int dice, int sides, bool playerVsPlayer)
  144. {
  145. return GetNewAosDamage(bonus, dice, sides, playerVsPlayer, 1.0);
  146. }
  147.  
  148. public virtual int GetNewAosDamage(int bonus, int dice, int sides, bool playerVsPlayer, double scalar)
  149. {
  150. int damage = Utility.Dice(dice, sides, bonus) * 100;
  151. int damageBonus = 0;
  152.  
  153. int inscribeSkill = GetInscribeFixed(m_Caster);
  154. int inscribeBonus = (inscribeSkill + (1000 * (inscribeSkill / 1000))) / 200;
  155. damageBonus += inscribeBonus;
  156.  
  157. int intBonus = Caster.Int / 10;
  158. damageBonus += intBonus;
  159.  
  160. int sdiBonus = AosAttributes.GetValue(m_Caster, AosAttribute.SpellDamage);
  161.  
  162. #region Mondain's Legacy
  163. sdiBonus += ArcaneEmpowermentSpell.GetSpellBonus(m_Caster, playerVsPlayer);
  164. #endregion
  165.  
  166. // PvP spell damage increase cap of 15% from an item’s magic property, 30% if spell school focused.
  167. if (playerVsPlayer)
  168. {
  169. if (SpellHelper.HasSpellMastery(m_Caster) && sdiBonus > 30)
  170. {
  171. sdiBonus = 30;
  172. }
  173.  
  174. if (!SpellHelper.HasSpellMastery(m_Caster) && sdiBonus > 15)
  175. {
  176. sdiBonus = 15;
  177. }
  178. }
  179.  
  180. damageBonus += sdiBonus;
  181.  
  182. TransformContext context = TransformationSpellHelper.GetContext(Caster);
  183.  
  184. if (context != null && context.Spell is ReaperFormSpell)
  185. {
  186. damageBonus += ((ReaperFormSpell)context.Spell).SpellDamageBonus;
  187. }
  188.  
  189. damage = AOS.Scale(damage, 100 + damageBonus);
  190.  
  191. int evalSkill = GetDamageFixed(m_Caster);
  192. int evalScale = 30 + ((9 * evalSkill) / 100);
  193.  
  194. damage = AOS.Scale(damage, evalScale);
  195.  
  196. damage = AOS.Scale(damage, (int)(scalar * 100));
  197.  
  198. return damage / 100;
  199. }
  200.  
  201. public virtual bool IsCasting { get { return m_State == SpellState.Casting; } }
  202.  
  203. public virtual void OnCasterHurt()
  204. {
  205. //Confirm: Monsters and pets cannot be disturbed.
  206. if (!Caster.Player)
  207. {
  208. return;
  209. }
  210.  
  211. if (IsCasting)
  212. {
  213. object o = ProtectionSpell.Registry[m_Caster];
  214. bool disturb = true;
  215.  
  216. if (o != null && o is double)
  217. {
  218. if (((double)o) > Utility.RandomDouble() * 100.0)
  219. {
  220. disturb = false;
  221. }
  222. }
  223.  
  224. #region Stygian Abyss
  225. int focus = SAAbsorptionAttributes.GetValue(Caster, SAAbsorptionAttribute.CastingFocus);
  226.  
  227. if (focus > 0)
  228. {
  229. if (focus > 30)
  230. {
  231. focus = 30;
  232. }
  233.  
  234. if (focus > Utility.Random(100))
  235. {
  236. disturb = false;
  237. Caster.SendLocalizedMessage(1113690); // You regain your focus and continue casting the spell.
  238. }
  239. }
  240. #endregion
  241.  
  242. if (disturb)
  243. {
  244. Disturb(DisturbType.Hurt, false, true);
  245. }
  246. }
  247. }
  248.  
  249. public virtual void OnCasterKilled()
  250. {
  251. Disturb(DisturbType.Kill);
  252. }
  253.  
  254. public virtual void OnConnectionChanged()
  255. {
  256. FinishSequence();
  257. }
  258.  
  259. public virtual bool OnCasterMoving(Direction d)
  260. {
  261. if (IsCasting && BlocksMovement)
  262. {
  263. m_Caster.SendLocalizedMessage(500111); // You are frozen and can not move.
  264. return false;
  265. }
  266.  
  267. return true;
  268. }
  269.  
  270. public virtual bool OnCasterEquiping(Item item)
  271. {
  272. if (IsCasting)
  273. {
  274. Disturb(DisturbType.EquipRequest);
  275. }
  276.  
  277. return true;
  278. }
  279.  
  280. public virtual bool OnCasterUsingObject(object o)
  281. {
  282. if (m_State == SpellState.Sequencing)
  283. {
  284. Disturb(DisturbType.UseRequest);
  285. }
  286.  
  287. return true;
  288. }
  289.  
  290. public virtual bool OnCastInTown(Region r)
  291. {
  292. return m_Info.AllowTown;
  293. }
  294.  
  295. public virtual bool ConsumeReagents()
  296. {
  297. if (m_Scroll != null || !m_Caster.Player)
  298. {
  299. return true;
  300. }
  301.  
  302. if (AosAttributes.GetValue(m_Caster, AosAttribute.LowerRegCost) > Utility.Random(100))
  303. {
  304. return true;
  305. }
  306.  
  307. if (DuelContext.IsFreeConsume(m_Caster))
  308. {
  309. return true;
  310. }
  311.  
  312. Container pack = m_Caster.Backpack;
  313.  
  314. if (pack == null)
  315. {
  316. return false;
  317. }
  318.  
  319. if (pack.ConsumeTotal(m_Info.Reagents, m_Info.Amounts) == -1)
  320. {
  321. return true;
  322. }
  323.  
  324. return false;
  325. }
  326.  
  327. public virtual double GetInscribeSkill(Mobile m)
  328. {
  329. // There is no chance to gain
  330. // m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 );
  331. return m.Skills[SkillName.Inscribe].Value;
  332. }
  333.  
  334. public virtual int GetInscribeFixed(Mobile m)
  335. {
  336. // There is no chance to gain
  337. // m.CheckSkill( SkillName.Inscribe, 0.0, 120.0 );
  338. return m.Skills[SkillName.Inscribe].Fixed;
  339. }
  340.  
  341. public virtual int GetDamageFixed(Mobile m)
  342. {
  343. //m.CheckSkill( DamageSkill, 0.0, m.Skills[DamageSkill].Cap );
  344. return m.Skills[DamageSkill].Fixed;
  345. }
  346.  
  347. public virtual double GetDamageSkill(Mobile m)
  348. {
  349. //m.CheckSkill( DamageSkill, 0.0, m.Skills[DamageSkill].Cap );
  350. return m.Skills[DamageSkill].Value;
  351. }
  352.  
  353. public virtual double GetResistSkill(Mobile m)
  354. {
  355. return m.Skills[SkillName.MagicResist].Value;
  356. }
  357.  
  358. public virtual double GetDamageScalar(Mobile target)
  359. {
  360. double scalar = 1.0;
  361.  
  362. if (!Core.AOS) //EvalInt stuff for AoS is handled elsewhere
  363. {
  364. double casterEI = m_Caster.Skills[DamageSkill].Value;
  365. double targetRS = target.Skills[SkillName.MagicResist].Value;
  366.  
  367. /*
  368. if( Core.AOS )
  369. targetRS = 0;
  370. */
  371.  
  372. //m_Caster.CheckSkill( DamageSkill, 0.0, 120.0 );
  373.  
  374. if (casterEI > targetRS)
  375. {
  376. scalar = (1.0 + ((casterEI - targetRS) / 500.0));
  377. }
  378. else
  379. {
  380. scalar = (1.0 + ((casterEI - targetRS) / 200.0));
  381. }
  382.  
  383. // magery damage bonus, -25% at 0 skill, +0% at 100 skill, +5% at 120 skill
  384. scalar += (m_Caster.Skills[CastSkill].Value - 100.0) / 400.0;
  385.  
  386. if (!target.Player && !target.Body.IsHuman /*&& !Core.AOS*/)
  387. {
  388. scalar *= 2.0; // Double magery damage to monsters/animals if not AOS
  389. }
  390. }
  391.  
  392. if (target is BaseCreature)
  393. {
  394. ((BaseCreature)target).AlterDamageScalarFrom(m_Caster, ref scalar);
  395. }
  396.  
  397. if (m_Caster is BaseCreature)
  398. {
  399. ((BaseCreature)m_Caster).AlterDamageScalarTo(target, ref scalar);
  400. }
  401.  
  402. if (Core.SE)
  403. {
  404. scalar *= GetSlayerDamageScalar(target);
  405. }
  406.  
  407. target.Region.SpellDamageScalar(m_Caster, target, ref scalar);
  408.  
  409. if (Evasion.CheckSpellEvasion(target)) //Only single target spells an be evaded
  410. {
  411. scalar = 0;
  412. }
  413.  
  414. return scalar;
  415. }
  416.  
  417. public virtual double GetSlayerDamageScalar(Mobile defender)
  418. {
  419. Spellbook atkBook = Spellbook.FindEquippedSpellbook(m_Caster);
  420.  
  421. double scalar = 1.0;
  422. if (atkBook != null)
  423. {
  424. SlayerEntry atkSlayer = SlayerGroup.GetEntryByName(atkBook.Slayer);
  425. SlayerEntry atkSlayer2 = SlayerGroup.GetEntryByName(atkBook.Slayer2);
  426.  
  427. if (atkSlayer != null && atkSlayer.Slays(defender) || atkSlayer2 != null && atkSlayer2.Slays(defender))
  428. {
  429. defender.FixedEffect(0x37B9, 10, 5); //TODO: Confirm this displays on OSIs
  430. scalar = 2.0;
  431. }
  432.  
  433. TransformContext context = TransformationSpellHelper.GetContext(defender);
  434.  
  435. if ((atkBook.Slayer == SlayerName.Silver || atkBook.Slayer2 == SlayerName.Silver) && context != null &&
  436. context.Type != typeof(HorrificBeastSpell))
  437. {
  438. scalar += .25; // Every necromancer transformation other than horrific beast take an additional 25% damage
  439. }
  440.  
  441. if (scalar != 1.0)
  442. {
  443. return scalar;
  444. }
  445. }
  446.  
  447. ISlayer defISlayer = Spellbook.FindEquippedSpellbook(defender);
  448.  
  449. if (defISlayer == null)
  450. {
  451. defISlayer = defender.Weapon as ISlayer;
  452. }
  453.  
  454. if (defISlayer != null)
  455. {
  456. SlayerEntry defSlayer = SlayerGroup.GetEntryByName(defISlayer.Slayer);
  457. SlayerEntry defSlayer2 = SlayerGroup.GetEntryByName(defISlayer.Slayer2);
  458.  
  459. if (defSlayer != null && defSlayer.Group.OppositionSuperSlays(m_Caster) ||
  460. defSlayer2 != null && defSlayer2.Group.OppositionSuperSlays(m_Caster))
  461. {
  462. scalar = 2.0;
  463. }
  464. }
  465.  
  466. return scalar;
  467. }
  468.  
  469. public virtual void DoFizzle()
  470. {
  471. m_Caster.LocalOverheadMessage(MessageType.Regular, 0x3B2, 502632); // The spell fizzles.
  472.  
  473. if (m_Caster.Player)
  474. {
  475. if (Core.AOS)
  476. {
  477. m_Caster.FixedParticles(0x3735, 1, 30, 9503, EffectLayer.Waist);
  478. }
  479. else
  480. {
  481. m_Caster.FixedEffect(0x3735, 6, 30);
  482. }
  483.  
  484. m_Caster.PlaySound(0x5C);
  485. }
  486. }
  487.  
  488. private CastTimer m_CastTimer;
  489. private AnimTimer m_AnimTimer;
  490.  
  491. public void Disturb(DisturbType type)
  492. {
  493. Disturb(type, true, false);
  494. }
  495.  
  496. public virtual bool CheckDisturb(DisturbType type, bool firstCircle, bool resistable)
  497. {
  498. if (resistable && m_Scroll is BaseWand)
  499. {
  500. return false;
  501. }
  502.  
  503. return true;
  504. }
  505.  
  506. public void Disturb(DisturbType type, bool firstCircle, bool resistable)
  507. {
  508. if (!CheckDisturb(type, firstCircle, resistable))
  509. {
  510. return;
  511. }
  512.  
  513. if (m_State == SpellState.Casting)
  514. {
  515. if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
  516. {
  517. return;
  518. }
  519.  
  520. m_State = SpellState.None;
  521. m_Caster.Spell = null;
  522.  
  523. OnDisturb(type, true);
  524.  
  525. if (m_CastTimer != null)
  526. {
  527. m_CastTimer.Stop();
  528. }
  529.  
  530. if (m_AnimTimer != null)
  531. {
  532. m_AnimTimer.Stop();
  533. }
  534.  
  535. //if (Core.AOS && m_Caster.Player && type == DisturbType.Hurt)
  536. //{
  537. // DoHurtFizzle();
  538. //}
  539.  
  540. //m_Caster.NextSpellTime = Core.TickCount + (int)GetDisturbRecovery().TotalMilliseconds;
  541. }
  542. else if (m_State == SpellState.Sequencing)
  543. {
  544. if (!firstCircle && !Core.AOS && this is MagerySpell && ((MagerySpell)this).Circle == SpellCircle.First)
  545. {
  546. return;
  547. }
  548.  
  549. m_State = SpellState.None;
  550. m_Caster.Spell = null;
  551.  
  552. OnDisturb(type, false);
  553.  
  554. Target.Cancel(m_Caster);
  555.  
  556. if (Core.AOS && m_Caster.Player && type == DisturbType.Hurt)
  557. {
  558. DoHurtFizzle();
  559. }
  560. }
  561. }
  562.  
  563. public virtual void DoHurtFizzle()
  564. {
  565. m_Caster.FixedEffect(0x3735, 6, 30);
  566. m_Caster.PlaySound(0x5C);
  567. }
  568.  
  569. public virtual void OnDisturb(DisturbType type, bool message)
  570. {
  571. if (message)
  572. {
  573. m_Caster.SendLocalizedMessage(500641); // Your concentration is disturbed, thus ruining thy spell.
  574. }
  575. }
  576.  
  577. public virtual bool CheckCast()
  578. {
  579. return true;
  580. }
  581.  
  582. public virtual void SayMantra()
  583. {
  584. if (m_Scroll is BaseWand)
  585. {
  586. return;
  587. }
  588.  
  589. if (m_Info.Mantra != null && m_Info.Mantra.Length > 0 && m_Caster.Player)
  590. {
  591. m_Caster.PublicOverheadMessage(MessageType.Spell, m_Caster.SpeechHue, true, m_Info.Mantra, false);
  592. }
  593. }
  594.  
  595. public virtual bool BlockedByHorrificBeast { get { return true; } }
  596. public virtual bool BlockedByAnimalForm { get { return true; } }
  597. public virtual bool BlocksMovement { get { return true; } }
  598.  
  599. public virtual bool CheckNextSpellTime { get { return !(m_Scroll is BaseWand); } }
  600.  
  601. public bool Cast()
  602. {
  603. m_StartCastTime = Core.TickCount;
  604.  
  605. if (Core.AOS && m_Caster.Spell is Spell && ((Spell)m_Caster.Spell).State == SpellState.Sequencing)
  606. {
  607. ((Spell)m_Caster.Spell).Disturb(DisturbType.NewCast);
  608. }
  609.  
  610. if (!m_Caster.CheckAlive())
  611. {
  612. return false;
  613. }
  614. else if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).Peaced)
  615. {
  616. m_Caster.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed.
  617. }
  618. else if (m_Scroll is BaseWand && m_Caster.Spell != null && m_Caster.Spell.IsCasting)
  619. {
  620. m_Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen.
  621. }
  622. else if (m_Caster.Spell != null && m_Caster.Spell.IsCasting)
  623. {
  624. m_Caster.SendLocalizedMessage(502642); // You are already casting a spell.
  625. }
  626. else if (BlockedByHorrificBeast && TransformationSpellHelper.UnderTransformation(m_Caster, typeof(HorrificBeastSpell)) ||
  627. (BlockedByAnimalForm && AnimalForm.UnderTransformation(m_Caster)))
  628. {
  629. m_Caster.SendLocalizedMessage(1061091); // You cannot cast that spell in this form.
  630. }
  631. else if (!(m_Scroll is BaseWand) && (m_Caster.Paralyzed || m_Caster.Frozen))
  632. {
  633. m_Caster.SendLocalizedMessage(502643); // You can not cast a spell while frozen.
  634. //}
  635. //else if (CheckNextSpellTime && Core.TickCount - m_Caster.NextSpellTime < 0)
  636. //{
  637. // m_Caster.SendLocalizedMessage(502644); // You have not yet recovered from casting a spell.
  638. }
  639. else if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).PeacedUntil > DateTime.UtcNow)
  640. {
  641. m_Caster.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed.
  642. }
  643. #region Dueling
  644. else if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).DuelContext != null &&
  645. !((PlayerMobile)m_Caster).DuelContext.AllowSpellCast(m_Caster, this))
  646. { }
  647. #endregion
  648.  
  649. else if (m_Caster.Mana >= ScaleMana(GetMana()))
  650. {
  651. #region Stygian Abyss
  652. if (m_Caster.Race == Race.Gargoyle && m_Caster.Flying)
  653. {
  654. var tiles = Caster.Map.Tiles.GetStaticTiles(Caster.X, Caster.Y, true);
  655. ItemData itemData;
  656. bool cancast = true;
  657.  
  658. for (int i = 0; i < tiles.Length && cancast; ++i)
  659. {
  660. itemData = TileData.ItemTable[tiles[i].ID & TileData.MaxItemValue];
  661. cancast = !(itemData.Name == "hover over");
  662. }
  663.  
  664. if (!cancast)
  665. {
  666. if (m_Caster.IsPlayer())
  667. {
  668. m_Caster.SendLocalizedMessage(1113750); // You may not cast spells while flying over such precarious terrain.
  669. return false;
  670. }
  671. else
  672. {
  673. m_Caster.SendMessage("Your staff level allows you to cast while flying over precarious terrain.");
  674. }
  675. }
  676. }
  677. #endregion
  678.  
  679. if (m_Caster.Spell == null && m_Caster.CheckSpellCast(this) && CheckCast() &&
  680. m_Caster.Region.OnBeginSpellCast(m_Caster, this))
  681. {
  682. m_State = SpellState.Casting;
  683. m_Caster.Spell = this;
  684.  
  685. if (!(m_Scroll is BaseWand) && RevealOnCast)
  686. {
  687. m_Caster.RevealingAction();
  688. }
  689.  
  690. SayMantra();
  691.  
  692. TimeSpan castDelay = GetCastDelay();
  693.  
  694. if (ShowHandMovement && (m_Caster.Body.IsHuman || (m_Caster.Player && m_Caster.Body.IsMonster)))
  695. {
  696. int count = (int)Math.Ceiling(castDelay.TotalSeconds / AnimateDelay.TotalSeconds);
  697.  
  698. if (count != 0)
  699. {
  700. m_AnimTimer = new AnimTimer(this, count);
  701. m_AnimTimer.Start();
  702. }
  703.  
  704. if (m_Info.LeftHandEffect > 0)
  705. {
  706. Caster.FixedParticles(0, 10, 5, m_Info.LeftHandEffect, EffectLayer.LeftHand);
  707. }
  708.  
  709. if (m_Info.RightHandEffect > 0)
  710. {
  711. Caster.FixedParticles(0, 10, 5, m_Info.RightHandEffect, EffectLayer.RightHand);
  712. }
  713. }
  714.  
  715. if (ClearHandsOnCast)
  716. {
  717. m_Caster.ClearHands();
  718. }
  719.  
  720. if (Core.ML)
  721. {
  722. WeaponAbility.ClearCurrentAbility(m_Caster);
  723. }
  724.  
  725. m_CastTimer = new CastTimer(this, castDelay);
  726. //m_CastTimer.Start();
  727.  
  728. OnBeginCast();
  729.  
  730. if (castDelay > TimeSpan.Zero)
  731. {
  732. m_CastTimer.Start();
  733. }
  734. else
  735. {
  736. m_CastTimer.Tick();
  737. }
  738.  
  739. return true;
  740. }
  741. else
  742. {
  743. return false;
  744. }
  745. }
  746. else
  747. {
  748. m_Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana
  749. }
  750.  
  751. return false;
  752. }
  753.  
  754. public abstract void OnCast();
  755.  
  756. public virtual void OnBeginCast()
  757. { }
  758.  
  759. public virtual void GetCastSkills(out double min, out double max)
  760. {
  761. min = max = 0; //Intended but not required for overriding.
  762. }
  763.  
  764. public virtual bool CheckFizzle()
  765. {
  766. if (m_Scroll is BaseWand)
  767. {
  768. return true;
  769. }
  770.  
  771. double minSkill, maxSkill;
  772.  
  773. GetCastSkills(out minSkill, out maxSkill);
  774.  
  775. if (DamageSkill != CastSkill)
  776. {
  777. Caster.CheckSkill(DamageSkill, 0.0, Caster.Skills[DamageSkill].Cap);
  778. }
  779.  
  780. return Caster.CheckSkill(CastSkill, minSkill, maxSkill);
  781. }
  782.  
  783. public abstract int GetMana();
  784.  
  785. public virtual int ScaleMana(int mana)
  786. {
  787. double scalar = 1.0;
  788.  
  789. if (!MindRotSpell.GetMindRotScalar(Caster, ref scalar))
  790. {
  791. scalar = 1.0;
  792. }
  793.  
  794. // Lower Mana Cost = 40%
  795. int lmc = AosAttributes.GetValue(m_Caster, AosAttribute.LowerManaCost);
  796. if (lmc > 40)
  797. {
  798. lmc = 40;
  799. }
  800.  
  801. scalar -= (double)lmc / 100;
  802.  
  803. return (int)(mana * scalar);
  804. }
  805.  
  806. public virtual TimeSpan GetDisturbRecovery()
  807. {
  808. if (Core.AOS)
  809. {
  810. return TimeSpan.Zero;
  811. }
  812.  
  813. double delay = 1.0 - Math.Sqrt((Core.TickCount - m_StartCastTime) / 1000.0 / GetCastDelay().TotalSeconds);
  814.  
  815. if (delay < 0.2)
  816. {
  817. delay = 0.2;
  818. }
  819.  
  820. return TimeSpan.FromSeconds(delay);
  821. }
  822.  
  823. public virtual int CastRecoveryBase { get { return 6; } }
  824. public virtual int CastRecoveryFastScalar { get { return 1; } }
  825. public virtual int CastRecoveryPerSecond { get { return 4; } }
  826. public virtual int CastRecoveryMinimum { get { return 0; } }
  827.  
  828. public virtual TimeSpan GetCastRecovery()
  829. {
  830. if (!Core.AOS)
  831. {
  832. return NextSpellDelay;
  833. }
  834.  
  835. int fcr = AosAttributes.GetValue(m_Caster, AosAttribute.CastRecovery);
  836.  
  837. fcr -= ThunderstormSpell.GetCastRecoveryMalus(m_Caster);
  838.  
  839. int fcrDelay = -(CastRecoveryFastScalar * fcr);
  840.  
  841. int delay = CastRecoveryBase + fcrDelay;
  842.  
  843. if (delay < CastRecoveryMinimum)
  844. {
  845. delay = CastRecoveryMinimum;
  846. }
  847.  
  848. return TimeSpan.FromSeconds((double)delay / CastRecoveryPerSecond);
  849. }
  850.  
  851. public abstract TimeSpan CastDelayBase { get; }
  852.  
  853. public virtual double CastDelayFastScalar { get { return 1; } }
  854. public virtual double CastDelaySecondsPerTick { get { return 0.25; } }
  855. public virtual TimeSpan CastDelayMinimum { get { return TimeSpan.FromSeconds(0.25); } }
  856.  
  857. //public virtual int CastDelayBase{ get{ return 3; } }
  858. //public virtual int CastDelayFastScalar{ get{ return 1; } }
  859. //public virtual int CastDelayPerSecond{ get{ return 4; } }
  860. //public virtual int CastDelayMinimum{ get{ return 1; } }
  861.  
  862. public virtual TimeSpan GetCastDelay()
  863. {
  864. if (m_Scroll is BaseWand)
  865. {
  866. return Core.ML ? CastDelayBase : TimeSpan.Zero; // TODO: Should FC apply to wands?
  867. }
  868.  
  869. // Faster casting cap of 2 (if not using the protection spell)
  870. // Faster casting cap of 0 (if using the protection spell)
  871. // Paladin spells are subject to a faster casting cap of 4
  872. // Paladins with magery of 70.0 or above are subject to a faster casting cap of 2
  873. int fcMax = 5;
  874.  
  875. if (CastSkill == SkillName.Magery || CastSkill == SkillName.Necromancy ||
  876. (CastSkill == SkillName.Chivalry && m_Caster.Skills[SkillName.Magery].Value >= 70.0))
  877. {
  878. fcMax = 5;
  879. }
  880.  
  881. int fc = AosAttributes.GetValue(m_Caster, AosAttribute.CastSpeed);
  882.  
  883. if (fc > fcMax)
  884. {
  885. fc = fcMax;
  886. }
  887.  
  888. if (ProtectionSpell.Registry.Contains(m_Caster))
  889. {
  890. fc -= 5;
  891. }
  892.  
  893. if (EssenceOfWindSpell.IsDebuffed(m_Caster))
  894. {
  895. fc -= EssenceOfWindSpell.GetFCMalus(m_Caster);
  896. }
  897.  
  898. TimeSpan baseDelay = CastDelayBase;
  899.  
  900. TimeSpan fcDelay = TimeSpan.FromSeconds(-(CastDelayFastScalar * fc * CastDelaySecondsPerTick));
  901.  
  902. //int delay = CastDelayBase + circleDelay + fcDelay;
  903. TimeSpan delay = baseDelay + fcDelay;
  904.  
  905. if (delay < CastDelayMinimum)
  906. {
  907. delay = CastDelayMinimum;
  908. }
  909.  
  910. #region Mondain's Legacy
  911. if (DreadHorn.IsUnderInfluence(m_Caster))
  912. {
  913. delay.Add(delay);
  914. }
  915. #endregion
  916.  
  917. //return TimeSpan.FromSeconds( (double)delay / CastDelayPerSecond );
  918. return delay;
  919. }
  920.  
  921. public virtual void FinishSequence()
  922. {
  923. m_State = SpellState.None;
  924.  
  925. if (m_Caster.Spell == this)
  926. {
  927. m_Caster.Spell = null;
  928. }
  929. }
  930.  
  931. public virtual int ComputeKarmaAward()
  932. {
  933. return 0;
  934. }
  935.  
  936. public virtual bool CheckSequence()
  937. {
  938. int mana = ScaleMana(GetMana());
  939.  
  940. if (m_Caster.Deleted || !m_Caster.Alive || m_Caster.Spell != this || m_State != SpellState.Sequencing)
  941. {
  942. //DoFizzle();
  943. }
  944. else if (m_Scroll != null && !(m_Scroll is Runebook) &&
  945. (m_Scroll.Amount <= 0 || m_Scroll.Deleted || m_Scroll.RootParent != m_Caster ||
  946. (m_Scroll is BaseWand && (((BaseWand)m_Scroll).Charges <= 0 || m_Scroll.Parent != m_Caster))))
  947. {
  948. //DoFizzle();
  949. }
  950. else if (!ConsumeReagents())
  951. {
  952. m_Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502630); // More reagents are needed for this spell.
  953. }
  954. else if (m_Caster.Mana < mana)
  955. {
  956. m_Caster.LocalOverheadMessage(MessageType.Regular, 0x22, 502625); // Insufficient mana for this spell.
  957. }
  958. else if (Core.AOS && (m_Caster.Frozen || m_Caster.Paralyzed))
  959. {
  960. m_Caster.SendLocalizedMessage(502646); // You cannot cast a spell while frozen.
  961. //DoFizzle();
  962. }
  963. else if (m_Caster is PlayerMobile && ((PlayerMobile)m_Caster).PeacedUntil > DateTime.UtcNow)
  964. {
  965. m_Caster.SendLocalizedMessage(1072060); // You cannot cast a spell while calmed.
  966. //DoFizzle();
  967. }
  968. else if (CheckFizzle())
  969. {
  970. m_Caster.Mana -= mana;
  971.  
  972. if (m_Scroll is SpellScroll)
  973. {
  974. m_Scroll.Consume();
  975. }
  976. #region SA
  977. else if (m_Scroll is SpellStone)
  978. {
  979. // The SpellScroll check above isn't removing the SpellStones for some reason.
  980. m_Scroll.Delete();
  981. }
  982. #endregion
  983.  
  984. else if (m_Scroll is BaseWand)
  985. {
  986. ((BaseWand)m_Scroll).ConsumeCharge(m_Caster);
  987. m_Caster.RevealingAction();
  988. }
  989.  
  990. if (m_Scroll is BaseWand)
  991. {
  992. bool m = m_Scroll.Movable;
  993.  
  994. m_Scroll.Movable = false;
  995.  
  996. if (ClearHandsOnCast)
  997. {
  998. m_Caster.ClearHands();
  999. }
  1000.  
  1001. m_Scroll.Movable = m;
  1002. }
  1003. else
  1004. {
  1005. if (ClearHandsOnCast)
  1006. {
  1007. m_Caster.ClearHands();
  1008. }
  1009. }
  1010.  
  1011. int karma = ComputeKarmaAward();
  1012.  
  1013. if (karma != 0)
  1014. {
  1015. Titles.AwardKarma(Caster, karma, true);
  1016. }
  1017.  
  1018. if (TransformationSpellHelper.UnderTransformation(m_Caster, typeof(VampiricEmbraceSpell)))
  1019. {
  1020. bool garlic = false;
  1021.  
  1022. for (int i = 0; !garlic && i < m_Info.Reagents.Length; ++i)
  1023. {
  1024. garlic = (m_Info.Reagents[i] == Reagent.Garlic);
  1025. }
  1026.  
  1027. if (garlic)
  1028. {
  1029. m_Caster.SendLocalizedMessage(1061651); // The garlic burns you!
  1030. AOS.Damage(m_Caster, Utility.RandomMinMax(17, 23), 100, 0, 0, 0, 0);
  1031. }
  1032. }
  1033.  
  1034. return true;
  1035. }
  1036. else
  1037. {
  1038. //DoFizzle();
  1039. }
  1040.  
  1041. return false;
  1042. }
  1043.  
  1044. public bool CheckBSequence(Mobile target)
  1045. {
  1046. return CheckBSequence(target, false);
  1047. }
  1048.  
  1049. public bool CheckBSequence(Mobile target, bool allowDead)
  1050. {
  1051. if (!target.Alive && !allowDead)
  1052. {
  1053. m_Caster.SendLocalizedMessage(501857); // This spell won't work on that!
  1054. return false;
  1055. }
  1056. else if (Caster.CanBeBeneficial(target, true, allowDead) && CheckSequence())
  1057. {
  1058. Caster.DoBeneficial(target);
  1059. return true;
  1060. }
  1061. else
  1062. {
  1063. return false;
  1064. }
  1065. }
  1066.  
  1067. public bool CheckHSequence(Mobile target)
  1068. {
  1069. if (!target.Alive)
  1070. {
  1071. m_Caster.SendLocalizedMessage(501857); // This spell won't work on that!
  1072. return false;
  1073. }
  1074. else if (Caster.CanBeHarmful(target) && CheckSequence())
  1075. {
  1076. Caster.DoHarmful(target);
  1077. return true;
  1078. }
  1079. else
  1080. {
  1081. return false;
  1082. }
  1083. }
  1084.  
  1085. private class AnimTimer : Timer
  1086. {
  1087. private readonly Spell m_Spell;
  1088.  
  1089. public AnimTimer(Spell spell, int count)
  1090. : base(TimeSpan.Zero, AnimateDelay, count)
  1091. {
  1092. m_Spell = spell;
  1093.  
  1094. Priority = TimerPriority.FiftyMS;
  1095. }
  1096.  
  1097. protected override void OnTick()
  1098. {
  1099. if (m_Spell.State != SpellState.Casting || m_Spell.m_Caster.Spell != m_Spell)
  1100. {
  1101. Stop();
  1102. return;
  1103. }
  1104.  
  1105. if (!m_Spell.Caster.Mounted && m_Spell.m_Info.Action >= 0)
  1106. {
  1107. if (m_Spell.Caster.Body.IsHuman)
  1108. {
  1109. m_Spell.Caster.Animate(m_Spell.m_Info.Action, 7, 1, true, false, 0);
  1110. }
  1111. else if (m_Spell.Caster.Player && m_Spell.Caster.Body.IsMonster)
  1112. {
  1113. m_Spell.Caster.Animate(12, 7, 1, true, false, 0);
  1114. }
  1115. }
  1116.  
  1117. if (!Running)
  1118. {
  1119. m_Spell.m_AnimTimer = null;
  1120. }
  1121. }
  1122. }
  1123.  
  1124. private class CastTimer : Timer
  1125. {
  1126. private readonly Spell m_Spell;
  1127.  
  1128. public CastTimer(Spell spell, TimeSpan castDelay)
  1129. : base(castDelay)
  1130. {
  1131. m_Spell = spell;
  1132.  
  1133. Priority = TimerPriority.TwentyFiveMS;
  1134. }
  1135.  
  1136. protected override void OnTick()
  1137. {
  1138. if (m_Spell == null || m_Spell.m_Caster == null)
  1139. {
  1140. return;
  1141. }
  1142. else if (m_Spell.m_State == SpellState.Casting && m_Spell.m_Caster.Spell == m_Spell)
  1143. {
  1144. m_Spell.m_State = SpellState.Sequencing;
  1145. m_Spell.m_CastTimer = null;
  1146. m_Spell.m_Caster.OnSpellCast(m_Spell);
  1147. if (m_Spell.m_Caster.Region != null)
  1148. {
  1149. m_Spell.m_Caster.Region.OnSpellCast(m_Spell.m_Caster, m_Spell);
  1150. }
  1151. m_Spell.m_Caster.NextSpellTime = Core.TickCount + (int)m_Spell.GetCastRecovery().TotalMilliseconds;
  1152. // Spell.NextSpellDelay;
  1153.  
  1154. Target originalTarget = m_Spell.m_Caster.Target;
  1155.  
  1156. m_Spell.OnCast();
  1157.  
  1158. if (m_Spell.m_Caster.Player && m_Spell.m_Caster.Target != originalTarget && m_Spell.Caster.Target != null)
  1159. {
  1160. m_Spell.m_Caster.Target.BeginTimeout(m_Spell.m_Caster, TimeSpan.FromSeconds(30.0));
  1161. }
  1162.  
  1163. m_Spell.m_CastTimer = null;
  1164. }
  1165. }
  1166.  
  1167. public void Tick()
  1168. {
  1169. OnTick();
  1170. }
  1171. }
  1172. }
  1173. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement