using System; using System.Collections.Generic; using System.Linq; using Server.Network; using Server.Spells; using Server.Targeting; namespace Server.Items { public class Firebomb : Item { private Timer m_Timer; private int m_Ticks = 0; private Mobile m_LitBy; private List m_Users; [Constructable] public Firebomb() : this(0x99B) { } [Constructable] public Firebomb(int itemID) : base(itemID) { //Name = "a firebomb"; Weight = 2.0; Hue = 1260; } public Firebomb(Serial serial) : base(serial) { } public override void Serialize(GenericWriter writer) { base.Serialize(writer); writer.WriteEncodedInt((int)0); // version } public override void Deserialize(GenericReader reader) { base.Deserialize(reader); int version = reader.ReadEncodedInt(); } public override void OnDoubleClick(Mobile from) { if (!IsChildOf(from.Backpack)) { from.SendLocalizedMessage(1042001); // That must be in your pack for you to use it. return; } if (Core.AOS && (from.Paralyzed || from.Frozen || (from.Spell != null && from.Spell.IsCasting))) { // to prevent exploiting for pvp from.SendLocalizedMessage(1075857); // You cannot use that while paralyzed. return; } if (m_Timer == null) { m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(1), new TimerCallback(OnFirebombTimerTick)); m_LitBy = from; from.SendLocalizedMessage(1060582); // You light the firebomb. Throw it now! } else from.SendLocalizedMessage(1060581); // You've already lit it! Better throw it now! if (m_Users == null) m_Users = new List(); if (!m_Users.Contains(from)) m_Users.Add(from); from.Target = new ThrowTarget(this); } private void OnFirebombTimerTick() { if (Deleted) { m_Timer.Stop(); return; } if (Map == Map.Internal && HeldBy == null) return; switch ( m_Ticks ) { case 0: case 1: case 2: { ++m_Ticks; if (HeldBy != null) HeldBy.PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); else if (RootParent == null) PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); else if (RootParent is Mobile) ((Mobile)RootParent).PublicOverheadMessage(MessageType.Regular, 957, false, m_Ticks.ToString()); break; } default: { if (HeldBy != null) HeldBy.DropHolding(); if (m_Users != null) { foreach (Mobile m in m_Users) { ThrowTarget targ = m.Target as ThrowTarget; if (targ != null && targ.Bomb == this) Target.Cancel(m); } m_Users.Clear(); m_Users = null; } if (RootParent is Mobile) { Mobile parent = (Mobile)RootParent; parent.SendLocalizedMessage(1060583); // The firebomb explodes in your hand! AOS.Damage(parent, Utility.Random(3) + 4, 0, 100, 0, 0, 0); } else if (RootParent == null) { var targets = GetTargets(); foreach (var victim in targets) { if (m_LitBy != null) m_LitBy.DoHarmful(victim); AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0); } new FirebombField(m_LitBy, targets.ToList()).MoveToWorld(Location, Map); } m_Timer.Stop(); Delete(); break; } } } private IEnumerable GetTargets() { if (Map == null) yield break; IPooledEnumerable eable = Map.GetMobilesInRange(Location, 1); foreach (Mobile m in eable) { if (m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, m) && m_LitBy.CanBeHarmful(m, false))) { yield return m; } } eable.Free(); } private void OnFirebombTarget(Mobile from, object obj) { if (Deleted || Map == Map.Internal || !IsChildOf(from.Backpack)) return; IPoint3D p = obj as IPoint3D; if (p == null) return; SpellHelper.GetSurfaceTop(ref p); from.RevealingAction(); IEntity to; if (p is Mobile) to = (Mobile)p; else to = new Entity(Serial.Zero, new Point3D(p), Map); Effects.SendMovingEffect(from, to, ItemID, 7, 0, false, false, Hue, 0); Timer.DelayCall(TimeSpan.FromSeconds(1.0), new TimerStateCallback(FirebombReposition_OnTick), new object[] { p, Map }); Internalize(); } private void FirebombReposition_OnTick(object state) { if (Deleted) return; object[] states = (object[])state; IPoint3D p = (IPoint3D)states[0]; Map map = (Map)states[1]; MoveToWorld(new Point3D(p), map); } private class ThrowTarget : Target { private readonly Firebomb m_Bomb; public ThrowTarget(Firebomb bomb) : base(12, true, TargetFlags.None) { m_Bomb = bomb; } public Firebomb Bomb { get { return m_Bomb; } } protected override void OnTarget(Mobile from, object targeted) { m_Bomb.OnFirebombTarget(from, targeted); } } } public class FirebombField : Item { private readonly List m_Burning; private readonly Timer m_Timer; private readonly Mobile m_LitBy; private readonly DateTime m_Expire; public FirebombField(Mobile litBy, List toDamage) : base(0x376A) { Movable = false; m_LitBy = litBy; m_Expire = DateTime.UtcNow + TimeSpan.FromSeconds(10); m_Burning = toDamage; m_Timer = Timer.DelayCall(TimeSpan.FromSeconds(1.0), TimeSpan.FromSeconds(1.0), new TimerCallback(OnFirebombFieldTimerTick)); } public FirebombField(Serial serial) : base(serial) { } public override void Serialize(GenericWriter writer) { // Don't serialize these... } public override void Deserialize(GenericReader reader) { } public override bool OnMoveOver(Mobile m) { if (ItemID == 0x398C && m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, m) && m_LitBy.CanBeHarmful(m, false))) { if (m_LitBy != null) m_LitBy.DoHarmful(m); AOS.Damage(m, m_LitBy, 2, 0, 100, 0, 0, 0); m.PlaySound(0x208); if (!m_Burning.Contains(m)) m_Burning.Add(m); } return true; } private void OnFirebombFieldTimerTick() { if (Deleted) { m_Timer.Stop(); return; } if (ItemID == 0x376A) { ItemID = 0x398C; return; } Mobile victim; for (int i = 0; i < m_Burning.Count;) { victim = m_Burning[i]; if (victim.Location == Location && victim.Map == Map && (m_LitBy == null || (SpellHelper.ValidIndirectTarget(m_LitBy, victim) && m_LitBy.CanBeHarmful(victim, false)))) { if (m_LitBy != null) m_LitBy.DoHarmful(victim); AOS.Damage(victim, m_LitBy, Utility.Random(3) + 4, 0, 100, 0, 0, 0); ++i; } else m_Burning.RemoveAt(i); } if (DateTime.UtcNow >= m_Expire) { m_Timer.Stop(); Delete(); ColUtility.Free(m_Burning); } } } }