public virtual void Shoot(object cannoneer) { AmmoInfo ammo = AmmoInfo.GetAmmoInfo(AmmoType); if (ammo == null) { return; } Mobile shooter = null; if (cannoneer is Mobile) { shooter = (Mobile)cannoneer; } if (shooter != null && shooter.Player) { m_Hits -= Utility.RandomMinMax(0, 4); } DoShootEffects(); AddAction(shooter, 1149691); //Fired successfully. int xOffset = 0; int yOffset = 0; int currentRange = 0; Point3D pnt = this.Location; Map map = this.Map; Direction d = GetFacing(); switch (d) { case Direction.North: xOffset = 0; yOffset = -1; break; case Direction.South: xOffset = 0; yOffset = 1; break; case Direction.West: xOffset = -1; yOffset = 0; break; case Direction.East: xOffset = 1; yOffset = 0; break; } int xo = xOffset; int yo = yOffset; int lateralOffset = 1; int latDist = ammo.LateralOffset; int range = Range; bool hit = false; while (currentRange++ <= range) { xOffset = xo; yOffset = yo; if (currentRange % latDist == 0) { lateralOffset++; } TimeSpan delay = TimeSpan.FromSeconds((double)currentRange / 10.0); switch (AmmoType) { case AmmunitionType.Empty: break; case AmmunitionType.Cannonball: case AmmunitionType.FrostCannonball: case AmmunitionType.FlameCannonball: { Point3D newPoint = pnt; List <IEntity> list = new List <IEntity>(); List <IDamageable> damageables = new List <IDamageable>(); for (int i = -lateralOffset; i <= lateralOffset; i++) { if (xOffset == 0) { newPoint = new Point3D(pnt.X + (xOffset + i), pnt.Y + (yOffset * currentRange), pnt.Z); } else { newPoint = new Point3D(pnt.X + (xOffset * currentRange), pnt.Y + (yOffset + i), pnt.Z); } BaseGalleon g = FindValidBoatTarget(newPoint, map, ammo); if (g != null && g != Galleon && g.IsEnemy(Galleon)) { list.Add(g); } damageables.AddRange(FindDamageables(shooter, newPoint, map, false, false, false, true, true)); } foreach (var m in damageables) { list.Add(m); } if (list.Count > 0) { IEntity toHit = list[Utility.Random(list.Count)]; if (toHit is Mobile) { Timer.DelayCall(delay, new TimerStateCallback(OnMobileHit), new object[] { (Mobile)toHit, newPoint, ammo, shooter }); hit = true; } else if (toHit is BaseGalleon) { Timer.DelayCall(delay, new TimerStateCallback(OnShipHit), new object[] { (BaseGalleon)toHit, newPoint, ammo, shooter }); hit = true; } else if (toHit is DamageableItem) { Timer.DelayCall(delay, new TimerStateCallback(OnDamageableItemHit), new object[] { (DamageableItem)toHit, newPoint, ammo, shooter }); hit = true; } } } break; case AmmunitionType.Grapeshot: { Point3D newPoint = pnt; List <Mobile> mobiles = new List <Mobile>(); for (int i = -lateralOffset; i <= lateralOffset; i++) { if (xOffset == 0) { newPoint = new Point3D(pnt.X + (xOffset + i), pnt.Y + (yOffset * currentRange), pnt.Z); } else { newPoint = new Point3D(pnt.X + (xOffset * currentRange), pnt.Y + (yOffset + i), pnt.Z); } mobiles.AddRange(FindDamageables(shooter, newPoint, map, true, true, true, true, false).OfType <Mobile>()); } if (mobiles.Count > 0) { Timer.DelayCall(delay, new TimerStateCallback(OnMobileHit), new object[] { mobiles, newPoint, ammo, shooter }); hit = true; } } break; } if (hit && ammo.SingleTarget) { break; } } ClearCannon(); InvalidateDamageState(); if (shooter != null) { ResendGump(shooter); } }