internal static Tuple <double, double> GenerateWind(DCSMission mission, MissionTemplateRecord template, int turbulenceFromWeather) { var windSpeedAtSeaLevel = 0.0; var windDirectionAtSeaLevel = 0.0; Wind windLevel = template.EnvironmentWind == Wind.Random ? PickRandomWindLevel() : template.EnvironmentWind; BriefingRoom.PrintToLog($"Wind speed level set to \"{windLevel}\"."); int windAverage = 0; for (int i = 0; i < 3; i++) { int windSpeed = Database.Instance.Common.Wind[(int)windLevel].Wind.GetValue(); int windDirection = windSpeed > 0 ? Toolbox.RandomInt(0, 360) : 0; if (i == 0) { windSpeedAtSeaLevel = windSpeed; windDirectionAtSeaLevel = windDirection * Toolbox.DEGREES_TO_RADIANS; } windAverage += windSpeed; mission.SetValue($"WeatherWindSpeed{i + 1}", windSpeed); mission.SetValue($"WeatherWindDirection{i + 1}", windDirection); } windAverage /= 3; mission.SetValue($"WeatherWindName", windLevel.ToString()); // TODO: get name from attribute mission.SetValue($"WeatherWindSpeedAverage", windAverage); mission.SetValue("WeatherGroundTurbulence", Database.Instance.Common.Wind[(int)windLevel].Turbulence.GetValue() + turbulenceFromWeather); return(new(windSpeedAtSeaLevel, windDirectionAtSeaLevel)); }
internal static void GenerateBullseyes(DCSMission mission, Coordinates objectivesCenter) { mission.SetValue("BullseyeBlueX", objectivesCenter.X + GetBullseyeRandomDistance()); mission.SetValue("BullseyeBlueY", objectivesCenter.Y + GetBullseyeRandomDistance()); mission.SetValue("BullseyeRedX", objectivesCenter.X + GetBullseyeRandomDistance()); mission.SetValue("BullseyeRedY", objectivesCenter.Y + GetBullseyeRandomDistance()); }
internal static Country[][] GenerateCountries(DCSMission mission, MissionTemplateRecord template) { int i; List <Country>[] countries = new List <Country>[] { new List <Country>(), new List <Country>() }; // Add default country for each coalition for (i = 0; i < 2; i++) { countries[i].Add(DEFAULT_COUNTRIES[i]); } // Add countries for player FGs to player coalition foreach (MissionTemplateFlightGroupRecord flightGroup in template.PlayerFlightGroups) { var group = flightGroup.Hostile ? template.ContextPlayerCoalition.GetEnemy() : template.ContextPlayerCoalition; countries[(int)group].Add(flightGroup.Country); } countries[(int)Coalition.Blue].AddRange(Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionBlue).Countries); countries[(int)Coalition.Red].AddRange(Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionRed).Countries); // Make sure each country doesn't contain the other's coalition default country for (i = 0; i < 2; i++) { countries[i].Remove(Country.ALL); countries[i] = countries[i].Distinct().ToList(); } var intersect = countries[(int)Coalition.Blue].Intersect(countries[(int)Coalition.Red]).ToList(); if (intersect.Count > 0) { throw new BriefingRoomException($"Countries can't be on both sides {string.Join(",", intersect)}. Check Red and Blue Coalitions as well as flight groups countries."); } // Add all non-aligned countries to the list of neutral countries List <Country> neutralCountries = new List <Country>(Toolbox.GetEnumValues <Country>()); for (i = 0; i < 2; i++) { neutralCountries = neutralCountries.Except(countries[i]).ToList(); } mission.SetValue("CoalitionNeutral", GetCountriesLuaTable(neutralCountries)); mission.SetValue("CoalitionBlue", GetCountriesLuaTable(countries[(int)Coalition.Blue])); mission.SetValue("CoalitionRed", GetCountriesLuaTable(countries[(int)Coalition.Red])); return(new Country[][] { countries[0].ToArray(), countries[1].ToArray(), }); }
internal static Month GenerateMissionDate(DCSMission mission, MissionTemplateRecord template) { int day; Month month; // Select a random year from the most recent coalition's decade. var year = Toolbox.GetRandomYearFromDecade(template.ContextDecade); BriefingRoom.PrintToLog($"No fixed date provided in the mission template, generating date in decade {template.ContextDecade}"); if (template.EnvironmentSeason == Season.Random) // Random season, pick any day of the year. { month = (Month)Toolbox.RandomInt(12); day = Toolbox.RandomMinMax(1, GeneratorTools.GetDaysPerMonth(month, year)); } else // Pick a date according to the desired season { Month[] seasonMonths = GetMonthsForSeason(template.EnvironmentSeason); int monthIndex = Toolbox.RandomInt(4); month = seasonMonths[monthIndex]; switch (monthIndex) { case 0: // First month of the season, season begins on the 21st day = Toolbox.RandomMinMax(21, GeneratorTools.GetDaysPerMonth(month, year)); break; case 3: // Last month of the season, season ends on the 20th day = Toolbox.RandomMinMax(1, 20); break; default: day = Toolbox.RandomMinMax(1, GeneratorTools.GetDaysPerMonth(month, year)); break; } } mission.SetValue("DateDay", day); mission.SetValue("DateMonth", (int)month + 1); mission.SetValue("DateYear", year); mission.SetValue("BriefingDate", $"{(int)month + 1:00}/{day:00}/{year:0000}"); BriefingRoom.PrintToLog($"Misson date set to {day} {month} {year}."); return(month); }
internal static void GenerateMissionTime(DCSMission mission, MissionTemplateRecord template, DBEntryTheater theaterDB, Month month) { double totalMinutes; int hour, minute; switch (template.EnvironmentTimeOfDay) { default: // case TimeOfDay.Random totalMinutes = Toolbox.RandomInt(Toolbox.MINUTES_PER_DAY); break; case TimeOfDay.RandomDaytime: totalMinutes = Toolbox.RandomInt(theaterDB.DayTime[(int)month].Min, theaterDB.DayTime[(int)month].Max - 60); break; case TimeOfDay.Dawn: totalMinutes = Toolbox.RandomInt(theaterDB.DayTime[(int)month].Min, theaterDB.DayTime[(int)month].Min + 120); break; case TimeOfDay.Noon: totalMinutes = Toolbox.RandomInt( (theaterDB.DayTime[(int)month].Min + theaterDB.DayTime[(int)month].Max) / 2 - 90, (theaterDB.DayTime[(int)month].Min + theaterDB.DayTime[(int)month].Max) / 2 + 90); break; case TimeOfDay.Twilight: totalMinutes = Toolbox.RandomInt(theaterDB.DayTime[(int)month].Max - 120, theaterDB.DayTime[(int)month].Max + 30); break; case TimeOfDay.Night: totalMinutes = Toolbox.RandomInt(0, theaterDB.DayTime[(int)month].Min - 120); break; } hour = Toolbox.Clamp((int)Math.Floor(totalMinutes / 60), 0, 23); minute = Toolbox.Clamp((int)Math.Floor((totalMinutes - hour * 60) / 15) * 15, 0, 45); mission.SetValue("BriefingTime", $"{hour:00}:{minute:00}"); mission.SetValue("StartTime", hour * 3600 + minute * 60); // DCS World time is stored in seconds since midnight }
internal static void GenerateWarehouses(DCSMission mission) { string warehousesAirportLua = ""; if (!File.Exists(AIRPORT_TEMPLATE_FILEPATH)) { throw new Exception("Airport warehouse template file (Include\\Lua\\Warehouses\\Airport.lua) not found."); } string airportLuaTemplate = File.ReadAllText(AIRPORT_TEMPLATE_FILEPATH); foreach (int airbaseID in mission.Airbases.Keys) { string airportLua = airportLuaTemplate; GeneratorTools.ReplaceKey(ref airportLua, "index", airbaseID); GeneratorTools.ReplaceKey(ref airportLua, "coalition", mission.Airbases[airbaseID].ToString().ToUpperInvariant()); warehousesAirportLua += airportLua + "\r\n"; } mission.SetValue("WarehousesAirports", warehousesAirportLua); }
internal static void GenerateMissionBriefingDescription(DCSMission mission, MissionTemplateRecord template, List <UnitFamily> objectiveTargetUnitFamilies, DBEntrySituation situationDB) { // Try to get the provided custom mission description. string briefingDescription = (template.BriefingMissionDescription ?? "").Replace("\r\n", "\n").Replace("\n", " ").Trim(); // No custom description found, generate one from the most frequent objective task/target combination. if (string.IsNullOrEmpty(briefingDescription)) { if (template.Objectives.Count == 0) { briefingDescription = ""; } else { var familyCount = 0; Dictionary <string, List <string> > descriptionsMap = new Dictionary <string, List <string> >(); foreach (var obj in template.Objectives) { DBEntryBriefingDescription descriptionDB = Database.Instance.GetEntry <DBEntryBriefingDescription>( Database.Instance.GetEntry <DBEntryObjectiveTask>(obj.Task).BriefingDescription); AppendDescription(obj.Task, descriptionDB.DescriptionText[(int)objectiveTargetUnitFamilies[familyCount]], ref descriptionsMap); familyCount++; AddSubTasks(obj, objectiveTargetUnitFamilies, ref descriptionsMap, ref familyCount); } briefingDescription = ConstructTaskDescriptions(descriptionsMap, mission); } } if (situationDB.BriefingDescriptions != null && situationDB.BriefingDescriptions.Count > 0) { briefingDescription = GeneratorTools.ParseRandomString(string.Join(" ", Toolbox.RandomFrom(situationDB.BriefingDescriptions), briefingDescription), mission); } mission.Briefing.Description = briefingDescription; mission.SetValue("BRIEFINGDESCRIPTION", briefingDescription); }
internal static int GenerateWeather(DCSMission mission, MissionTemplateRecord template, DBEntryTheater theaterDB, Month month, DBEntryAirbase playerAirbase) { var baseAlt = template.OptionsMission.Contains("SeaLevelRefCloud") ? 0.0 : playerAirbase.Elevation; if (template.OptionsMission.Contains("HighCloud")) { baseAlt += 2000; } DBEntryWeatherPreset weatherDB; if (string.IsNullOrEmpty(template.EnvironmentWeatherPreset)) // Random weather { weatherDB = Toolbox.RandomFrom(Database.Instance.GetAllEntries <DBEntryWeatherPreset>()); } else { weatherDB = Database.Instance.GetEntry <DBEntryWeatherPreset>(template.EnvironmentWeatherPreset); } mission.SetValue("WeatherName", weatherDB.BriefingDescription); mission.SetValue("WeatherCloudsBase", weatherDB.CloudsBase.GetValue() + baseAlt); mission.SetValue("WeatherCloudsPreset", Toolbox.RandomFrom(weatherDB.CloudsPresets)); mission.SetValue("WeatherCloudsThickness", weatherDB.CloudsThickness.GetValue()); mission.SetValue("WeatherDust", weatherDB.Dust); mission.SetValue("WeatherDustDensity", weatherDB.DustDensity.GetValue()); mission.SetValue("WeatherFog", weatherDB.Fog); mission.SetValue("WeatherFogThickness", weatherDB.FogThickness.GetValue()); mission.SetValue("WeatherFogVisibility", weatherDB.FogVisibility.GetValue()); mission.SetValue("WeatherQNH", weatherDB.QNH.GetValue()); mission.SetValue("WeatherTemperature", theaterDB.Temperature[(int)month].GetValue()); mission.SetValue("WeatherVisibility", weatherDB.Visibility.GetValue()); return(weatherDB.Turbulence.GetValue()); }
internal static void GenerateForcedOptions(DCSMission mission, MissionTemplateRecord template) { string forcedOptionsLua = ""; foreach (RealismOption realismOption in template.OptionsRealism) { switch (realismOption) { case RealismOption.BirdStrikes: forcedOptionsLua += "[\"birds\"] = 300,"; break; case RealismOption.HideLabels: forcedOptionsLua += "[\"labels\"] = 0,"; break; case RealismOption.NoBDA: forcedOptionsLua += "[\"RBDAI\"] = false,\r\n"; break; case RealismOption.NoCheats: forcedOptionsLua += "[\"immortal\"] = false, [\"fuel\"] = false, [\"weapons\"] = false,"; break; case RealismOption.NoCrashRecovery: forcedOptionsLua += "[\"permitCrash\"] = false,"; break; case RealismOption.NoEasyComms: forcedOptionsLua += "[\"easyCommunication\"] = false,"; break; case RealismOption.NoExternalViews: forcedOptionsLua += "[\"externalViews\"] = false,"; break; case RealismOption.NoGameMode: forcedOptionsLua += "[\"easyFlight\"] = false, [\"easyRadar\"] = false,"; break; case RealismOption.NoOverlays: forcedOptionsLua += "[\"miniHUD\"] = false, [\"cockpitStatusBarAllowed\"] = false,"; break; case RealismOption.NoPadlock: forcedOptionsLua += "[\"padlock\"] = false,"; break; case RealismOption.RandomFailures: forcedOptionsLua += "[\"accidental_failures\"] = true,"; break; case RealismOption.RealisticGEffects: forcedOptionsLua += "[\"geffect\"] = \"realistic\","; break; case RealismOption.WakeTurbulence: forcedOptionsLua += "[\"wakeTurbulence\"] = true,"; break; } } // Some realism options are forced OFF when not explicitely enabled if (!template.OptionsRealism.Contains(RealismOption.BirdStrikes)) { forcedOptionsLua += "[\"birds\"] = 0,"; } else if (!template.OptionsRealism.Contains(RealismOption.RandomFailures)) { forcedOptionsLua += "[\"accidental_failures\"] = false,"; } else if (!template.OptionsRealism.Contains(RealismOption.NoBDA)) { forcedOptionsLua += "[\"RBDAI\"] = true,"; } forcedOptionsLua += $"[\"civTraffic\"] = \"{(template.OptionsMission.Contains("EnableCivilianTraffic") ? "medium" : "false")}\","; forcedOptionsLua += $"[\"radio\"] = {(template.OptionsRealism.Contains(RealismOption.DisableDCSRadioAssists) ? "false" : "true")},"; switch (template.OptionsFogOfWar) { default: forcedOptionsLua += "[\"optionsView\"] = \"optview_all\","; break; // case FogOfWar.All case FogOfWar.AlliesOnly: forcedOptionsLua += "[\"optionsView\"] = \"optview_onlyallies\","; break; case FogOfWar.KnownUnitsOnly: forcedOptionsLua += "[\"optionsView\"] = \"optview_allies\","; break; case FogOfWar.SelfOnly: forcedOptionsLua += "[\"optionsView\"] = \"optview_myaircraft\","; break; case FogOfWar.None: forcedOptionsLua += "[\"optionsView\"] = \"optview_onlymap\","; break; } mission.SetValue("ForcedOptions", forcedOptionsLua); }
internal static async Task <DCSMission> GenerateAsync(MissionTemplateRecord template, bool useObjectivePresets) { // Check for missing entries in the database GeneratorTools.CheckDBForMissingEntry <DBEntryCoalition>(template.ContextCoalitionBlue); GeneratorTools.CheckDBForMissingEntry <DBEntryCoalition>(template.ContextCoalitionRed); GeneratorTools.CheckDBForMissingEntry <DBEntryWeatherPreset>(template.EnvironmentWeatherPreset, true); GeneratorTools.CheckDBForMissingEntry <DBEntryTheater>(template.ContextTheater); if (!template.PlayerFlightGroups.Any(x => !x.Hostile)) { throw new BriefingRoomException("Cannot have all players on hostile side."); } var mission = new DCSMission(); var waypoints = new List <Waypoint>(); var immediateActivationAircraftGroupsIDs = new List <int>(); var lateActivationAircraftGroupsIDs = new List <int>(); var theaterDB = Database.Instance.GetEntry <DBEntryTheater>(template.ContextTheater); var situationDB = Toolbox.RandomFrom( Database.Instance.GetAllEntries <DBEntrySituation>() .Where(x => x.Theater == template.ContextTheater.ToLower()) .ToArray() ); if (template.ContextSituation.StartsWith(template.ContextTheater)) { situationDB = Database.Instance.GetEntry <DBEntrySituation>(template.ContextSituation); } var coalitionsDB = new DBEntryCoalition[] { Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionBlue), Database.Instance.GetEntry <DBEntryCoalition>(template.ContextCoalitionRed) }; // Copy values from the template mission.SetValue("BriefingTheater", theaterDB.UIDisplayName); mission.SetValue("BriefingSituation", situationDB.UIDisplayName); mission.SetValue("BriefingAllyCoalition", coalitionsDB[(int)template.ContextPlayerCoalition].UIDisplayName); mission.SetValue("BriefingEnemyCoalition", coalitionsDB[(int)template.ContextPlayerCoalition.GetEnemy()].UIDisplayName); mission.SetValue("EnableAudioRadioMessages", !template.OptionsMission.Contains("RadioMessagesTextOnly")); mission.SetValue("LuaPlayerCoalition", $"coalition.side.{template.ContextPlayerCoalition.ToString().ToUpperInvariant()}"); mission.SetValue("LuaEnemyCoalition", $"coalition.side.{template.ContextPlayerCoalition.GetEnemy().ToString().ToUpperInvariant()}"); mission.SetValue("TheaterID", theaterDB.DCSID); mission.SetValue("AircraftActivatorCurrentQueue", ""); // Just to make sure aircraft groups spawning queues are empty mission.SetValue("AircraftActivatorReserveQueue", ""); mission.SetValue("MissionPlayerSlots", template.GetPlayerSlotsCount() == 1 ? "Single-player mission" : $"{template.GetPlayerSlotsCount()}-players mission"); foreach (string oggFile in Database.Instance.Common.CommonOGG) { mission.AddMediaFile($"l10n/DEFAULT/{Toolbox.AddMissingFileExtension(oggFile, ".ogg")}", $"{BRPaths.INCLUDE_OGG}{Toolbox.AddMissingFileExtension(oggFile, ".ogg")}"); } var coalitionsCountries = MissionGeneratorCountries.GenerateCountries(mission, template); var unitMaker = new UnitMaker(mission, template, coalitionsDB, theaterDB, situationDB, template.ContextPlayerCoalition, coalitionsCountries, template.GetPlayerSlotsCount() == 1); var drawingMaker = new DrawingMaker(mission, template, theaterDB, situationDB); var zoneMaker = new ZoneMaker(unitMaker); BriefingRoom.PrintToLog("Generating mission date and time..."); var month = MissionGeneratorDateTime.GenerateMissionDate(mission, template); MissionGeneratorDateTime.GenerateMissionTime(mission, template, theaterDB, month); BriefingRoom.PrintToLog("Setting up airbases..."); var airbasesGenerator = new MissionGeneratorAirbases(template, situationDB); var requiredRunway = template.PlayerFlightGroups.Select(x => Database.Instance.GetEntry <DBEntryUnit>(x.Aircraft).AircraftData.MinimumRunwayLengthFt).Max(); var playerAirbase = airbasesGenerator.SelectStartingAirbase(mission, template.FlightPlanTheaterStartingAirbase, requiredRunway: requiredRunway); mission.Briefing.AddItem(DCSMissionBriefingItemType.Airbase, $"{playerAirbase.Name}\t{playerAirbase.Runways}\t{playerAirbase.ATC}\t{playerAirbase.ILS}\t{playerAirbase.TACAN}"); airbasesGenerator.SelectStartingAirbaseForPackages(mission, playerAirbase); airbasesGenerator.SetupAirbasesCoalitions(mission, playerAirbase); zoneMaker.AddAirbaseZones(playerAirbase, mission.MissionPackages); mission.SetValue("PlayerAirbaseName", playerAirbase.Name); mission.SetValue("MissionAirbaseX", playerAirbase.Coordinates.X); mission.SetValue("MissionAirbaseY", playerAirbase.Coordinates.Y); BriefingRoom.PrintToLog("Generating mission weather..."); var turbulenceFromWeather = MissionGeneratorWeather.GenerateWeather(mission, template, theaterDB, month, playerAirbase); var(windSpeedAtSeaLevel, windDirectionAtSeaLevel) = MissionGeneratorWeather.GenerateWind(mission, template, turbulenceFromWeather); // Generate objectives BriefingRoom.PrintToLog("Generating objectives..."); var objectiveCoordinates = new List <Coordinates>(); var objectiveTargetUnitFamilies = new List <UnitFamily>(); var lastObjectiveCoordinates = playerAirbase.Coordinates; var objectivesGenerator = new MissionGeneratorObjectives(unitMaker, drawingMaker, template); var objectiveGroupedWaypoints = new List <List <Waypoint> >(); var i = 0; foreach (var objectiveTemplate in template.Objectives) { var(objectiveCoords, waypointGroup) = objectivesGenerator.GenerateObjective( mission, template, situationDB, objectiveTemplate, lastObjectiveCoordinates, playerAirbase, useObjectivePresets, ref i, ref objectiveCoordinates, ref waypoints, ref objectiveTargetUnitFamilies); lastObjectiveCoordinates = objectiveCoords; objectiveGroupedWaypoints.Add(waypointGroup); i++; } var objectivesCenter = (objectiveCoordinates.Count == 0) ? playerAirbase.Coordinates : Coordinates.Sum(objectiveCoordinates) / objectiveCoordinates.Count; mission.SetValue("MissionCenterX", objectivesCenter.X); mission.SetValue("MissionCenterY", objectivesCenter.Y); // Generate carrier groups BriefingRoom.PrintToLog("Generating carrier groups..."); var carrierDictionary = MissionGeneratorCarrierGroup.GenerateCarrierGroup( unitMaker, zoneMaker, mission, template, playerAirbase.Coordinates, objectivesCenter, windSpeedAtSeaLevel, windDirectionAtSeaLevel); var averageInitialPosition = playerAirbase.Coordinates; if (carrierDictionary.Count > 0) { averageInitialPosition = (averageInitialPosition + carrierDictionary.First().Value.Coordinates) / 2.0; } // Generate extra flight plan info MissionGeneratorFlightPlan.GenerateBullseyes(mission, objectivesCenter); MissionGeneratorFlightPlan.GenerateObjectiveWPCoordinatesLua(template, mission, waypoints, drawingMaker); MissionGeneratorFlightPlan.GenerateAircraftPackageWaypoints(template, mission, objectiveGroupedWaypoints, averageInitialPosition, objectivesCenter); MissionGeneratorFlightPlan.GenerateIngressAndEgressWaypoints(template, waypoints, averageInitialPosition, objectivesCenter); // Generate surface-to-air defenses MissionGeneratorAirDefense.GenerateAirDefense(template, unitMaker, averageInitialPosition, objectivesCenter); // Generate combat air patrols var capGroupsID = MissionGeneratorCombatAirPatrols.GenerateCAP(unitMaker, template, averageInitialPosition, objectivesCenter); foreach (int capGroupID in capGroupsID) // Add 50% of CAP groups to the list of A/C activated on takeoff, the other 50% to the list of A/C activated later. { if (Toolbox.RandomChance(2)) { immediateActivationAircraftGroupsIDs.Add(capGroupID); } else { lateActivationAircraftGroupsIDs.Add(capGroupID); } } // Generate player flight groups BriefingRoom.PrintToLog("Generating player flight groups..."); foreach (var templateFlightGroup in template.PlayerFlightGroups) { MissionGeneratorPlayerFlightGroups.GeneratePlayerFlightGroup(unitMaker, mission, template, templateFlightGroup, playerAirbase, waypoints, carrierDictionary, averageInitialPosition, objectivesCenter); } // Generate mission features BriefingRoom.PrintToLog("Generating mission features..."); mission.AppendValue("ScriptMissionFeatures", ""); // Just in case there's no features var missionFeaturesGenerator = new MissionGeneratorFeaturesMission(unitMaker, template); foreach (var templateFeature in template.MissionFeatures) { missionFeaturesGenerator.GenerateMissionFeature(mission, templateFeature, playerAirbase.Coordinates, objectivesCenter); } // Add ogg files to the media files dictionary foreach (string mediaFile in mission.GetMediaFileNames()) { if (!mediaFile.ToLowerInvariant().EndsWith(".ogg")) { continue; // Not an .ogg file } mission.AppendValue("MapResourcesFiles", $"[\"ResKey_Snd_{Path.GetFileNameWithoutExtension(mediaFile)}\"] = \"{Path.GetFileName(mediaFile)}\",\n"); } // Get unit tables from the unit maker (MUST BE DONE AFTER ALL UNITS ARE GENERATED) mission.SetValue("CountriesBlue", unitMaker.GetUnitsLuaTable(Coalition.Blue)); mission.SetValue("CountriesRed", unitMaker.GetUnitsLuaTable(Coalition.Red)); mission.SetValue("Drawings", drawingMaker.GetLuaDrawings()); mission.SetValue("Zones", zoneMaker.GetLuaZones()); // Generate briefing and additional mission info BriefingRoom.PrintToLog("Generating briefing..."); var missionName = GeneratorTools.GenerateMissionName(template.BriefingMissionName); mission.Briefing.Name = missionName; mission.SetValue("MISSIONNAME", missionName); MissionGeneratorBriefing.GenerateMissionBriefingDescription(mission, template, objectiveTargetUnitFamilies, situationDB); mission.SetValue("DescriptionText", mission.Briefing.GetBriefingAsRawText("\\\n")); // Generate mission options BriefingRoom.PrintToLog("Generating options..."); MissionGeneratorOptions.GenerateForcedOptions(mission, template); // Generate warehouses BriefingRoom.PrintToLog("Generating warehouses..."); MissionGeneratorWarehouses.GenerateWarehouses(mission); // Generate image files BriefingRoom.PrintToLog("Generating images..."); MissionGeneratorImages.GenerateTitle(mission, template); await MissionGeneratorImages.GenerateKneeboardImagesAsync(mission); return(mission); }