private Coordinates PlaceInAirbase(MissionTemplateRecord template, DBEntrySituation situationDB, DBEntryAirbase playerAirbase, List <KeyValuePair <string, object> > extraSettings, DBEntryObjectiveTarget targetDB, DBEntryObjectiveTargetBehavior targetBehaviorDB, ref string luaUnit, Coordinates objectiveCoordinates, int unitCount, UnitFamily objectiveTargetUnitFamily) { int airbaseID = 0; var parkingSpotIDsList = new List <int>(); var parkingSpotCoordinatesList = new List <Coordinates>(); var targetAirbaseOptions = (from DBEntryAirbase airbaseDB in situationDB.GetAirbases(template.OptionsMission.Contains("InvertCountriesCoalitions")) where airbaseDB.DCSID != playerAirbase.DCSID select airbaseDB).OrderBy(x => x.Coordinates.GetDistanceFrom(objectiveCoordinates)); DBEntryAirbase targetAirbase = targetAirbaseOptions.FirstOrDefault(x => template.OptionsMission.Contains("SpawnAnywhere") ? true : x.Coalition == template.ContextPlayerCoalition.GetEnemy()); airbaseID = targetAirbase.DCSID; var parkingSpots = UnitMaker.SpawnPointSelector.GetFreeParkingSpots( targetAirbase.DCSID, unitCount, objectiveTargetUnitFamily, targetBehaviorDB.Location == DBEntryObjectiveTargetBehaviorLocation.SpawnOnAirbaseParkingNoHardenedShelter); parkingSpotIDsList = parkingSpots.Select(x => x.DCSID).ToList(); parkingSpotCoordinatesList = parkingSpots.Select(x => x.Coordinates).ToList(); luaUnit += "Parked"; extraSettings.Add("GroupAirbaseID".ToKeyValuePair(airbaseID)); extraSettings.Add("ParkingID".ToKeyValuePair(parkingSpotIDsList.ToArray())); extraSettings.Add("UnitX".ToKeyValuePair((from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.X).ToArray())); extraSettings.Add("UnitY".ToKeyValuePair((from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.Y).ToArray())); return(targetAirbase.Coordinates); }
private static void CreateLua(DCSMission mission, MissionTemplateRecord template, DBEntryObjectiveTarget targetDB, DBEntryObjectiveTask taskDB, int objectiveIndex, string objectiveName, UnitMakerGroupInfo?targetGroupInfo, string taskString) { // Add Lua table for this objective string objectiveLua = $"briefingRoom.mission.objectives[{objectiveIndex + 1}] = {{ "; objectiveLua += $"complete = false, "; objectiveLua += $"groupID = {targetGroupInfo.Value.GroupID}, "; objectiveLua += $"hideTargetCount = false, "; objectiveLua += $"name = \"{objectiveName}\", "; objectiveLua += $"targetCategory = Unit.Category.{targetDB.UnitCategory.ToLuaName()}, "; objectiveLua += $"taskType = \"{taskDB.ID}\", "; objectiveLua += $"task = \"{taskString}\", "; objectiveLua += $"unitsCount = {targetGroupInfo.Value.UnitsID.Length}, "; objectiveLua += $"unitsID = {{ {string.Join(", ", targetGroupInfo.Value.UnitsID)} }} "; objectiveLua += "}\n"; // Add F10 sub-menu for this objective objectiveLua += $"briefingRoom.f10Menu.objectives[{objectiveIndex + 1}] = missionCommands.addSubMenuForCoalition(coalition.side.{template.ContextPlayerCoalition.ToString().ToUpperInvariant()}, \"Objective {objectiveName}\", nil)\n"; mission.AppendValue("ScriptObjectives", objectiveLua); // Add objective trigger Lua for this objective string triggerLua = Toolbox.ReadAllTextIfFileExists($"{BRPaths.INCLUDE_LUA_OBJECTIVETRIGGERS}{taskDB.CompletionTriggerLua}"); GeneratorTools.ReplaceKey(ref triggerLua, "ObjectiveIndex", objectiveIndex + 1); mission.AppendValue("ScriptObjectivesTriggers", triggerLua); }
internal static string[] GetEmbeddedAirDefenseUnits(MissionTemplateRecord template, Side side, Country?country = null) { DBCommonAirDefenseLevel airDefenseInfo = (side == Side.Ally) ? Database.Instance.Common.AirDefense.AirDefenseLevels[(int)template.SituationFriendlyAirDefense.Get()] : Database.Instance.Common.AirDefense.AirDefenseLevels[(int)template.SituationEnemyAirDefense.Get()]; DBEntryCoalition unitsCoalitionDB = Database.Instance.GetEntry <DBEntryCoalition>(template.GetCoalitionID(side)); if (unitsCoalitionDB == null) { return(new string[0]); } List <string> units = new List <string>(); if (Toolbox.RandomDouble() >= airDefenseInfo.EmbeddedChance) { return(new string[0]); } int airDefenseUnitsCount = airDefenseInfo.EmbeddedUnitCount.GetValue(); for (int i = 0; i < airDefenseUnitsCount; i++) { var families = new List <UnitFamily> { UnitFamily.VehicleAAA, UnitFamily.VehicleAAA, UnitFamily.VehicleSAMShortIR, UnitFamily.VehicleSAMShortIR, UnitFamily.VehicleSAMShort }; units.AddRange(unitsCoalitionDB.GetRandomUnits(families, template.ContextDecade, 1, template.Mods, country).Item2); } return(units.ToArray()); }
internal Tuple <DBEntryAirbase, List <int>, List <Coordinates> > GetAirbaseAndParking( MissionTemplateRecord template, Coordinates coordinates, int unitCount, Coalition coalition, UnitFamily unitFamily) { var targetAirbaseOptions = (from DBEntryAirbase airbaseDB in SituationDB.GetAirbases(template.OptionsMission.Contains("InvertCountriesCoalitions")) where airbaseDB.Coalition == coalition && ValidateAirfieldParking(AirbaseParkingSpots[airbaseDB.DCSID], unitFamily, unitCount) && ValidateAirfieldRunway(airbaseDB, unitFamily) select airbaseDB).OrderBy(x => x.Coordinates.GetDistanceFrom(coordinates)); if (targetAirbaseOptions.Count() == 0) { throw new BriefingRoomException("No airbase found for aircraft."); } var targetAirbase = targetAirbaseOptions.First(); var objectiveCoordinates = targetAirbase.Coordinates; var airbaseID = targetAirbase.DCSID; var parkingSpotIDsList = new List <int>(); var parkingSpotCoordinatesList = new List <Coordinates>(); var parkingSpots = GetFreeParkingSpots(airbaseID, unitCount, unitFamily); parkingSpotIDsList = parkingSpots.Select(x => x.DCSID).ToList(); parkingSpotCoordinatesList = parkingSpots.Select(x => x.Coordinates).ToList(); return(Tuple.Create(targetAirbase, parkingSpotIDsList, parkingSpotCoordinatesList)); }
internal static void GenerateTitle(DCSMission mission, MissionTemplateRecord template) { ImageMaker imageMaker = new(); imageMaker.TextOverlay.Alignment = ContentAlignment.MiddleCenter; imageMaker.TextOverlay.Text = mission.Briefing.Name; List <ImageMakerLayer> imageLayers = new List <ImageMakerLayer>(); string[] theaterImages = Directory.GetFiles($"{BRPaths.INCLUDE_JPG}Theaters\\", $"{Database.Instance.GetEntry<DBEntryTheater>(template.ContextTheater).DCSID}*.jpg"); if (theaterImages.Length == 0) { imageLayers.Add(new ImageMakerLayer("_default.jpg")); } else { imageLayers.Add(new ImageMakerLayer("Theaters\\" + Path.GetFileName(Toolbox.RandomFrom(theaterImages)))); } imageLayers.Add(new ImageMakerLayer($"Flags\\{template.GetCoalitionID(template.ContextPlayerCoalition)}.png", ContentAlignment.TopLeft, 8, 8, 0, .5)); byte[] imageBytes = imageMaker.GetImageBytes(imageLayers.ToArray()); mission.AddMediaFile($"l10n/DEFAULT/title_{mission.UniqueID}.jpg", imageBytes); }
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 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 string GetTemplateCoalition(MissionTemplateRecord template, Coalition coalition) { if (coalition == Coalition.Red) { return(template.ContextCoalitionRed); } return(template.ContextCoalitionBlue); }
private static Tuple <Coordinates, Coordinates> GetSpawnAndDestination( UnitMaker unitMaker, MissionTemplateRecord template, DBEntryTheater theaterDB, List <Coordinates> usedCoordinates, Coordinates landbaseCoordinates, Coordinates objectivesCenter, double carrierPathDeg) { var travelMinMax = new MinMaxD(Database.Instance.Common.CarrierGroup.CourseLength, Database.Instance.Common.CarrierGroup.CourseLength * 2); Coordinates?carrierGroupCoordinates = null; Coordinates?destinationPath = null; var iteration = 0; var maxDistance = 25; while (iteration < 100) { carrierGroupCoordinates = unitMaker.SpawnPointSelector.GetRandomSpawnPoint( new SpawnPointType[] { SpawnPointType.Sea }, landbaseCoordinates, new MinMaxD(10, maxDistance), objectivesCenter, new MinMaxD(10, 99999), GeneratorTools.GetSpawnPointCoalition(template, Side.Ally)); if (!carrierGroupCoordinates.HasValue) { maxDistance += 25; continue; } var minDist = usedCoordinates.Aggregate(99999999.0, (acc, x) => x.GetDistanceFrom(carrierGroupCoordinates.Value) < acc ? x.GetDistanceFrom(carrierGroupCoordinates.Value) : acc); if (minDist < Database.Instance.Common.CarrierGroup.ShipSpacing) { continue; } destinationPath = Coordinates.FromAngleAndDistance(carrierGroupCoordinates.Value, travelMinMax, carrierPathDeg); if (ShapeManager.IsPosValid(destinationPath.Value, theaterDB.WaterCoordinates, theaterDB.WaterExclusionCoordinates)) { break; } iteration++; if (iteration > 10) { maxDistance += 1; } } if (!carrierGroupCoordinates.HasValue) { throw new BriefingRoomException($"Carrier spawnpoint could not be found."); } if (!destinationPath.HasValue) { throw new BriefingRoomException($"Carrier destination could not be found."); } if (!ShapeManager.IsPosValid(destinationPath.Value, theaterDB.WaterCoordinates, theaterDB.WaterExclusionCoordinates)) { throw new BriefingRoomException($"Carrier waypoint is on shore"); } return(new(carrierGroupCoordinates.Value, destinationPath.Value)); }
private static void GenerateFOB( UnitMaker unitMaker, ZoneMaker zoneMaker, MissionTemplateFlightGroupRecord flightGroup, Dictionary <string, UnitMakerGroupInfo> carrierDictionary, DCSMission mission, MissionTemplateRecord template, Coordinates landbaseCoordinates, Coordinates objectivesCenter) { DBEntryTheater theaterDB = Database.Instance.GetEntry <DBEntryTheater>(template.ContextTheater); if (theaterDB == null) { return; // Theater doesn't exist. Should never happen. } Coordinates?spawnPoint = unitMaker.SpawnPointSelector.GetRandomSpawnPoint( new SpawnPointType[] { SpawnPointType.LandLarge }, landbaseCoordinates, new MinMaxD(5, template.FlightPlanObjectiveDistance), objectivesCenter, new MinMaxD(10, template.FlightPlanObjectiveDistance / 2), template.ContextPlayerCoalition); if (!spawnPoint.HasValue) { BriefingRoom.PrintToLog($"No spawn point found for FOB air defense unit groups", LogMessageErrorLevel.Warning); return; } DBEntryUnit unitDB = Database.Instance.GetEntry <DBEntryUnit>(flightGroup.Carrier); if (unitDB == null) { return; // Unit doesn't exist or is not a carrier } double radioFrequency = 127.5 + carrierDictionary.Count; var FOBNames = new List <string> { "FOB_London", "FOB_Dallas", "FOB_Paris", "FOB_Moscow", "FOB_Berlin" }; UnitMakerGroupInfo?groupInfo = unitMaker.AddUnitGroup( unitDB.Families[0], 1, Side.Ally, "GroupStatic", "UnitStaticFOB", spawnPoint.Value, 0, "FOBCallSignIndex".ToKeyValuePair(FOBNames.IndexOf(flightGroup.Carrier) + 1), "RadioBand".ToKeyValuePair((int)RadioModulation.AM), "RadioFrequency".ToKeyValuePair(GeneratorTools.GetRadioFrenquency(radioFrequency))); if (!groupInfo.HasValue || (groupInfo.Value.UnitsID.Length == 0)) { return; // Couldn't generate group } zoneMaker.AddCTLDPickupZone(spawnPoint.Value, true); mission.Briefing.AddItem( DCSMissionBriefingItemType.Airbase, $"{unitDB.UIDisplayName}\t-\t{GeneratorTools.FormatRadioFrequency(radioFrequency)}\t\t"); carrierDictionary.Add(flightGroup.Carrier, groupInfo.Value); // This bit limits FOBS to one per game think about how we can fix this }
internal static void GenerateAircraftPackageWaypoints(MissionTemplateRecord template, DCSMission mission, List <List <Waypoint> > objectiveGroupedWaypoints, Coordinates averageInitialLocation, Coordinates objectivesCenter) { foreach (var package in template.AircraftPackages) { var missionPackage = mission.MissionPackages.First(x => x.RecordIndex == template.AircraftPackages.IndexOf(package)); missionPackage.Waypoints = objectiveGroupedWaypoints.Where((v, i) => package.ObjectiveIndexes.Contains(i)).SelectMany(x => x).ToList(); // THIS IS WHERE THE OBJECTIVES ARE BROKEN GenerateIngressAndEgressWaypoints(template, missionPackage.Waypoints, averageInitialLocation, objectivesCenter); } }
internal DrawingMaker( DCSMission mission, MissionTemplateRecord template, DBEntryTheater theaterDB, DBEntrySituation situationDB) { Mission = mission; Template = template; TheaterDB = theaterDB; SituationDB = situationDB; Clear(); AddTheaterZones(); }
internal static Coalition?GetSpawnPointCoalition(MissionTemplateRecord template, Side side, bool forceSide = false) { // No countries spawning restriction if (template.OptionsMission.Contains("SpawnAnywhere") && !forceSide) { return(null); } Coalition coalition = side == Side.Ally ? template.ContextPlayerCoalition : template.ContextPlayerCoalition.GetEnemy(); return(coalition); }
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(), }); }
private Coordinates GetNearestSpawnCoordinates(MissionTemplateRecord template, Coordinates coreCoordinates, DBEntryObjectiveTarget targetDB) { Coordinates?spawnPoint = UnitMaker.SpawnPointSelector.GetNearestSpawnPoint( targetDB.ValidSpawnPoints, coreCoordinates); if (!spawnPoint.HasValue) { throw new BriefingRoomException($"Failed to spawn objective unit group. {String.Join(",", targetDB.ValidSpawnPoints.Select(x => x.ToString()).ToList())} Please try again (Consider Adusting Flight Plan)"); } Coordinates objectiveCoordinates = spawnPoint.Value; return(objectiveCoordinates); }
internal static async Task <DCSMission> GenerateRetryableAsync(MissionTemplate template, bool useObjectivePresets) { var templateRecord = new MissionTemplateRecord(template); var mission = await Policy .HandleResult <DCSMission>(x => x.IsExtremeDistance(template, out double distance)) .Or <BriefingRoomException>() .RetryAsync(3) .ExecuteAsync(() => GenerateAsync(templateRecord, useObjectivePresets)); if (mission.IsExtremeDistance(template, out double distance)) { BriefingRoom.PrintToLog($"Distance to objectives exceeds 1.7x of requested distance. ({Math.Round(distance, 2)}NM)", LogMessageErrorLevel.Warning); } return(mission); }
private void AddEmbeddedAirDefenseUnits(MissionTemplateRecord template, DBEntryObjectiveTarget targetDB, DBEntryObjectiveTargetBehavior targetBehaviorDB, DBEntryObjectiveTask taskDB, ObjectiveOption[] objectiveOptions, Coordinates objectiveCoordinates, UnitMakerGroupFlags groupFlags, List <KeyValuePair <string, object> > extraSettings) { // Static targets (aka buildings) need to have their "embedded" air defenses spawned in another group string[] airDefenseUnits = GeneratorTools.GetEmbeddedAirDefenseUnits(template, taskDB.TargetSide); if (airDefenseUnits.Length > 0) { UnitMaker.AddUnitGroup( airDefenseUnits, taskDB.TargetSide, UnitFamily.VehicleAAA, targetBehaviorDB.GroupLua[(int)targetDB.UnitCategory], targetBehaviorDB.UnitLua[(int)targetDB.UnitCategory], objectiveCoordinates + Coordinates.CreateRandom(100, 500), groupFlags, extraSettings.ToArray()); } }
internal static void GenerateAirDefense(MissionTemplateRecord template, UnitMaker unitMaker, Coordinates averageInitialPosition, Coordinates objectivesCenter) { foreach (Coalition coalition in Toolbox.GetEnumValues <Coalition>()) { bool ally = coalition == template.ContextPlayerCoalition; Side side = ally ? Side.Ally : Side.Enemy; AmountNR airDefenseAmount = ally ? template.SituationFriendlyAirDefense.Get() : template.SituationEnemyAirDefense.Get(); Coordinates centerPoint = ally ? averageInitialPosition : objectivesCenter; Coordinates opposingPoint = ally ? objectivesCenter : averageInitialPosition; foreach (AirDefenseRange airDefenseRange in Toolbox.GetEnumValues <AirDefenseRange>()) { CreateAirDefenseGroups(template, unitMaker, side, coalition, airDefenseAmount, airDefenseRange, centerPoint, opposingPoint); } } }
internal static void GenerateObjectiveWPCoordinatesLua(MissionTemplateRecord template, DCSMission mission, List <Waypoint> waypoints, DrawingMaker DrawingMaker) { var scriptWaypoints = waypoints.Where(x => !x.ScriptIgnore).ToList(); for (int i = 0; i < scriptWaypoints.Count; i++) { mission.AppendValue("ScriptObjectives", $"briefingRoom.mission.objectives[{i + 1}].waypoint = {scriptWaypoints[i].Coordinates.ToLuaTable()}\n"); } if (template.OptionsMission.Contains("MarkWaypoints")) { foreach (var waypoint in waypoints) { DrawingMaker.AddDrawing(waypoint.Name, DrawingType.TextBox, waypoint.Coordinates, "Text".ToKeyValuePair(waypoint.Name)); } } }
internal static async Task <DCSCampaign> GenerateAsync(CampaignTemplate campaignTemplate) { DCSCampaign campaign = new(); campaign.Name = GeneratorTools.GenerateMissionName(campaignTemplate.BriefingCampaignName);; string baseFileName = Toolbox.RemoveInvalidPathCharacters(campaign.Name); DateTime date = GenerateCampaignDate(campaignTemplate); campaignTemplate.Player.AIWingmen = true; //Make sure wingmen is always true for campaign for (int i = 0; i < campaignTemplate.MissionsCount; i++) { // Increment the date by a few days for each mission after the first if (i > 0) { date = IncrementDate(date); } MissionTemplateRecord template = CreateMissionTemplate(campaignTemplate, campaign.Name, i, (int)campaignTemplate.MissionsObjectiveCount); DCSMission mission = await MissionGenerator.GenerateAsync(template, true); // TODO: mission.DateTime.Day = date.Day; mission.DateTime.Month = date.Month; mission.DateTime.Year = date.Year; if (mission == null) { BriefingRoom.PrintToLog($"Failed to generate mission {i + 1} in the campaign.", LogMessageErrorLevel.Warning); continue; } campaign.AddMission(mission); } if (campaign.MissionCount < 1) // No missions generated, something went very wrong. { throw new BriefingRoomException($"Campaign has no valid mission."); } CreateImageFiles(campaignTemplate, campaign, baseFileName); campaign.CMPFile = GetCMPFile(campaignTemplate, campaign.Name); return(campaign); }
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 UnitMaker( DCSMission mission, MissionTemplateRecord template, DBEntryCoalition[] coalitionsDB, DBEntryTheater theaterDB, DBEntrySituation situationDB, Coalition playerCoalition, Country[][] coalitionsCountries, bool singlePlayerMission) { CallsignGenerator = new UnitMakerCallsignGenerator(coalitionsDB); SpawnPointSelector = new UnitMakerSpawnPointSelector(theaterDB, situationDB, template.OptionsMission.Contains("InvertCountriesCoalitions")); Mission = mission; Template = template; CoalitionsDB = coalitionsDB; PlayerCoalition = playerCoalition; CoalitionsCountries = coalitionsCountries; SinglePlayerMission = singlePlayerMission; GroupID = 1; UnitID = 1; }
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 int[] GenerateCAP(UnitMaker unitMaker, MissionTemplateRecord template, Coordinates averageInitialPosition, Coordinates objectivesCenter) { List <int> capAircraftGroupIDs = new List <int>(); var commonCAPDB = Database.Instance.Common.CAP; foreach (Coalition coalition in Toolbox.GetEnumValues <Coalition>()) { if (coalition == Coalition.Neutural) // Skip Neutural { continue; } bool ally = coalition == template.ContextPlayerCoalition; Side side = ally ? Side.Ally : Side.Enemy; AmountNR capAmount = ally ? template.SituationFriendlyAirForce.Get() : template.SituationEnemyAirForce.Get(); Coordinates flyPathtoObjectives = (objectivesCenter - averageInitialPosition).Normalize() * Toolbox.NM_TO_METERS * commonCAPDB.MinDistanceFromOpposingPoint; // TODO: distance according to decade Coordinates centerPoint = objectivesCenter; if (ally) { centerPoint -= flyPathtoObjectives; } else { centerPoint += flyPathtoObjectives; } Coordinates opposingPoint = objectivesCenter; CreateCAPGroups( unitMaker, template, side, coalition, capAmount, centerPoint, opposingPoint, objectivesCenter, ref capAircraftGroupIDs); } return(capAircraftGroupIDs.ToArray()); }
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 void GenerateIngressAndEgressWaypoints(MissionTemplateRecord template, List <Waypoint> waypoints, Coordinates averageInitialLocation, Coordinates objectivesCenter) { if (!template.MissionFeatures.Contains("IngressEgressWaypoints")) { return; } BriefingRoom.PrintToLog($"Generating ingress and egress waypoints..."); double flightPathLength = (objectivesCenter - averageInitialLocation).GetLength(); double ingressDeviation = Math.Max(4.0, flightPathLength * .15); Coordinates baseIngressPosition = averageInitialLocation + (objectivesCenter - averageInitialLocation) * .7f; waypoints.Insert(0, new Waypoint( Database.Instance.Common.Names.WPIngressName, baseIngressPosition + Coordinates.CreateRandom(ingressDeviation * 0.9, ingressDeviation * 1.1))); waypoints.Add( new Waypoint( Database.Instance.Common.Names.WPEgressName, baseIngressPosition + Coordinates.CreateRandom(ingressDeviation * 0.9, ingressDeviation * 1.1))); }
private Coordinates GetSpawnCoordinates(MissionTemplateRecord template, Coordinates lastCoordinates, DBEntryAirbase playerAirbase, DBEntryObjectiveTarget targetDB) { int objectiveDistance = template.FlightPlanObjectiveDistance; if (objectiveDistance < 1) { objectiveDistance = Toolbox.RandomInt(40, 160); } int objectiveSeperation = template.FlightPlanObjectiveSeperation; if (objectiveSeperation < 1) { objectiveSeperation = Toolbox.RandomInt(10, 100); } Coordinates?spawnPoint = UnitMaker.SpawnPointSelector.GetRandomSpawnPoint( targetDB.ValidSpawnPoints, playerAirbase.Coordinates, new MinMaxD( objectiveDistance * OBJECTIVE_DISTANCE_VARIATION_MIN, objectiveDistance * OBJECTIVE_DISTANCE_VARIATION_MAX), lastCoordinates, new MinMaxD( objectiveSeperation * OBJECTIVE_DISTANCE_VARIATION_MIN, objectiveSeperation * OBJECTIVE_DISTANCE_VARIATION_MAX), GeneratorTools.GetSpawnPointCoalition(template, Side.Enemy)); if (!spawnPoint.HasValue) { throw new BriefingRoomException($"Failed to spawn objective unit group. {String.Join(",", targetDB.ValidSpawnPoints.Select(x => x.ToString()).ToList())} Please try again (Consider Adusting Flight Plan)"); } Coordinates objectiveCoordinates = spawnPoint.Value; return(objectiveCoordinates); }
internal MissionGeneratorFeatures(UnitMaker unitMaker, MissionTemplateRecord template) { _unitMaker = unitMaker; _template = template; }
private static void CreateCAPGroups( UnitMaker unitMaker, MissionTemplateRecord template, Side side, Coalition coalition, AmountNR capAmount, Coordinates centerPoint, Coordinates opposingPoint, Coordinates destination, ref List <int> capAircraftGroupIDs) { var commonCAPDB = Database.Instance.Common.CAP; DBCommonCAPLevel capLevelDB = commonCAPDB.CAPLevels[(int)capAmount]; int unitsLeftToSpawn = capLevelDB.UnitCount.GetValue(); if (unitsLeftToSpawn < 1) { return; // No groups to add, no need to go any further } do { int groupSize = Toolbox.RandomFrom(commonCAPDB.GroupSize); groupSize = Math.Min(unitsLeftToSpawn, groupSize); unitsLeftToSpawn -= groupSize; // Find spawn point at the proper distance from the objective(s), but not to close from starting airbase Coordinates?spawnPoint = unitMaker.SpawnPointSelector.GetRandomSpawnPoint( new SpawnPointType[] { SpawnPointType.Air }, centerPoint, commonCAPDB.DistanceFromCenter, opposingPoint, new MinMaxD(commonCAPDB.MinDistanceFromOpposingPoint, 99999), GeneratorTools.GetSpawnPointCoalition(template, side)); // No spawn point found, stop here. if (!spawnPoint.HasValue) { BriefingRoom.PrintToLog($"No spawn point found for {coalition} combat air patrols.", LogMessageErrorLevel.Warning); return; } Coordinates groupDestination = destination + Coordinates.CreateRandom(10, 20) * Toolbox.NM_TO_METERS; var extraSettings = new Dictionary <string, object> { { "Payload", "Air-To-Air" }, { "GroupX2", groupDestination.X }, { "GroupY2", groupDestination.Y } }; var luaUnit = commonCAPDB.LuaUnit; var luaGroup = commonCAPDB.LuaGroup; var spawnpointCoordinates = spawnPoint.Value; var unitFamilies = commonCAPDB.UnitFamilies.ToList(); if (template.MissionFeatures.Contains("ContextGroundStartAircraft")) { luaGroup += "Parked"; luaUnit += "Parked"; var(airbase, parkingSpotIDsList, parkingSpotCoordinatesList) = unitMaker.SpawnPointSelector.GetAirbaseAndParking(template, spawnPoint.Value, groupSize, coalition, unitFamilies.First()); spawnpointCoordinates = airbase.Coordinates; extraSettings.AddIfKeyUnused("ParkingID", parkingSpotIDsList.ToArray()); extraSettings.AddIfKeyUnused("GroupAirbaseID", airbase.DCSID); extraSettings.AddIfKeyUnused("UnitX", (from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.X).ToArray()); extraSettings.AddIfKeyUnused("UnitY", (from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.Y).ToArray()); } UnitMakerGroupInfo?groupInfo = unitMaker.AddUnitGroup( unitFamilies, groupSize, side, luaGroup, luaUnit, spawnpointCoordinates, 0, extraSettings.ToArray()); if (!groupInfo.HasValue) // Failed to generate a group { BriefingRoom.PrintToLog($"Failed to find units for {coalition} air defense unit group.", LogMessageErrorLevel.Warning); } capAircraftGroupIDs.Add(groupInfo.Value.GroupID); } while (unitsLeftToSpawn > 0); }
internal MissionGeneratorFeaturesObjectives(UnitMaker unitMaker, MissionTemplateRecord template) : base(unitMaker, template) { }