protected override bool OnLoad(string iniFilePath) { //int i; var ini = new INIFile(iniFilePath); string[] badCountries = (from country in ini.GetValueArray <string>("Coalition", "Countries").Distinct() where !Enum.TryParse <Country>(country, true, out _) select country).ToArray(); if (badCountries.Length > 0) { BriefingRoom.PrintToLog($"Bad countr{(badCountries.Length == 1 ? "y" : "ies")} in coalition \"{ID}\": {string.Join(", ", badCountries)}", LogMessageErrorLevel.Warning); } Countries = ini.GetValueArray <Country>("Coalition", "Countries").Append(Country.ALL).Distinct().OrderBy(x => x).ToArray(); if (Countries.Length == 0) { BriefingRoom.PrintToLog($"No country in coalition \"{ID}\", coalition was ignored.", LogMessageErrorLevel.Warning); return(false); } DefaultUnitList = ini.GetValue <string>("Coalition", "DefaultUnitList"); if (!Database.EntryExists <DBEntryDefaultUnitList>(DefaultUnitList)) { BriefingRoom.PrintToLog($"Default unit list \"{DefaultUnitList}\" required by coalition \"{ID}\" doesn't exist. Coalition was ignored.", LogMessageErrorLevel.Warning); return(false); } NATOCallsigns = ini.GetValue("Coalition", "NATOCallsigns", false); return(true); }
private Dictionary <Country, List <string> > SelectValidUnits(List <UnitFamily> families, Decade decade, List <string> unitMods) { var validUnits = new Dictionary <Country, List <string> >(); foreach (Country country in Countries) { validUnits[country] = ( from DBEntryUnit unit in Database.GetAllEntries <DBEntryUnit>() where unit.Families.Intersect(families).ToList().Count > 0 && unit.Operators.ContainsKey(country) && (string.IsNullOrEmpty(unit.RequiredMod) || unitMods.Contains(unit.RequiredMod, StringComparer.InvariantCultureIgnoreCase)) && (unit.Operators[country][0] <= decade) && (unit.Operators[country][1] >= decade) select unit.ID).Distinct().ToList(); } validUnits = validUnits.Where(x => x.Value.Count > 0).ToDictionary(x => x.Key, x => x.Value); // At least one unit found, return it if (validUnits.Count > 0) { return(validUnits); } BriefingRoom.PrintToLog($"No Units of types {string.Join(", ", families)} found in coalition of {string.Join(", ", Countries.Where(x => x != Country.ALL))} forced to use defaults", LogMessageErrorLevel.Info); return(new Dictionary <Country, List <string> > { { Country.ALL, Database.GetEntry <DBEntryDefaultUnitList>(DefaultUnitList).DefaultUnits[(int)families.First(), (int)decade].ToList() } }); }
public DBCommonNames() { int i; BriefingRoom.PrintToLog("Loading common global settings..."); INIFile ini = new($"{BRPaths.DATABASE}Names.ini"); MissionNameTemplate = ini.GetValue <string>("Mission", "Template"); for (i = 0; i < MISSION_NAMES_PART_COUNT; i++) { MissionNameParts[i] = ini.GetValueArray <string>("Mission", $"Part{i + 1}"); } for (i = 0; i < Toolbox.EnumCount <UnitFamily>(); i++) { UnitFamilies[i] = ini.GetValueArray <string>("UnitFamilies", ((UnitFamily)i).ToString()); Array.Resize(ref UnitFamilies[i], 2); UnitGroups[i] = ini.GetValue <string>("UnitGroups", ((UnitFamily)i).ToString()); } WPEgressName = ini.GetValue <string>("Waypoints", "Egress").ToUpperInvariant(); WPFinalName = ini.GetValue <string>("Waypoints", "Final").ToUpperInvariant(); WPIngressName = ini.GetValue <string>("Waypoints", "Ingress").ToUpperInvariant(); WPInitialName = ini.GetValue <string>("Waypoints", "Initial").ToUpperInvariant(); WPObjectivesNames = (from string wpName in ini.GetValueArray <string>("Waypoints", "Objectives") select wpName.ToUpperInvariant()).ToArray(); }
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)); }
protected override bool OnLoad(string iniFilePath) { var ini = new INIFile(iniFilePath); BriefingName = new string[2] { ini.GetValue <string>("ObjectiveTarget", "Briefing.UnitName.Singular"), ini.GetValue <string>("ObjectiveTarget", "Briefing.UnitName.Plural") }; UnitFamilies = Toolbox.SetSingleCategoryFamilies(ini.GetValueArray <UnitFamily>("ObjectiveTarget", "Units.Families")); if (UnitFamilies.Length == 0) { BriefingRoom.PrintToLog($"No unit categories for objective target \"{ID}\"", LogMessageErrorLevel.Warning); return(false); } UnitCount = new MinMaxI[Toolbox.EnumCount <Amount>()]; foreach (Amount amount in Toolbox.GetEnumValues <Amount>()) { UnitCount[(int)amount] = ini.GetValue <MinMaxI>("ObjectiveTarget", $"Units.Count.{amount}"); } ValidSpawnPoints = DatabaseTools.CheckSpawnPoints(ini.GetValueArray <SpawnPointType>("ObjectiveTarget", "ValidSpawnPoints")); return(true); }
private void SetValue(string key, string value, bool append) { if (string.IsNullOrEmpty(key)) { return; } key = key.ToUpperInvariant(); value = value ?? ""; value = value.Replace("\r\n", "\n"); string displayedValue = value.Replace("\n", " "); if (displayedValue.Length > MAX_VALUE_LENGTH_DISPLAY) { displayedValue = displayedValue.Substring(0, MAX_VALUE_LENGTH_DISPLAY) + "..."; } BriefingRoom.PrintToLog($"Mission parameter \"{key.ToLowerInvariant()}\" {(append ? "appended with" : "set to")} \"{displayedValue}\"."); if (!Values.ContainsKey(key)) { Values.Add(key, value); } else { Values[key] = append ? Values[key] + value : 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 }
protected override bool OnLoad(string iniFilePath) { var ini = new INIFile(iniFilePath); // Unit info DCSIDs = (from string u in ini.GetValueArray <string>("Unit", "DCSID") select u.Trim()).ToArray(); if (DCSIDs.Length < 1) { BriefingRoom.PrintToLog($"Unit {ID} contains no DCS unit ID, unit was ignored.", LogMessageErrorLevel.Warning); return(false); } Families = ini.GetValueArray <UnitFamily>("Unit", "Families"); if (Families.Length == 0) { BriefingRoom.PrintToLog($"Unit {ID} has no family, unit was ignored.", LogMessageErrorLevel.Warning); return(false); } // Make sure all unit families belong to same category (unit cannot be a helicopter and a ground vehicle at the same time, for instance) Families = (from UnitFamily f in Families where f.GetUnitCategory() == Category select f).Distinct().ToArray(); ExtraLua = ini.GetValue <string>("Unit", "ExtraLua").Trim(); if (!string.IsNullOrEmpty(ExtraLua) && !ExtraLua.EndsWith(",")) { ExtraLua += ","; } Flags = ini.GetValueArrayAsEnumFlags <DBEntryUnitFlags>("Unit", "Flags"); OffsetCoordinates = (from string s in ini.GetValueArray <string>("Unit", "Offset.Coordinates", ';') select new Coordinates(s)).ToArray(); OffsetHeading = ini.GetValueArray <double>("Unit", "Offset.Heading"); Shape = ini.GetValueArray <string>("Unit", "Shape"); RequiredMod = ini.GetValue <string>("Unit", "RequiredMod"); AircraftData = new DBEntryUnitAircraftData(); // Load the list of operators Operators = new Dictionary <Country, Decade[]>(); foreach (string k in ini.GetKeysInSection("Operators")) { if (!Enum.TryParse(k, true, out Country country)) { BriefingRoom.PrintToLog($"Country {k} in unit {ID} doesn't exist.", LogMessageErrorLevel.Warning); continue; } if (Operators.ContainsKey(country)) { continue; } Operators.Add(country, ini.GetValueArrayAsMinMaxEnum <Decade>("Operators", k)); } if (IsAircraft) // Load aircraft-specific data, if required { DCSIDs = new string[] { DCSIDs[0] }; // Aircraft can not have multiple unit types in their group AircraftData = new DBEntryUnitAircraftData(ini, iniFilePath.Contains(BRPaths.CUSTOMDATABASE)); } return(true); }
internal void GenerateMissionFeature(DCSMission mission, string featureID, string objectiveName, int objectiveIndex, int objectiveGroupID, Coordinates objectiveCoordinates, Side objectiveTargetSide, bool hideEnemy = false) { DBEntryFeatureObjective featureDB = Database.Instance.GetEntry <DBEntryFeatureObjective>(featureID); if (featureDB == null) // Feature doesn't exist { BriefingRoom.PrintToLog($"Objective feature {featureID} not found.", LogMessageErrorLevel.Warning); return; } double spawnDistance = Math.Max(1.0, featureDB.UnitGroupSpawnDistance) * Toolbox.NM_TO_METERS; Coordinates coordinates; if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.SpawnOnObjective)) { coordinates = objectiveCoordinates + Coordinates.CreateRandom(10, 50); } else { Coordinates?spawnPoint = _unitMaker.SpawnPointSelector.GetRandomSpawnPoint( featureDB.UnitGroupValidSpawnPoints, objectiveCoordinates, new MinMaxD(spawnDistance * .75, spawnDistance * 1.5)); if (!spawnPoint.HasValue) // No spawn point found { BriefingRoom.PrintToLog($"No spawn point found for objective feature {featureID}.", LogMessageErrorLevel.Warning); return; } coordinates = spawnPoint.Value; } Coordinates coordinates2 = coordinates + Coordinates.CreateRandom(10, 20) * Toolbox.NM_TO_METERS; Dictionary <string, object> extraSettings = new Dictionary <string, object>(StringComparer.InvariantCultureIgnoreCase); extraSettings.AddIfKeyUnused("ObjectiveName", objectiveName); extraSettings.AddIfKeyUnused("ObjectiveIndex", objectiveIndex + 1); extraSettings.AddIfKeyUnused("ObjectiveGroupID", objectiveGroupID); if (featureID == "TargetDesignationLaser") { var laserCode = _template.OptionsMission.Contains("SingleLaserCode") ? 1688 : getNextLaserCode(); extraSettings.AddIfKeyUnused("LASERCODE", laserCode); mission.Briefing.AddItem(DCSMissionBriefingItemType.JTAC, $"{objectiveName}\t{laserCode}"); } UnitMakerGroupInfo?groupInfo = AddMissionFeature( featureDB, mission, coordinates, coordinates2, ref extraSettings, objectiveTargetSide, hideEnemy); AddBriefingRemarkFromFeature(featureDB, mission, false, groupInfo, extraSettings); }
private void LoadEntries <T>(string subDirectory) where T : DBEntry, new() { BriefingRoom.PrintToLog($"Loading {subDirectory.ToLowerInvariant()}..."); string directory = $"{BRPaths.DATABASE}{subDirectory}"; if (!Directory.Exists(directory)) { throw new Exception($"Directory {directory} not found."); } Type dbType = typeof(T); string shortTypeName = dbType.Name.Substring(7).ToLowerInvariant(); if (!DBEntries.ContainsKey(dbType)) { DBEntries.Add(dbType, new Dictionary <string, DBEntry>(StringComparer.InvariantCultureIgnoreCase)); } DBEntries[dbType].Clear(); foreach (string filePath in Directory.EnumerateFiles(directory, "*.ini", SearchOption.AllDirectories)) { string id = Path.GetFileNameWithoutExtension(filePath).Replace(",", "").Trim(); // No commas in file names, so we don't break comma-separated arrays if (DBEntries[dbType].ContainsKey(id)) { continue; } T entry = new T(); if (!entry.Load(this, id, filePath)) { continue; } DBEntries[dbType].Add(id, entry); BriefingRoom.PrintToLog($"Loaded {shortTypeName} \"{id}\""); } BriefingRoom.PrintToLog($"Found {DBEntries[dbType].Count} database entries of type \"{typeof(T).Name}\""); bool mustHaveAtLeastOneEntry = true; if ((dbType == typeof(DBEntryDefaultUnitList)) || (dbType == typeof(DBEntryFeatureMission)) || (dbType == typeof(DBEntryFeatureObjective))) { mustHaveAtLeastOneEntry = false; } // If a required database type has no entries, raise an error. if ((DBEntries[dbType].Count == 0) && mustHaveAtLeastOneEntry) { throw new BriefingRoomException($"No valid database entries found in the \"{subDirectory}\" directory"); } }
protected override bool OnLoad(string iniFilePath) { int i, j; DefaultUnits = new string[Toolbox.EnumCount <UnitFamily>(), Toolbox.EnumCount <Decade>()][]; for (i = 0; i < Toolbox.EnumCount <UnitFamily>(); i++) { for (j = 0; j < Toolbox.EnumCount <Decade>(); j++) { DefaultUnits[i, j] = new string[0]; } } var ini = new INIFile(iniFilePath); foreach (UnitFamily family in Toolbox.GetEnumValues <UnitFamily>()) { foreach (Decade decade in Toolbox.GetEnumValues <Decade>()) { string[] units = GetValidDBEntryIDs <DBEntryUnit>(ini.GetValueArray <string>($"{decade}", $"{family}"), out string[] invalidUnits); foreach (string u in invalidUnits) { BriefingRoom.PrintToLog($"Unit \"{u}\" not found in default unit list \"{ID}\".", LogMessageErrorLevel.Warning); } if (units.Length == 0) { continue; } for (i = (int)decade; i <= (int)Decade.Decade2020; i++) { DefaultUnits[(int)family, i] = units.ToArray(); } } } for (i = 0; i < Toolbox.EnumCount <UnitFamily>(); i++) { for (j = 0; j < Toolbox.EnumCount <Decade>(); j++) { if (DefaultUnits[i, j].Length == 0) { BriefingRoom.PrintToLog($"Default unit list \"{ID}\" has no unit of family \"{(UnitFamily)i}\" during {(Decade)j}, unit list was ignored.", LogMessageErrorLevel.Warning); return(false); } } } return(true); }
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 (string unitsLua, List <int> unitsIDList) AddUnits( string[] unitSets, string groupName, UnitCallsign?callsign, string unitTypeLua, Coordinates coordinates, UnitMakerGroupFlags unitMakerGroupFlags, params KeyValuePair <string, object>[] extraSettings ) { string unitsLuaTable = ""; int unitLuaIndex = 1; List <int> unitsIDList = new List <int>(); foreach (var unitSet in unitSets) { DBEntryUnit unitDB = Database.Instance.GetEntry <DBEntryUnit>(unitSet); if (unitDB == null) { BriefingRoom.PrintToLog($"Unit \"{unitSet}\" not found.", LogMessageErrorLevel.Warning); continue; } int unitSetIndex = 0; foreach (string DCSID in unitDB.DCSIDs) { unitsLuaTable += AddUnit( DCSID, groupName, callsign, unitLuaIndex, unitSetIndex, unitDB, unitTypeLua, coordinates, unitMakerGroupFlags, extraSettings ); unitsIDList.Add(UnitID); unitSetIndex++; unitLuaIndex++; UnitID++; } } return(unitsLuaTable, unitsIDList); }
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 void GenerateMissionFeature(DCSMission mission, string featureID, Coordinates initialCoordinates, Coordinates objectivesCenter) { DBEntryFeatureMission featureDB = Database.Instance.GetEntry <DBEntryFeatureMission>(featureID); if (featureDB == null) // Feature doesn't exist { BriefingRoom.PrintToLog($"Mission feature {featureID} not found.", LogMessageErrorLevel.Warning); return; } Coalition coalition = featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.Friendly) ? _template.ContextPlayerCoalition : _template.ContextPlayerCoalition.GetEnemy(); Coordinates pointSearchCenter = Coordinates.Lerp(initialCoordinates, objectivesCenter, featureDB.UnitGroupSpawnDistance); Coordinates?spawnPoint = _unitMaker.SpawnPointSelector.GetRandomSpawnPoint( featureDB.UnitGroupValidSpawnPoints, pointSearchCenter, featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.AwayFromMissionArea) ? new MinMaxD(50, 100) : new MinMaxD(0, 5), coalition: featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.IgnoreBorders) ? null : coalition ); if (!spawnPoint.HasValue) // No spawn point found { BriefingRoom.PrintToLog($"No spawn point found for mission feature {featureID}.", LogMessageErrorLevel.Warning); return; } var goPoint = spawnPoint.Value; if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.MoveTowardObjectives)) { goPoint = objectivesCenter; } else if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.MoveTowardPlayerBase)) { goPoint = initialCoordinates; } Coordinates coordinates2 = goPoint + Coordinates.CreateRandom(5, 20) * Toolbox.NM_TO_METERS; Dictionary <string, object> extraSettings = new Dictionary <string, object>(); UnitMakerGroupInfo? groupInfo = AddMissionFeature(featureDB, mission, spawnPoint.Value, coordinates2, ref extraSettings); AddBriefingRemarkFromFeature(featureDB, mission, false, groupInfo, extraSettings); }
protected override bool OnLoad(string iniFilePath) { var ini = new INIFile(iniFilePath); BriefingRemarks = new string[2][]; BriefingRemarks[(int)Side.Ally] = ini.GetValueArray <string>("Briefing", "Remarks", ';'); BriefingRemarks[(int)Side.Enemy] = ini.GetValueArray <string>("Briefing", "Remarks.Enemy", ';'); // Included files IncludeLua = Toolbox.AddMissingFileExtensions(ini.GetValueArray <string>("Include", "Lua"), ".lua"); IncludeLuaSettings = ini.GetValue <string>("Lua", "LuaSettings"); IncludeOgg = Toolbox.AddMissingFileExtensions(ini.GetValueArray <string>("Include", "Ogg"), ".ogg"); foreach (string f in IncludeLua) { if (!File.Exists($"{SourceLuaDirectory}{f}")) { BriefingRoom.PrintToLog($"File \"{SourceLuaDirectory}{f}\", required by feature \"{ID}\", doesn't exist.", LogMessageErrorLevel.Warning); } } foreach (string f in IncludeOgg) { if (!File.Exists($"{BRPaths.INCLUDE_OGG}{f}")) { BriefingRoom.PrintToLog($"File \"{BRPaths.INCLUDE_OGG}{f}\", required by feature \"{ID}\", doesn't exist.", LogMessageErrorLevel.Warning); } } // Unit group UnitGroupFamilies = ini.GetValueArray <UnitFamily>("UnitGroup", "Families"); UnitGroupFlags = ini.GetValueArrayAsEnumFlags <FeatureUnitGroupFlags>("UnitGroup", "Flags"); UnitGroupLuaGroup = ini.GetValue <string>("UnitGroup", "Lua.Group"); UnitGroupLuaUnit = ini.GetValue <string>("UnitGroup", "Lua.Unit"); UnitGroupSize = ini.GetValue <MinMaxI>("UnitGroup", "Size"); ExtraGroups = ini.GetValue <MinMaxI>("UnitGroup", "ExtraGroups"); UnitGroupSpawnDistance = ini.GetValue <double>("UnitGroup", "SpawnDistance"); UnitGroupPayload = ini.GetValue <string>("UnitGroup", "Payload", "default"); UnitGroupValidSpawnPoints = DatabaseTools.CheckSpawnPoints(ini.GetValueArray <SpawnPointType>("UnitGroup", "ValidSpawnPoints")); return(true); }
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 void Load() { int i; BriefingRoom.PrintToLog("Loading common global settings..."); INIFile commonIni = new($"{BRPaths.DATABASE}Common.ini"); CommonOGG = commonIni.GetValueArray <string>("Include", "CommonOgg"); foreach (string f in CommonOGG) { if (!File.Exists($"{BRPaths.INCLUDE_OGG}{f}.ogg")) { BriefingRoom.PrintToLog($"File \"Include\\Ogg\\{f}.ogg\" doesn't exist.", LogMessageErrorLevel.Warning); } } BriefingRoom.PrintToLog("Loading common air defense settings..."); AirDefense = new DBCommonAirDefense(); BriefingRoom.PrintToLog("Loading common CAP settings..."); CAP = new DBCommonCAP(); BriefingRoom.PrintToLog("Loading common carrier group settings..."); CarrierGroup = new DBCommonCarrierGroup(); BriefingRoom.PrintToLog("Loading common names settings..."); Names = new DBCommonNames(); BriefingRoom.PrintToLog("Loading common briefing settings..."); Briefing = new DBCommonBriefing(); BriefingRoom.PrintToLog("Loading common wind settings..."); INIFile windIni = new($"{BRPaths.DATABASE}Wind.ini"); Wind = new DBCommonWind[Toolbox.EnumCount <Wind>() - 1]; // -1 because we don't want "Random" for (i = 0; i < Wind.Length; i++) { Wind[i] = new DBCommonWind(windIni, ((Wind)i).ToString()); } }
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))); }
protected override bool OnLoad(string iniFilePath) { var ini = new INIFile(iniFilePath); Features = Database.CheckIDs <DBEntryFeatureObjective>(ini.GetValueArray <string>("ObjectivePreset", "Features")); Options = ini.GetValueArray <ObjectiveOption>("ObjectivePreset", "Options"); Targets = Database.CheckIDs <DBEntryObjectiveTarget>(ini.GetValueArray <string>("ObjectivePreset", "Targets")); if (Targets.Length == 0) { BriefingRoom.PrintToLog($"No valid targets for objective preset \"{ID}\"", LogMessageErrorLevel.Warning); return(false); } TargetsBehaviors = Database.CheckIDs <DBEntryObjectiveTargetBehavior>(ini.GetValueArray <string>("ObjectivePreset", "TargetsBehaviors")); if (TargetsBehaviors.Length == 0) { BriefingRoom.PrintToLog($"No valid target behaviors for objective preset \"{ID}\"", LogMessageErrorLevel.Warning); return(false); } Tasks = Database.CheckIDs <DBEntryObjectiveTask>(ini.GetValueArray <string>("ObjectivePreset", "Tasks")); if (Tasks.Length == 0) { BriefingRoom.PrintToLog($"No valid tasks for objective preset \"{ID}\"", LogMessageErrorLevel.Warning); return(false); } return(true); }
protected override bool OnLoad(string iniFilePath) { var ini = new INIFile(iniFilePath); BriefingDescription = ini.GetValue <string>("Briefing", "Description"); if (!Database.Instance.EntryExists <DBEntryBriefingDescription>(BriefingDescription)) { BriefingRoom.PrintToLog($"Objective task \"{ID}\" references non-existing briefing description \"{BriefingDescription}\".", LogMessageErrorLevel.Warning); return(false); } BriefingTask = new string[2]; BriefingTask[0] = ini.GetValue <string>("Briefing", "Task.Singular"); BriefingTask[1] = ini.GetValue <string>("Briefing", "Task.Plural"); BriefingRemarks = ini.GetValueArray <string>("Briefing", "Remarks", ';'); CompletionTriggerLua = Toolbox.AddMissingFileExtension(ini.GetValue <string>("ObjectiveTask", "CompletionTriggerLua"), ".lua"); if (!File.Exists($"{BRPaths.INCLUDE_LUA_OBJECTIVETRIGGERS}{CompletionTriggerLua}")) { BriefingRoom.PrintToLog($"Completion trigger Lua file {CompletionTriggerLua} for objective task \"{ID}\" not found.", LogMessageErrorLevel.Warning); return(false); } TargetSide = ini.GetValue <Side>("ObjectiveTask", "TargetSide"); ValidUnitCategories = ini.GetValueArray <UnitCategory>("ObjectiveTask", "ValidUnitCategories").Distinct().ToArray(); if (ValidUnitCategories.Length == 0) { ValidUnitCategories = Toolbox.GetEnumValues <UnitCategory>(); // No category means all categories } // Included files IncludeOgg = Toolbox.AddMissingFileExtensions(ini.GetValueArray <string>("Include", "Ogg"), ".ogg"); return(true); }
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); }
protected override bool OnLoad(string iniFilePath) { int i; var ini = new INIFile(iniFilePath); // [Briefing] section BriefingNames = ini.GetValueArray <string>("Briefing", "Names"); // [Theater] section DCSID = ini.GetValue <string>("Theater", "DCSID"); DefaultMapCenter = ini.GetValue <Coordinates>("Theater", "DefaultMapCenter"); MagneticDeclination = ini.GetValue <double>("Theater", "MagneticDeclination"); // [Daytime] section DayTime = new MinMaxI[12]; for (i = 0; i < 12; i++) { MinMaxI?dayTimeValue = ParseMinMaxTime(ini.GetValueArray <string>("Daytime", ((Month)i).ToString())); if (!dayTimeValue.HasValue) // Cast failed { BriefingRoom.PrintToLog( $"Wrong format for daytime value for month {(Month)i} in theater {ID}, using default value", LogMessageErrorLevel.Warning); } DayTime[i] = dayTimeValue ?? DEFAULT_DAYTIME; } // Water Coordinates WaterCoordinates = new List <Coordinates>(); foreach (string key in ini.GetKeysInSection("WaterCoordinates")) { WaterCoordinates.Add(ini.GetValue <Coordinates>("WaterCoordinates", key)); } List <DBEntryTheaterSpawnPoint> spawnPointsList = new List <DBEntryTheaterSpawnPoint>(); foreach (string key in ini.GetKeysInSection("SpawnPoints")) { DBEntryTheaterSpawnPoint sp = new DBEntryTheaterSpawnPoint(); if (sp.Load(ini, key)) { spawnPointsList.Add(sp); } } SpawnPoints = spawnPointsList.ToArray(); WaterExclusionCoordinates = new List <List <Coordinates> >(); if (ini.GetSections().Contains("waterexclusioncoordinates")) { // Water Exclusion Coordinates var tempList = new List <Coordinates>(); var groupID = ini.GetKeysInSection("WaterExclusionCoordinates").First().Split(".")[0]; foreach (string key in ini.GetKeysInSection("WaterExclusionCoordinates")) { var newGroupId = key.Split(".")[0]; if (groupID != newGroupId) { groupID = newGroupId; WaterExclusionCoordinates.Add(tempList); tempList = new List <Coordinates>(); } tempList.Add(ini.GetValue <Coordinates>("WaterExclusionCoordinates", key)); } WaterExclusionCoordinates.Add(tempList); } // [Temperature] section Temperature = new MinMaxI[12]; for (i = 0; i < 12; i++) { Temperature[i] = ini.GetValue <MinMaxI>("Temperature", ((Month)i).ToString()); } return(true); }
internal static void GeneratePlayerFlightGroup( UnitMaker unitMaker, DCSMission mission, MissionTemplateRecord template, MissionTemplateFlightGroupRecord flightGroup, DBEntryAirbase playerAirbase, List <Waypoint> waypoints, Dictionary <string, UnitMakerGroupInfo> carrierDictionary, Coordinates averageInitialLocation, Coordinates objectivesCenter) { DBEntryAirbase airbase = playerAirbase; List <Waypoint> flightWaypoints = new List <Waypoint>(waypoints); Coordinates groupStartingCoords = playerAirbase.Coordinates; var package = template.AircraftPackages.FirstOrDefault(x => x.FlightGroupIndexes.Contains(template.PlayerFlightGroups.IndexOf(flightGroup))); if (package is not null) { var missionPackage = mission.MissionPackages.First(x => x.RecordIndex == template.AircraftPackages.IndexOf(package)); flightWaypoints = missionPackage.Waypoints; airbase = missionPackage.Airbase; groupStartingCoords = missionPackage.Airbase.Coordinates; } DBEntryUnit unitDB = Database.Instance.GetEntry <DBEntryUnit>(flightGroup.Aircraft); // Not an unit, or not a player-controllable unit, abort. if ((unitDB == null) || !unitDB.AircraftData.PlayerControllable) { throw new BriefingRoomException($"Player flight group unit {flightGroup.Aircraft} does not exist or is not player-controllable."); } if (unitDB.AircraftData.MinimumRunwayLengthFt > 0 && airbase.RunwayLengthFt < unitDB.AircraftData.MinimumRunwayLengthFt) { BriefingRoom.PrintToLog($"Runway at {airbase.Name}({airbase.RunwayLengthFt}ft) is shorter than {unitDB.UIDisplayName}({unitDB.AircraftData.MinimumRunwayLengthFt}ft) required runway length.", LogMessageErrorLevel.Warning); } List <int> parkingSpotIDsList = new List <int>(); List <Coordinates> parkingSpotCoordinatesList = new List <Coordinates>(); var groupLuaFile = "GroupAircraftPlayer"; var carrierUnitID = 0; string carrierName = null; var side = flightGroup.Hostile ? Side.Enemy : Side.Ally; var country = flightGroup.Country; var payload = flightGroup.Payload; var extraSettings = new Dictionary <string, object>(); UnitMakerGroupFlags unitMakerGroupFlags = flightGroup.AIWingmen ? UnitMakerGroupFlags.FirstUnitIsClient : 0; DCSSkillLevel skillLevel = flightGroup.AIWingmen ? Toolbox.RandomFrom(DCSSkillLevel.High, DCSSkillLevel.Excellent) : DCSSkillLevel.Client; if (!string.IsNullOrEmpty(flightGroup.Carrier) && carrierDictionary.ContainsKey(flightGroup.Carrier) && !flightGroup.Hostile) // Carrier take off { var carrier = carrierDictionary[flightGroup.Carrier]; if (carrier.UnitDB.Families.Contains(UnitFamily.ShipCarrierSTOVL) && flightGroup.Carrier != "LHA_Tarawa") { extraSettings.AddIfKeyUnused("Speed", 0); unitMakerGroupFlags = 0; skillLevel = DCSSkillLevel.Client; if (flightGroup.Aircraft == "AV8BNA") { payload = "EMPTY"; } } groupLuaFile = "GroupAircraftPlayerCarrier"; carrierUnitID = carrier.UnitsID[0]; carrierName = carrier.UnitDB.UIDisplayName; for (int i = 0; i < flightGroup.Count; i++) { parkingSpotIDsList.Add(i + 1); parkingSpotCoordinatesList.Add(carrier.Coordinates); } groupStartingCoords = carrier.Coordinates; } else if (flightGroup.Hostile) { var coalition = GeneratorTools.GetSpawnPointCoalition(template, side, true); var(hostileAirbase, hostileParkingSpotIDsList, hostileParkingSpotCoordinatesList) = unitMaker.SpawnPointSelector.GetAirbaseAndParking(template, objectivesCenter, flightGroup.Count, coalition.Value, unitDB.Families.First()); parkingSpotIDsList = hostileParkingSpotIDsList; parkingSpotCoordinatesList = hostileParkingSpotCoordinatesList; groupStartingCoords = hostileParkingSpotCoordinatesList.First(); airbase = hostileAirbase; if (country == Country.CJTFBlue || country == Country.CJTFRed) { country = coalition == Coalition.Blue ? Country.CJTFBlue : Country.CJTFRed; } } else // Land airbase take off { var parkingSpots = unitMaker.SpawnPointSelector.GetFreeParkingSpots(airbase.DCSID, flightGroup.Count, unitDB.Families[0]); parkingSpotIDsList = parkingSpots.Select(x => x.DCSID).ToList(); parkingSpotCoordinatesList = parkingSpots.Select(x => x.Coordinates).ToList(); groupStartingCoords = parkingSpotCoordinatesList.First(); } extraSettings.AddIfKeyUnused("Payload", payload); extraSettings.AddIfKeyUnused("Skill", skillLevel); extraSettings.AddIfKeyUnused("PlayerStartingAction", GeneratorTools.GetPlayerStartingAction(flightGroup.StartLocation)); extraSettings.AddIfKeyUnused("PlayerStartingType", GeneratorTools.GetPlayerStartingType(flightGroup.StartLocation)); extraSettings.AddIfKeyUnused("Country", country); extraSettings.AddIfKeyUnused("InitialWPName", Database.Instance.Common.Names.WPInitialName); extraSettings.AddIfKeyUnused("FinalWPName", Database.Instance.Common.Names.WPFinalName); extraSettings.AddIfKeyUnused("ParkingID", parkingSpotIDsList.ToArray()); extraSettings.AddIfKeyUnused("PlayerWaypoints", GenerateFlightPlanLua(flightWaypoints)); extraSettings.AddIfKeyUnused("LastPlayerWaypointIndex", flightWaypoints.Count + 2); extraSettings.AddIfKeyUnused("LinkUnit", carrierUnitID); extraSettings.AddIfKeyUnused("UnitX", (from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.X).ToArray()); extraSettings.AddIfKeyUnused("UnitY", (from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.Y).ToArray()); extraSettings.AddIfKeyUnused("MissionAirbaseX", groupStartingCoords.X); extraSettings.AddIfKeyUnused("MissionAirbaseY", groupStartingCoords.Y); extraSettings.AddIfKeyUnused("MissionAirbaseID", airbase.DCSID); extraSettings.AddIfKeyUnused("Livery", flightGroup.Livery); UnitMakerGroupInfo?groupInfo = unitMaker.AddUnitGroup( Enumerable.Repeat(flightGroup.Aircraft, flightGroup.Count).ToArray(), side, unitDB.Families[0], groupLuaFile, "UnitAircraftParked", groupStartingCoords, unitMakerGroupFlags, extraSettings.ToArray() ); if (!groupInfo.HasValue) { BriefingRoom.PrintToLog("Failed to generate player flight group.", LogMessageErrorLevel.Warning); return; } SaveFlightGroup(mission, groupInfo, flightGroup, unitDB, carrierName ?? airbase.Name); SaveWaypointsToBriefing( mission, groupStartingCoords, flightWaypoints, template.OptionsMission.Contains("ImperialUnitsForBriefing"), groupInfo); }
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); }
internal Tuple <Country, List <string> > GetRandomUnits(List <UnitFamily> families, Decade decade, int count, List <string> unitMods, Country?requiredCountry = null) { // Count is zero, return an empty array. if (count < 1) { throw new BriefingRoomException("Asking for a zero unit list"); } if (families.Select(x => x.GetUnitCategory()).Any(x => x != families.First().GetUnitCategory())) { throw new BriefingRoomException($"Cannot mix Categories in types {string.Join(", ", families)}"); } UnitCategory category = families.First().GetUnitCategory(); bool allowDifferentUnitTypes = false; switch (category) { // Units are planes or helicopters, make sure unit count does not exceed the maximum flight group size case UnitCategory.Helicopter: case UnitCategory.Plane: count = Toolbox.Clamp(count, 1, Toolbox.MAXIMUM_FLIGHT_GROUP_SIZE); break; // Units are ships or static buildings, only one unit per group (that's the law in DCS World, buddy) case UnitCategory.Ship: case UnitCategory.Static: count = 1; break; // Units are ground vehicles, allow multiple unit types in the group case UnitCategory.Vehicle: allowDifferentUnitTypes = true; break; } var validUnits = SelectValidUnits(families, decade, unitMods); var selectableUnits = new List <string>(); var country = Toolbox.RandomFrom(validUnits.Keys.ToList()); if (requiredCountry.HasValue) { if (validUnits.ContainsKey(requiredCountry.Value)) { country = requiredCountry.Value; } else { BriefingRoom.PrintToLog($"Could not find suitable units for {requiredCountry.Value} using units from other coalition members.", LogMessageErrorLevel.Info); } } selectableUnits = validUnits[country]; // Different unit types allowed in the group, pick a random type for each unit. if (allowDifferentUnitTypes) { List <string> selectedUnits = new List <string>(); for (int i = 0; i < count; i++) { selectedUnits.Add(Toolbox.RandomFrom(selectableUnits)); } return(new (country, selectedUnits.ToList())); } // Different unit types NOT allowed in the group, pick a random type and fill the whole array with it. string unit = Toolbox.RandomFrom(selectableUnits); return(new (country, Enumerable.Repeat(unit, count).ToList())); }
private static void CreateAirDefenseGroups( MissionTemplateRecord template, UnitMaker unitMaker, Side side, Coalition coalition, AmountNR airDefenseAmount, AirDefenseRange airDefenseRange, Coordinates centerPoint, Coordinates opposingPoint) { var commonAirDefenseDB = Database.Instance.Common.AirDefense; DBCommonAirDefenseLevel airDefenseLevelDB = commonAirDefenseDB.AirDefenseLevels[(int)airDefenseAmount]; int groupCount = airDefenseLevelDB.GroupsInArea[(int)airDefenseRange].GetValue(); if (groupCount < 1) { return; // No groups to add, no need to go any further } List <UnitFamily> unitFamilies; SpawnPointType[] validSpawnPoints; switch (airDefenseRange) { case AirDefenseRange.MediumRange: unitFamilies = new List <UnitFamily> { UnitFamily.VehicleSAMMedium }; validSpawnPoints = new SpawnPointType[] { SpawnPointType.LandLarge }; break; case AirDefenseRange.LongRange: unitFamilies = new List <UnitFamily> { UnitFamily.VehicleSAMLong }; validSpawnPoints = new SpawnPointType[] { SpawnPointType.LandLarge }; break; default: // case AirDefenseRange.ShortRange: unitFamilies = new List <UnitFamily> { UnitFamily.VehicleAAA, UnitFamily.VehicleAAAStatic, UnitFamily.VehicleInfantryMANPADS, UnitFamily.VehicleSAMShort, UnitFamily.VehicleSAMShort, UnitFamily.VehicleSAMShortIR, UnitFamily.VehicleSAMShortIR }; validSpawnPoints = new SpawnPointType[] { SpawnPointType.LandSmall, SpawnPointType.LandMedium, SpawnPointType.LandLarge }; break; } for (int i = 0; i < groupCount; i++) { // Find spawn point at the proper distance Coordinates?spawnPoint = unitMaker.SpawnPointSelector.GetRandomSpawnPoint( validSpawnPoints, centerPoint, commonAirDefenseDB.DistanceFromCenter[(int)side, (int)airDefenseRange], opposingPoint, new MinMaxD(commonAirDefenseDB.MinDistanceFromOpposingPoint[(int)side, (int)airDefenseRange], 99999), GeneratorTools.GetSpawnPointCoalition(template, side)); // No spawn point found, stop here. if (!spawnPoint.HasValue) { BriefingRoom.PrintToLog($"No spawn point found for {airDefenseRange} air defense unit groups", LogMessageErrorLevel.Warning); return; } var groupInfo = unitMaker.AddUnitGroup( unitFamilies, 1, side, "GroupVehicle", "UnitVehicle", spawnPoint.Value); if (!groupInfo.HasValue) // Failed to generate a group { BriefingRoom.PrintToLog( $"Failed to add {airDefenseRange} air defense unit group for {coalition} coalition.", LogMessageErrorLevel.Warning); } } }
private UnitMakerGroupInfo?AddStaticGroup( Country country, Coalition coalition, DCSSkillLevel?skill, UnitFamily unitFamily, Side side, string[] unitSets, string groupName, UnitCallsign?callsign, string groupTypeLua, Coordinates coordinates, UnitMakerGroupFlags unitMakerGroupFlags, params KeyValuePair <string, object>[] extraSettings ) { List <int> unitsIDList = new List <int>(); var initalGroupId = GroupID; foreach (var unitSet in unitSets) { DBEntryUnit unitDB = Database.Instance.GetEntry <DBEntryUnit>(unitSet); if (unitDB == null) { BriefingRoom.PrintToLog($"Unit \"{unitSet}\" not found.", LogMessageErrorLevel.Warning); continue; } int unitSetIndex = 0; foreach (var DCSID in unitDB.DCSIDs) { var groupHeading = GetGroupHeading(coordinates, extraSettings); SetUnitCoordinatesAndHeading(unitDB, unitSetIndex, coordinates, groupHeading, out Coordinates unitCoordinates, out double unitHeading); var firstUnitID = UnitID; var groupLua = CreateGroup( groupTypeLua, unitCoordinates, groupName, extraSettings ); var unitLua = DCSID == "FARP" ? "UnitStaticFOB" : (unitDB.Category == UnitCategory.Cargo ? "UnitCargo" : "UnitStatic"); var unitsLuaTable = AddUnit( DCSID, groupName, callsign, 1, unitSetIndex, unitDB, unitLua, coordinates, unitMakerGroupFlags, extraSettings ); unitsIDList.Add(UnitID); unitSetIndex++; UnitID++; GeneratorTools.ReplaceKey(ref groupLua, "Units", unitsLuaTable); GeneratorTools.ReplaceKey(ref groupLua, "UnitID", firstUnitID); // Must be after units are added GeneratorTools.ReplaceKey(ref groupLua, "Skill", skill); // Must be after units are added, because skill is set as a unit level GeneratorTools.ReplaceKey(ref groupLua, "Hidden", GeneratorTools.GetHiddenStatus(Template.OptionsFogOfWar, side, unitMakerGroupFlags)); // If "hidden" was not set through custom values AddUnitGroupToTable(country, UnitCategory.Static, groupLua); BriefingRoom.PrintToLog($"Added group of {DCSID} {coalition} {unitFamily} at {coordinates}"); GroupID++; } } if (unitMakerGroupFlags.HasFlag(UnitMakerGroupFlags.EmbeddedAirDefense) && unitFamily != UnitFamily.StaticStructureOffshore) { var firstUnitID = UnitID; string[] airDefenseUnits = GeneratorTools.GetEmbeddedAirDefenseUnits(Template, side); var groupLua = CreateGroup( "GroupVehicle", coordinates, groupName, extraSettings ); var(unitsLuaTable, embeddedunitsIDList) = AddUnits( airDefenseUnits, groupName, callsign, "UnitVehicle", coordinates, unitMakerGroupFlags, extraSettings ); GeneratorTools.ReplaceKey(ref groupLua, "Units", unitsLuaTable); GeneratorTools.ReplaceKey(ref groupLua, "UnitID", firstUnitID); // Must be after units are added GeneratorTools.ReplaceKey(ref groupLua, "Skill", skill); // Must be after units are added, because skill is set as a unit level GeneratorTools.ReplaceKey(ref groupLua, "Hidden", GeneratorTools.GetHiddenStatus(Template.OptionsFogOfWar, side, unitMakerGroupFlags)); // If "hidden" was not set through custom values GroupID++; unitsIDList.AddRange(embeddedunitsIDList); AddUnitGroupToTable(country, UnitCategory.Vehicle, groupLua); BriefingRoom.PrintToLog($"Added group of Embedded Air Defense for Static {coalition} {unitFamily} at {coordinates}"); } DBEntryUnit firstUnitDB = Database.Instance.GetEntry <DBEntryUnit>(unitSets.First()); if (firstUnitDB == null) { return(new UnitMakerGroupInfo(initalGroupId, coordinates, unitsIDList, groupName)); } return(new UnitMakerGroupInfo(initalGroupId, coordinates, unitsIDList, groupName, firstUnitDB.AircraftData.RadioFrequency, firstUnitDB)); }
internal UnitMakerGroupInfo?AddUnitGroup( string[] units, Side side, UnitFamily unitFamily, string groupTypeLua, string unitTypeLua, Coordinates coordinates, UnitMakerGroupFlags unitMakerGroupFlags = 0, params KeyValuePair <string, object>[] extraSettings) { if (units.Length == 0) { return(null); } Coalition coalition = (side == Side.Ally) ? PlayerCoalition : PlayerCoalition.GetEnemy(); Country country = (coalition == Coalition.Blue) ? Country.CJTFBlue : Country.CJTFRed; if (extraSettings.Any(x => x.Key == "Country")) { country = (Country)extraSettings.First(x => x.Key == "Country").Value; } var skill = GeneratorTools.GetDefaultSkillLevel(Template, side); if (extraSettings.Any(x => x.Key == "Skill")) { skill = (DCSSkillLevel)extraSettings.First(x => x.Key == "Skill").Value; } var isUsingSkynet = Template.MissionFeatures.Contains("SkynetIADS"); string groupName; UnitCallsign?callsign = null; if (unitFamily.GetUnitCategory().IsAircraft()) { callsign = CallsignGenerator.GetCallsign(unitFamily, coalition, side, isUsingSkynet); groupName = callsign.Value.GroupName; if (extraSettings.Any(x => x.Key == "PlayerStartingType") && extraSettings.First(x => x.Key == "PlayerStartingType").Value.ToString() == "TakeOffParking") { groupName += "(C)"; } } else { groupName = GeneratorTools.GetGroupName(GroupID, unitFamily, side, isUsingSkynet); } if (unitFamily.GetUnitCategory() == UnitCategory.Static || unitFamily.GetUnitCategory() == UnitCategory.Cargo && unitFamily != UnitFamily.FOB) { return(AddStaticGroup( country, coalition, skill, unitFamily, side, units, groupName, callsign, groupTypeLua, coordinates, unitMakerGroupFlags, extraSettings )); } var groupLua = CreateGroup( groupTypeLua, coordinates, groupName, extraSettings ); int firstUnitID = UnitID; var(unitsLuaTable, unitsIDList) = AddUnits( units, groupName, callsign, unitTypeLua, coordinates, unitMakerGroupFlags, extraSettings ); if (unitsIDList.Count == 0) { return(null); // No valid units added to this group } GeneratorTools.ReplaceKey(ref groupLua, "Units", unitsLuaTable); DBEntryUnit firstUnitDB = units.Select(x => Database.Instance.GetEntry <DBEntryUnit>(x)).First(x => x != null); var aircraftCategories = new UnitCategory[] { UnitCategory.Helicopter, UnitCategory.Plane }; var isAircraft = firstUnitDB != null && aircraftCategories.Contains(firstUnitDB.Category); if (isAircraft) { groupLua = ApplyAircraftFields(groupLua, firstUnitDB, extraSettings); if (unitMakerGroupFlags.HasFlag(UnitMakerGroupFlags.ImmediateAircraftSpawn)) { Mission.AppendValue("AircraftActivatorCurrentQueue", $"{GroupID},"); } else if (unitMakerGroupFlags.HasFlag(UnitMakerGroupFlags.RadioAircraftSpawn)) { Mission.AppendValue("AircraftRadioActivator", $"{{{GroupID}, \"{groupName}\"}},"); } else if (groupTypeLua != "GroupAircraftParkedUncontrolled") { Mission.AppendValue("AircraftActivatorReserveQueue", $"{GroupID},"); } } GeneratorTools.ReplaceKey(ref groupLua, "UnitID", firstUnitID); // Must be after units are added GeneratorTools.ReplaceKey(ref groupLua, "Skill", skill); // Must be after units are added, because skill is set as a unit level GeneratorTools.ReplaceKey(ref groupLua, "Hidden", GeneratorTools.GetHiddenStatus(Template.OptionsFogOfWar, side, unitMakerGroupFlags)); // If "hidden" was not set through custom values AddUnitGroupToTable(country, unitFamily.GetUnitCategory(), groupLua); BriefingRoom.PrintToLog($"Added group of {units.Length} {coalition} {unitFamily} at {coordinates}"); GroupID++; if (firstUnitDB == null) { return(new UnitMakerGroupInfo(GroupID - 1, coordinates, unitsIDList, groupName)); } return(new UnitMakerGroupInfo(GroupID - 1, coordinates, unitsIDList, groupName, firstUnitDB.AircraftData.RadioFrequency, firstUnitDB)); }