public void ResolveCannon(ShipCannon shipCannon, Mobile from, Point3D targetLocation, Map map, bool hit) { if (hit) { ResolveCannonHit(from, targetLocation); } else { Splash(targetLocation, map); } }
public static void PlaceShipCannon(BaseBoat boat, Point3D point, CannonType cannonType, CannonPosition cannonPosition) { if (boat == null) { return; } ShipCannon shipCannon = new ShipCannon(); shipCannon.Visible = false; shipCannon.m_Boat = boat; shipCannon.m_CannonType = cannonType; shipCannon.m_CannonPosition = cannonPosition; shipCannon.m_xOffset = point.X; shipCannon.m_yOffset = point.Y; shipCannon.m_zOffset = point.Z; Point3D cannonLocation = boat.GetRotatedLocation(point.X, point.Y, 0); shipCannon.MoveToWorld(new Point3D(boat.Location.X + cannonLocation.X, boat.Location.Y + cannonLocation.Y, boat.Location.Z + cannonLocation.Z), boat.Map); shipCannon.BoatFacingChange(boat.Facing); shipCannon.Z = boat.Location.Z + cannonLocation.Z + shipCannon.GetAdjustedCannonZOffset(); shipCannon.Hue = boat.CannonHue; if (boat.MobileControlType != MobileControlType.Player) { shipCannon.Ammunition = shipCannon.GetMaxAmmunition(); } shipCannon.Visible = true; boat.m_Cannons.Add(shipCannon); switch (cannonPosition) { case CannonPosition.Left: boat.m_LeftCannons.Add(shipCannon); break; case CannonPosition.Right: boat.m_RightCannons.Add(shipCannon); break; case CannonPosition.Front: boat.m_FrontCannons.Add(shipCannon); break; case CannonPosition.Rear: boat.m_RearCannons.Add(shipCannon); break; } }
public void FireCannon(ShipCannon shipCannon, Mobile from, Point3D targetLocation, Map map, bool hit, bool showSmoke) { if (shipCannon == null) { return; } int cannonballItemID = 0xE73; int cannonballHue = 0; int smokeHue = 0; bool fixedDirection = false; double shotDelay = .04; int shotSpeed = 6; Point3D smokeLocation = shipCannon.Location; switch (shipCannon.Facing) { case Direction.North: { } break; case Direction.East: { smokeLocation.X++; } break; case Direction.South: { smokeLocation.Y++; } break; case Direction.West: { smokeLocation.X--; } break; } if (m_Boat != null) { double gunsPercent = (double)((float)m_Boat.GunPoints / (float)m_Boat.MaxGunPoints); double misfireChance = BaseBoat.CannonMaxMisfireChance * (1 - gunsPercent); double chance = Utility.RandomDouble(); double distance = Utility.GetDistanceToSqrt(shipCannon.Location, targetLocation); double flatDistance = Utility.GetDistance(shipCannon.Location, targetLocation); //Misfire if (chance < misfireChance) { List <Mobile> m_MobilesOnBoat = m_Boat.GetMobilesOnBoat(true, true); foreach (Mobile mobile in m_MobilesOnBoat) { if (m_Boat.IsOwner(mobile) || m_Boat.IsCoOwner(mobile) || m_Boat.IsFriend(mobile)) { mobile.SendMessage("Misfire!"); } } Effects.SendLocationEffect(shipCannon.Location, map, 0x3735, 10); Effects.PlaySound(shipCannon.Location, map, 0x475); return; } if (m_Boat.MobileFactionType == MobileFactionType.Undead) { cannonballItemID = Utility.RandomList(6880, 6881, 6882, 6883, 6884); smokeHue = 2630; } //Hit if (hit) { m_Boat.LastCombatTime = DateTime.UtcNow; Effects.PlaySound(shipCannon.Location, map, 0x664); if (showSmoke) { Effects.SendLocationEffect(smokeLocation, map, 0x36CB, 10, smokeHue, 0); } SpellHelper.AdjustField(ref targetLocation, map, 12, false); IEntity startLocation = new Entity(Serial.Zero, new Point3D(shipCannon.Location.X, shipCannon.Location.Y, shipCannon.Location.Z + 10), map); IEntity endLocation = new Entity(Serial.Zero, new Point3D(targetLocation.X, targetLocation.Y, targetLocation.Z + 5), map); Effects.SendMovingEffect(startLocation, endLocation, cannonballItemID, shotSpeed, 0, fixedDirection, false, cannonballHue, 0); double effectDelay = distance * shotDelay; Timer.DelayCall(TimeSpan.FromSeconds(effectDelay), delegate { ResolveCannon(shipCannon, from, targetLocation, map, hit); }); } //Miss else { int xOffset = 0; int yOffset = 0; double effectiveDistance = distance; int distanceOffset = (int)(Math.Floor(effectiveDistance / 2)); if (distance >= 2) { xOffset = Utility.RandomMinMax(0, distanceOffset); if (Utility.RandomDouble() > .5) { xOffset *= -1; } yOffset = Utility.RandomMinMax(0, distanceOffset); if (Utility.RandomDouble() > .5) { yOffset *= -1; } } Effects.PlaySound(shipCannon.Location, map, 0x664); Effects.SendLocationEffect(smokeLocation, map, 0x36CB, 10, smokeHue, 0); IEntity startLocation = new Entity(Serial.Zero, new Point3D(shipCannon.Location.X, shipCannon.Location.Y, shipCannon.Location.Z + 10), map); IEntity endLocation = new Entity(Serial.Zero, new Point3D(targetLocation.X + xOffset, targetLocation.Y + yOffset, targetLocation.Z + 5), map); Effects.SendMovingEffect(startLocation, endLocation, cannonballItemID, shotSpeed, 0, fixedDirection, false, cannonballHue, 0); Point3D splashLocation = new Point3D(targetLocation.X + xOffset, targetLocation.Y + yOffset, +targetLocation.Z); double newDistance = from.GetDistanceToSqrt(splashLocation); double effectDelay = newDistance * shotDelay; Timer.DelayCall(TimeSpan.FromSeconds(effectDelay), delegate { ResolveCannon(shipCannon, from, splashLocation, map, hit); }); } } }
public void OnTarget(Mobile from, Point3D point, bool IsNPCShip, bool canHitCenter, bool canHitHold, bool canHitTillerman) { if (m_Boat == null) { return; } Map map = from.Map; BaseBoat targetBoat = BaseBoat.FindBoatAt(point, map); //For Player Ships if (m_Boat.MobileControlType == MobileControlType.Player) { if (!from.Player) { return; } else if (!from.Alive) { from.SendMessage("You must be alive to use this."); return; } else if (!m_Boat.Contains(from)) { from.SendMessage("You are no longer on the boat."); return; } else if (targetBoat == m_Boat) { from.SendMessage("You may not fire onto your own ship!"); return; } else if (Ammunition == 0) { from.SendMessage("At least one of your cannons must be loaded to fire a volley."); return; } else if (DateTime.UtcNow < m_Boat.CannonCooldown) { from.SendMessage("You must wait before firing another cannon volley."); return; } } bool volleyValid = false; bool tooClose = false; double cannonDelayTotal = 0; int cannonsFiring = 0; //Need At Least One Cannon With LOS to Target and In Range of Target For Volley To Be Valid foreach (ShipCannon shipCannon in m_Boat.m_Cannons) { //Cannon Has Ammunition and is on Correct Ship Side for Volley if (shipCannon.Ammunition > 0 && shipCannon.Facing == Facing) { cannonDelayTotal += BaseBoat.CannonCooldownTime; cannonsFiring++; double modifiedRange = (double)BaseBoat.CannonMaxRange * m_Boat.CannonRangeScalar; //Already Deterined to Be Valid Shot: NPC AI Ship if (IsNPCShip) { volleyValid = true; break; } //Cannon is in LOS and Within Range if (shipCannon.InAngle(point) && Utility.GetDistanceToSqrt(shipCannon.Location, point) <= modifiedRange) { volleyValid = true; } //Cannon is too close if (Utility.GetDistanceToSqrt(shipCannon.Location, point) < 2) { tooClose = true; } } } //At Least One Cannon Was Too Close to Fire if (tooClose) { volleyValid = false; } //Can Fire Cannon Volley if (volleyValid) { if (m_Boat.TillerMan != null) { m_Boat.TillerMan.Say("Firing cannons!"); } m_Boat.LastCombatTime = DateTime.UtcNow; //Ship Cooldown Time (Average of Delay for Each Cannon Type that is Firing) double cooldown = cannonDelayTotal / cannonsFiring; m_Boat.CannonCooldown = DateTime.UtcNow + TimeSpan.FromSeconds(cooldown); m_Boat.StartCannonCooldown(); List <ShipCannon> cannonsToFire = new List <ShipCannon>(); foreach (ShipCannon shipCannon in m_Boat.m_Cannons) { if (shipCannon.Ammunition > 0 && shipCannon.Facing == Facing) { cannonsToFire.Add(shipCannon); } } int firingLoops = BaseBoat.CannonFiringLoops; int cannonCount = cannonsToFire.Count; for (int a = 0; a < firingLoops; a++) { for (int b = 0; b < cannonCount; b++) { bool showSmoke = false; bool lastCannon = false; int cannonIndex = Utility.RandomMinMax(0, cannonsToFire.Count - 1); ShipCannon shipCannon = cannonsToFire[cannonIndex]; if (a == 0) { showSmoke = true; } if (a == (firingLoops - 1)) { shipCannon.Ammunition--; cannonsToFire.RemoveAt(cannonIndex); if (b == cannonCount - 1) { lastCannon = true; } } //Check Accuracy double cannonAccuracy = BaseBoat.CannonAccuracy * m_Boat.CannonAccuracyModifer; double opponentMovementPenalty = 0; double movementAccuracyPenalty = 0; //Own Ship Movement Penalty TimeSpan timeStationary = DateTime.UtcNow - m_Boat.TimeLastMoved; double secondsStationary = (double)timeStationary.TotalSeconds; if (secondsStationary > BaseBoat.CannonMovementAccuracyCooldown) { secondsStationary = BaseBoat.CannonMovementAccuracyCooldown; } if (targetBoat != null) { TimeSpan timeTargetStationary = DateTime.UtcNow - targetBoat.TimeLastMoved; double secondsOpponentStationary = (double)timeStationary.TotalSeconds; if (secondsOpponentStationary > BaseBoat.CannonMovementAccuracyCooldown) { secondsOpponentStationary = BaseBoat.CannonMovementAccuracyCooldown; } opponentMovementPenalty = 1 - (BaseBoat.CannonTargetMovementMaxAccuracyPenalty * (1 - (secondsOpponentStationary / BaseBoat.CannonMovementAccuracyCooldown))); //No Movement Penalty to Shoot a Ship That is in Reduced Speed Mode if (targetBoat.ReducedSpeedMode) { opponentMovementPenalty = 1; } } movementAccuracyPenalty = 1 - (BaseBoat.CannonMovementMaxAccuracyPenalty * (1 - (secondsStationary / BaseBoat.CannonMovementAccuracyCooldown))); double finalAccuracy = cannonAccuracy * movementAccuracyPenalty * opponentMovementPenalty; double chance = Utility.RandomDouble(); bool hit = false; //Hit Target if (chance <= finalAccuracy) { hit = true; } Point3D cannonEndLocation = point; if (IsNPCShip && targetBoat != null) { if (canHitCenter) { cannonEndLocation = targetBoat.GetRandomEmbarkLocation(true); } else if (canHitHold && canHitTillerman) { if (Utility.RandomDouble() < .5) { cannonEndLocation = targetBoat.Hold.Location; } else { cannonEndLocation = targetBoat.TillerMan.Location; } } else if (canHitHold && !canHitTillerman) { cannonEndLocation = targetBoat.Hold.Location; } else if (!canHitHold && canHitTillerman) { cannonEndLocation = targetBoat.TillerMan.Location; } } double delay = (BaseBoat.CannonLoopDelay * (a + 1) / (double)firingLoops) * b; Timer.DelayCall(TimeSpan.FromSeconds(delay), delegate { FireCannon(shipCannon, from, cannonEndLocation, map, hit, showSmoke); }); } } } else { if (tooClose) { from.SendMessage("Your target is too close to the ship to be fired upon."); } else { from.SendMessage("At least one of your cannons must be within range of and in line of sight of your target in order to fire a cannon volley."); } } }
public CannonTarget(ShipCannon shipCannon) : base(25, true, TargetFlags.Harmful) { m_ShipCannon = shipCannon; }