/// <summary> /// Generates a <see cref="DCSMission"/> from a <see cref="MissionTemplate"/> /// </summary> /// <param name="template">The <see cref="MissionTemplate"/> to use</param> /// <returns>A <see cref="DCSMission"/>, or nuLL if something when wrong</returns> private DCSMission DoMissionGeneration(MissionTemplate template) { DateTime generationStartTime = DateTime.Now; DebugLog.Instance.Clear(); DebugLog.Instance.WriteLine($"Starting mission generation..."); // Check for missing entries in the database GeneratorTools.CheckDBForMissingEntry <DBEntryCoalition>(template.ContextCoalitionBlue); GeneratorTools.CheckDBForMissingEntry <DBEntryCoalition>(template.ContextCoalitionRed); GeneratorTools.CheckDBForMissingEntry <DBEntryObjective>(template.ObjectiveType); GeneratorTools.CheckDBForMissingEntry <DBEntryTheater>(template.TheaterID); // Create the mission and copy some values (theater database entry ID, etc.) from the template DCSMission mission = new DCSMission(); CopyTemplateValues(mission, template); // Get some DB entries from the database for easier reference DBEntryCoalition[] coalitionsDB = new DBEntryCoalition[2]; coalitionsDB[(int)Coalition.Blue] = Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionBlue); coalitionsDB[(int)Coalition.Red] = Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionRed); DBEntryObjective objectiveDB; if (template.ObjectiveType == "Random") { objectiveDB = Toolbox.RandomFrom <DBEntryObjective>(Database.Instance.GetAllEntries <DBEntryObjective>().Where(x => x.ID != "Random").ToArray()); } else { objectiveDB = Database.Instance.GetEntry <DBEntryObjective>(template.ObjectiveType); } DBEntryTheater theaterDB = Database.Instance.GetEntry <DBEntryTheater>(template.TheaterID); // Create the unit maker, which will be used to generate unit groups and their properties UnitMaker unitMaker = new UnitMaker(coalitionsDB, theaterDB); // Create a list of flight group descriptions which will be used in the briefing List <UnitFlightGroupBriefingDescription> briefingFGList = new List <UnitFlightGroupBriefingDescription>(); // Setup airbases DBEntryTheaterAirbase airbaseDB; using (MissionGeneratorAirbases airbaseGen = new MissionGeneratorAirbases()) { airbaseDB = airbaseGen.SelectStartingAirbase(mission, template, theaterDB, objectiveDB); mission.InitialAirbaseID = airbaseDB.DCSID; mission.InitialPosition = airbaseDB.Coordinates; airbaseGen.SetupAirbasesCoalitions(mission, template.TheaterRegionsCoalitions, theaterDB); } // Generate mission objectives DebugLog.Instance.WriteLine("Generating mission objectives..."); using (MissionGeneratorObjectives objectives = new MissionGeneratorObjectives(unitMaker.SpawnPointSelector)) objectives.CreateObjectives(mission, template, objectiveDB, theaterDB); // Generate mission date and time DebugLog.Instance.WriteLine("Generating mission date and time..."); using (MissionGeneratorDateTime dateTime = new MissionGeneratorDateTime()) { dateTime.GenerateMissionDate(mission, template, coalitionsDB); dateTime.GenerateMissionTime(mission, template, theaterDB); } // Generate mission weather DebugLog.Instance.WriteLine("Generating mission weather..."); using (MissionGeneratorWeather weather = new MissionGeneratorWeather()) { weather.GenerateWeather(mission, template.EnvironmentWeather, theaterDB); weather.GenerateWind(mission, template.EnvironmentWind, theaterDB); } // Generate Carrier using (MissionGeneratorCarrier unitGroupGen = new MissionGeneratorCarrier(unitMaker)) unitGroupGen.GenerateCarriers(mission, template, coalitionsDB[(int)mission.CoalitionPlayer]); // Generate player unit groups DebugLog.Instance.WriteLine("Generating player unit groups and mission package..."); string aiEscortTypeCAP, aiEscortTypeSEAD; using (MissionGeneratorPlayerFlightGroups unitGroupGen = new MissionGeneratorPlayerFlightGroups(unitMaker)) briefingFGList.AddRange( unitGroupGen.CreateUnitGroups( mission, template, objectiveDB, coalitionsDB[(int)mission.CoalitionPlayer], out aiEscortTypeCAP, out aiEscortTypeSEAD)); // Generate objective unit groups DebugLog.Instance.WriteLine("Generating objectives unit groups..."); using (MissionGeneratorObjectivesUnitGroups unitGroupGen = new MissionGeneratorObjectivesUnitGroups(unitMaker)) unitGroupGen.CreateUnitGroups(mission, template, objectiveDB, coalitionsDB); // Generate friendly support units DebugLog.Instance.WriteLine("Generating friendly support units..."); using (MissionGeneratorSupportUnits unitGroupGen = new MissionGeneratorSupportUnits(unitMaker)) briefingFGList.AddRange(unitGroupGen.CreateUnitGroups(mission, coalitionsDB[(int)mission.CoalitionPlayer], template.OptionsUnitMods)); // Generate enemy air defense unit groups DebugLog.Instance.WriteLine("Generating enemy air defense unit groups..."); using (MissionGeneratorAirDefense unitGroupGen = new MissionGeneratorAirDefense(unitMaker, false, template, mission)) unitGroupGen.CreateUnitGroups(mission, objectiveDB, coalitionsDB[(int)mission.CoalitionEnemy], GeneratorTools.GetEnemySpawnPointCoalition(template), template.OptionsUnitMods); // Generate ally air defense unit groups DebugLog.Instance.WriteLine("Generating friendly air defense unit groups..."); using (MissionGeneratorAirDefense unitGroupGen = new MissionGeneratorAirDefense(unitMaker, true, template, mission)) unitGroupGen.CreateUnitGroups(mission, objectiveDB, coalitionsDB[(int)mission.CoalitionPlayer], GeneratorTools.GetAllySpawnPointCoalition(template), template.OptionsUnitMods); //// Generate enemy fighter patrols DebugLog.Instance.WriteLine("Generating enemy fighter patrol unit groups..."); using (MissionGeneratorEnemyFighterPatrols unitGroupGen = new MissionGeneratorEnemyFighterPatrols(unitMaker)) unitGroupGen.CreateUnitGroups(mission, template, objectiveDB, coalitionsDB[(int)mission.CoalitionEnemy], aiEscortTypeCAP, aiEscortTypeSEAD); //// Generate mission features DebugLog.Instance.WriteLine("Generating mission features unit groups..."); using (MissionGeneratorExtensionsAndFeatures featuresGen = new MissionGeneratorExtensionsAndFeatures(unitMaker)) featuresGen.GenerateExtensionsAndFeatures(mission, template, objectiveDB, coalitionsDB); // Generates the mission flight plan DebugLog.Instance.WriteLine("Generating mission flight plan..."); using (MissionGeneratorFlightPlan flightPlan = new MissionGeneratorFlightPlan()) { flightPlan.SetBullseye(mission); flightPlan.AddObjectiveWaypoints(mission, objectiveDB); flightPlan.AddExtraWaypoints(mission, template); } // Generate briefing. Must be last because it uses information from other generators DebugLog.Instance.WriteLine("Generating mission briefing..."); using (MissionGeneratorBriefing briefing = new MissionGeneratorBriefing()) { briefing.GenerateMissionName(mission, template); briefing.GenerateMissionBriefing(mission, template, objectiveDB, airbaseDB, briefingFGList, coalitionsDB); } // Set if radio sounds are enabled mission.RadioSounds = !template.OptionsPreferences.Contains(MissionTemplatePreferences.DisableRadioSounds); // Add common .ogg vorbis files and make sure each only appears only once. mission.OggFiles.AddRange(Database.Instance.Common.CommonOGG); mission.OggFiles.AddRange(Database.Instance.Common.CommonOGGForGameMode[(int)template.GetMissionType()]); mission.OggFiles = (from string f in mission.OggFiles where !string.IsNullOrEmpty(f.Trim()) select f.Trim()) .Distinct(StringComparer.InvariantCultureIgnoreCase).ToList(); // If radio sounds are disabled, do not include radio .ogg files to save on file size if (!mission.RadioSounds) { mission.OggFiles = (from string f in mission.OggFiles where (f.ToLowerInvariant() == "radio0") || (!f.ToLowerInvariant().StartsWith("radio")) select f).ToList(); } // Make sure included Lua scripts appear only once mission.IncludedLuaScripts = mission.IncludedLuaScripts.Distinct().OrderBy(x => x).ToList(); // Create aircraft queues and finalize the core script CreateAircraftActivationQueues(mission); switch (template.GetMissionType()) { case MissionType.SinglePlayer: mission.CoreLuaScript += "briefingRoom.mission.missionType = brMissionType.SINGLE_PLAYER\r\n"; break; case MissionType.Cooperative: mission.CoreLuaScript += "briefingRoom.mission.missionType = brMissionType.COOPERATIVE\r\n"; break; case MissionType.Versus: mission.CoreLuaScript += "briefingRoom.mission.missionType = brMissionType.VERSUS\r\n"; break; } DebugLog.Instance.WriteLine($"Mission generation completed successfully in {(DateTime.Now - generationStartTime).TotalSeconds.ToString("F3", NumberFormatInfo.InvariantInfo)} second(s)."); unitMaker.Dispose(); return(mission); }
/// <summary> /// /// </summary> /// <param name="mission"></param> /// <param name="template"></param> /// <param name="playerCoalitionDB"></param> /// <param name="windDirection0">Wind direction at altitude 0, in degrees. Used by carrier groups to make sure carriers sail into the wind.</param> /// <returns></returns> public void GenerateCarriers(DCSMission mission, MissionTemplate template, DBEntryCoalition playerCoalitionDB) { var carriers = new string[] {}; if (template.GetMissionType() == MissionType.SinglePlayer) { if (string.IsNullOrEmpty(template.PlayerSPCarrier)) { return; } carriers = carriers.Append(template.PlayerSPCarrier).ToArray(); } else { carriers = template.PlayerMPFlightGroups.Aggregate(new string[] {}, (acc, x) => !string.IsNullOrEmpty(x.Carrier)? acc.Append(x.Carrier).ToArray() : acc); } if (carriers.Length == 0) { return; } foreach (string carrier in carriers) { DBEntryTheaterSpawnPoint?spawnPoint = UnitMaker.SpawnPointSelector.GetRandomSpawnPoint( // If spawn point types are specified, use them. Else look for spawn points of any type new TheaterLocationSpawnPointType[] { TheaterLocationSpawnPointType.Sea }, // Select spawn points at a proper distance from last location (previous objective or home airbase) mission.InitialPosition, new MinMaxD(10, 50), // Make sure no objective is too close to the initial location null, null, GeneratorTools.GetAllySpawnPointCoalition(template)); if (!spawnPoint.HasValue) { throw new Exception($"Failed to find a spawn point for Carrier"); } Coordinates position = mission.InitialPosition; DCSMissionUnitGroup group; string[] ships = new string[] { carrier }; foreach (var ship in new UnitFamily[] { UnitFamily.ShipFrigate, UnitFamily.ShipFrigate, UnitFamily.ShipCruiser, UnitFamily.ShipCruiser, UnitFamily.ShipTransport }) { ships = ships.Append(playerCoalitionDB.GetRandomUnits(ship, mission.DateTime.Decade, 1, template.OptionsUnitMods)[0]).ToArray(); } DebugLog.Instance.WriteLine($"Ships to be spawned {ships.Aggregate((acc, x) => $"{acc}, {x}")}", 1, DebugLogMessageErrorLevel.Warning); group = UnitMaker.AddUnitGroup( mission, ships, Side.Ally, spawnPoint.Value.Coordinates, "GroupCarrier", "UnitShip", Toolbox.BRSkillLevelToDCSSkillLevel(template.PlayerAISkillLevel)); if (group == null) { DebugLog.Instance.WriteLine($"Failed to create AI Carrier with ship of type \"{carrier}\".", 1, DebugLogMessageErrorLevel.Warning); } else { //set all units against the wind int windDirection = mission.Weather.WindDirection[0]; double WindSpeed = mission.Weather.WindSpeed[0]; double windOverDeck = 12.8611; // 25kts group.Speed = windOverDeck - WindSpeed; if (group.Speed <= 2.6) { group.Speed = 2.57222; //5kts } double heading = Toolbox.ClampAngle((windDirection + 180) * Toolbox.DEGREES_TO_RADIANS); foreach (DCSMissionUnitGroupUnit unit in group.Units) { unit.Heading = heading; } group.Units[0].Coordinates = group.Coordinates; group.Coordinates2 = Coordinates.FromAngleAndDistance(group.Coordinates, (group.Speed * Toolbox.METERS_PER_SECOND_TO_KNOTS) * Toolbox.NM_TO_METERS, heading); } string cvnId = mission.Carriers.Length > 0? (mission.Carriers.Length + 1).ToString() : ""; group.TACAN = new Tacan(74 + mission.Carriers.Length, $"CVN{cvnId}"); group.ILS = 11 + mission.Carriers.Length; group.RadioFrequency = 127.5f + mission.Carriers.Length; mission.Carriers = mission.Carriers.Append(group).ToArray(); } return; }
/// <summary> /// /// </summary> /// <param name="mission"></param> /// <param name="template"></param> /// <param name="playerCoalitionDB"></param> /// <param name="windDirection0">Wind direction at altitude 0, in degrees. Used by carrier groups to make sure carriers sail into the wind.</param> /// <returns></returns> public DBEntryUnit GenerateCarrier(DCSMission mission, MissionTemplate template, DBEntryCoalition playerCoalitionDB, int windDirection0) { if (string.IsNullOrEmpty(template.PlayerCarrier)) { return(null); } DBEntryTheaterSpawnPoint?spawnPoint = UnitMaker.SpawnPointSelector.GetRandomSpawnPoint( // If spawn point types are specified, use them. Else look for spawn points of any type new TheaterLocationSpawnPointType[] { TheaterLocationSpawnPointType.Sea }, // Select spawn points at a proper distance from last location (previous objective or home airbase) mission.InitialPosition, new MinMaxD(10, 50), // Make sure no objective is too close to the initial location null, null, GeneratorTools.GetAllySpawnPointCoalition(template)); if (!spawnPoint.HasValue) { throw new Exception($"Failed to find a spawn point for Carrier"); } Coordinates position = mission.InitialPosition; DCSMissionUnitGroup group; string[] ships = new string[] { template.PlayerCarrier }; foreach (var ship in new UnitFamily[] { UnitFamily.ShipFrigate, UnitFamily.ShipFrigate, UnitFamily.ShipCruiser, UnitFamily.ShipCruiser, UnitFamily.ShipTransport }) { ships = ships.Append(playerCoalitionDB.GetRandomUnits(ship, mission.DateTime.Decade, 1, template.OptionsUnitMods)[0]).ToArray(); } DebugLog.Instance.WriteLine($"Ships to be spawned {ships.Aggregate((acc, x) => $"{acc}, {x}")}", 1, DebugLogMessageErrorLevel.Warning); group = UnitMaker.AddUnitGroup( mission, ships, Side.Ally, spawnPoint.Value.Coordinates, "GroupCarrier", "UnitShip", Toolbox.BRSkillLevelToDCSSkillLevel(template.PlayerAISkillLevel)); if (group == null) { DebugLog.Instance.WriteLine($"Failed to create AI Carrier with ship of type \"{template.PlayerCarrier}\".", 1, DebugLogMessageErrorLevel.Warning); } else { //set all units against the wind double heading = Toolbox.ClampAngle((windDirection0 + 180) * Toolbox.DEGREES_TO_RADIANS); foreach (DCSMissionUnitGroupUnit unit in group.Units) { unit.Heading = heading; } } mission.Carrier = group.Units[0]; return((from DBEntryUnit unit in Database.Instance.GetAllEntries <DBEntryUnit>() where unit.ID == template.PlayerCarrier select unit).ToArray()[0]); }