public virtual bool AcceptEscorter(Mobile mobile) { EDI dest = GetDestination(); if (dest == null || mobile == null) { return(false); } if (!mobile.Alive) { return(false); } BaseBoat m_Boat = BaseBoat.FindBoatAt(mobile.Location, mobile.Map); if (m_Boat != null) { if (m_Boat.Deleted || m_Boat.m_SinkTimer != null) { mobile.SendMessage("Your boat is in no condition right now to be taking on passengers!"); return(false); } if (!(m_Boat.IsOwner(mobile) || m_Boat.IsCoOwner(mobile))) { mobile.SendMessage("Only owners and co-owners of this ship have permission to take on passengers."); return(false); } Say("Thank you! Let us return to " + dest.Name); if (Body.IsHuman && !Mounted) { Animate(32, 3, 1, true, false, 0); } if (m_DeleteTimer != null) { m_DeleteTimer.Stop(); } m_DeleteTime = DateTime.UtcNow + TimeSpan.FromMinutes(120); m_DeleteTimer = new DeleteTimer(this, m_DeleteTime - DateTime.UtcNow); m_DeleteTimer.Start(); Location = m_Boat.GetRandomEmbarkLocation(true); m_Boat.AddEmbarkedMobile(this); } return(true); }
public static void StartThrowShipBomb(BaseCreature creature, BaseBoat targetBoat) { Timer.DelayCall(TimeSpan.FromSeconds(.3), delegate { Effects.PlaySound(creature.Location, creature.Map, 0x666); }); Point3D randomShipLocation = targetBoat.GetRandomEmbarkLocation(true); IEntity startLocation = new Entity(Serial.Zero, new Point3D(creature.Location.X, creature.Location.Y, creature.Location.Z + 10), creature.Map); IEntity endLocation = new Entity(Serial.Zero, new Point3D(randomShipLocation.X, randomShipLocation.Y, randomShipLocation.Z + 5), targetBoat.Map); Effects.SendMovingEffect(startLocation, endLocation, 0x1C19, 10, 0, false, false, 0, 0); int distance = targetBoat.GetBoatToLocationDistance(targetBoat, creature.Location); double destinationDelay = (double)distance * .06; double explosionDelay = (double)distance * .16; Timer.DelayCall(TimeSpan.FromSeconds(destinationDelay), delegate { Effects.SendLocationEffect(endLocation.Location, targetBoat.Map, 0x1C19, 20); }); Timer.DelayCall(TimeSpan.FromSeconds(explosionDelay), delegate { DetonateShipBomb(creature, targetBoat, randomShipLocation); }); }
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 static void GenerateShipCrew(BaseBoat boat) { if (boat == null) return; if (boat.Deleted) return; int shipLevel = 1; if (boat is MediumBoat || boat is MediumDragonBoat) shipLevel = 2; if (boat is LargeBoat || boat is LargeDragonBoat) shipLevel = 3; if (boat is CarrackBoat) shipLevel = 4; if (boat is GalleonBoat) shipLevel = 5; BaseCreature bc_Creature; Point3D creatureLocation; int crewNumber = 0; int ratChances = 0; Dictionary<Type, int> DictCrewOptions = new Dictionary<Type, int>(); switch (boat.MobileFactionType) { case MobileFactionType.Fishing: #region Fishing crewNumber = 3 + shipLevel; for (int a = 0; a < crewNumber; a++) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.OceanFisherman(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } #endregion break; case MobileFactionType.Pirate: #region Pirate crewNumber = 3 + shipLevel; for (int a = 0; a < crewNumber; a++) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.OceanPirate(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } if (Utility.RandomDouble() <= (.2 * shipLevel) ) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.PirateShipCarpenter(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } if (Utility.RandomDouble() <= (.2 * shipLevel)) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.PirateSawbones(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.OceanPirateCaptain(boat); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.Owner = bc_Creature; boat.AddEmbarkedMobile(bc_Creature); #endregion break; case MobileFactionType.Britain: #region Britain DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(Custom.Pirates.BritainSailor), 2); DictCrewOptions.Add(typeof(Custom.Pirates.BritainMarine), 1); crewNumber = 3 + shipLevel; for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } if (Utility.RandomDouble() <= (.2 * shipLevel ) ) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.BritainShipCarpenter(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } if (Utility.RandomDouble() <= (.2 * shipLevel)) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.BritainShipSurgeon(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.BritainShipCaptain(boat); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.Owner = bc_Creature; boat.AddEmbarkedMobile(bc_Creature); #endregion break; case MobileFactionType.Orc: #region Orc crewNumber = 3 + shipLevel; DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(OrcishGrunt), 1); DictCrewOptions.Add(typeof(OrcishScout), 1); DictCrewOptions.Add(typeof(OrcMojoka), 1); for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; if (bc_Creature is OrcishGrunt) bc_Creature.PackItem(new Bow() { Movable = false, Hue = 0 }); creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } crewNumber = (int)(Math.Ceiling((double)shipLevel / 2)); DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(OrcishExecutioner), 1); DictCrewOptions.Add(typeof(OrcishSurjin), 1); DictCrewOptions.Add(typeof(OrcishMaurk), 1); DictCrewOptions.Add(typeof(ElderMojoka), 1); for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; if (bc_Creature is OrcishExecutioner || bc_Creature is OrcishSurjin) bc_Creature.PackItem(new Bow() { Movable = false, Hue = 0 }); creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } #endregion break; case MobileFactionType.Orghereim: #region Orghereim crewNumber = 3 + shipLevel; DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(OrghereimBowMaiden), 1); DictCrewOptions.Add(typeof(OrghereimTracker), 1); DictCrewOptions.Add(typeof(OrghereimSwordThane), 1); DictCrewOptions.Add(typeof(OrghereimIceCarl), 1); DictCrewOptions.Add(typeof(OrghereimShieldMaiden), 1); for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; if (bc_Creature is OrghereimSwordThane || bc_Creature is OrghereimShieldMaiden) bc_Creature.PackItem(new Bow() { Movable = false, Hue = 0 }); creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } crewNumber = (int)(Math.Ceiling((double)shipLevel / 2)); DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(OrghereimBoneMender), 1); DictCrewOptions.Add(typeof(OrghereimCrone), 1); DictCrewOptions.Add(typeof(OrghereimSage), 1); DictCrewOptions.Add(typeof(OrghereimShieldMother), 1); for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; if (bc_Creature is OrghereimShieldMother) bc_Creature.PackItem(new Bow() { Movable = false, Hue = 0 }); creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } #endregion break; case MobileFactionType.Undead: #region Undead crewNumber = 3 + shipLevel; for (int a = 0; a < crewNumber; a++) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.SkeletalCrewman(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } crewNumber = 3 + shipLevel; DictCrewOptions = new Dictionary<Type, int>(); DictCrewOptions.Add(typeof(Skeleton), 15); DictCrewOptions.Add(typeof(ZombieMagi), 5); DictCrewOptions.Add(typeof(SkeletalMage), 5); DictCrewOptions.Add(typeof(Lich), 3); DictCrewOptions.Add(typeof(SkeletalDrake), 2); DictCrewOptions.Add(typeof(LichLord), 1); for (int a = 0; a < crewNumber; a++) { int TotalValues = 0; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { TotalValues += pair.Value; } double ActionCheck = Utility.RandomDouble(); double CumulativeAmount = 0.0; double AdditionalAmount = 0.0; bool foundDirection = true; foreach (KeyValuePair<Type, int> pair in DictCrewOptions) { AdditionalAmount = (double)pair.Value / (double)TotalValues; if (ActionCheck >= CumulativeAmount && ActionCheck < (CumulativeAmount + AdditionalAmount)) { bc_Creature = (BaseCreature)Activator.CreateInstance(pair.Key); if (bc_Creature == null) continue; creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); break; } CumulativeAmount += AdditionalAmount; } } int necromancers = (int)(Math.Ceiling((double)shipLevel / 2)); for (int a = 0; a < necromancers; a++) { creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.GhostShipNecromancer(); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.AddEmbarkedMobile(bc_Creature); } creatureLocation = boat.GetRandomEmbarkLocation(true); bc_Creature = new Custom.Pirates.SkeletalCaptain(boat); bc_Creature.BardImmune = true; bc_Creature.MoveToWorld(creatureLocation, boat.Map); boat.Crew.Add(bc_Creature); boat.Owner = bc_Creature; boat.AddEmbarkedMobile(bc_Creature); #endregion break; } }