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); }
private string CreateGroup( string groupTypeLua, Coordinates coordinates, string groupName, params KeyValuePair <string, object>[] extraSettings ) { string lua = File.ReadAllText($"{BRPaths.INCLUDE_LUA_UNITS}{Toolbox.AddMissingFileExtension(groupTypeLua, ".lua")}"); foreach (KeyValuePair <string, object> extraSetting in extraSettings) // Replace custom values first so they override other replacements { if (!(extraSetting.Value is Array)) // Array extra settings are treated on a per-unit basis { GeneratorTools.ReplaceKey(ref lua, extraSetting.Key, extraSetting.Value); } } GeneratorTools.ReplaceKey(ref lua, "GroupID", GroupID); GeneratorTools.ReplaceKey(ref lua, "GroupX", coordinates.X); GeneratorTools.ReplaceKey(ref lua, "GroupY", coordinates.Y); GeneratorTools.ReplaceKey(ref lua, "GroupX2", coordinates.X); // GroupX2 and GroupY2 are replaced by the default coordinates only if they were not replaced earlier in extraSetting replacements. GeneratorTools.ReplaceKey(ref lua, "GroupY2", coordinates.Y); GeneratorTools.ReplaceKey(ref lua, "Name", groupName); return(lua); }
private static string ConstructTaskDescriptions(Dictionary <string, List <string> > descriptionsMap, DCSMission mission) { var briefingDescriptionList = new List <string>(); var maxDescriptionCount = Database.Instance.Common.Briefing.MaxObjectiveDescriptionCount; while (descriptionsMap.Keys.Count > 0 && briefingDescriptionList.Count < maxDescriptionCount) { var task = descriptionsMap.Keys.First(); if (descriptionsMap.Keys.Count > 1) { task = Out.Of() .Values(descriptionsMap.Keys.ToList()) .WithWeights(descriptionsMap.Values.Select(x => x.Count).ToList()) .PickOne(); } var item = descriptionsMap[task].GroupBy(i => i).OrderByDescending(grp => grp.Count()).Select(grp => grp.Key).First(); descriptionsMap[task].Remove(item); if (descriptionsMap[task].Count == 0) { descriptionsMap.Remove(task); } briefingDescriptionList.Add(item); } var description = GeneratorTools.ParseRandomString(JoinObjectiveDescriptions(briefingDescriptionList), mission); if (descriptionsMap.Keys.Count > 0 && briefingDescriptionList.Count == maxDescriptionCount) { description = $"{description} {Database.Instance.Common.Briefing.OverflowObjectiveDescriptionText}"; } return(description); }
protected void AddBriefingRemarkFromFeature(T featureDB, DCSMission mission, bool useEnemyRemarkIfAvailable, UnitMakerGroupInfo?groupInfo, Dictionary <string, object> stringReplacements) { string[] remarks; if (useEnemyRemarkIfAvailable && featureDB.BriefingRemarks[(int)Side.Enemy].Length > 0) { remarks = featureDB.BriefingRemarks[(int)Side.Enemy].ToArray(); } else { remarks = featureDB.BriefingRemarks[(int)Side.Ally].ToArray(); } if (remarks.Length == 0) { return; // No briefing remarks for this feature } string remark = Toolbox.RandomFrom(remarks); foreach (KeyValuePair <string, object> stringReplacement in stringReplacements) { GeneratorTools.ReplaceKey(ref remark, stringReplacement.Key, stringReplacement.Value.ToString()); } if (groupInfo.HasValue) { GeneratorTools.ReplaceKey(ref remark, "GroupName", groupInfo.Value.Name); GeneratorTools.ReplaceKey(ref remark, "GroupFrequency", GeneratorTools.FormatRadioFrequency(groupInfo.Value.Frequency)); GeneratorTools.ReplaceKey(ref remark, "GroupUnitName", groupInfo.Value.UnitDB.UIDisplayName); } mission.Briefing.AddItem(DCSMissionBriefingItemType.Remark, remark, featureDB is DBEntryFeatureMission); }
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 }
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 void AddToList(string UIName, string template, Coordinates coordinates, DrawingColour colour, DrawingColour fillColour) { GeneratorTools.ReplaceKey(ref template, "UIName", UIName); GeneratorTools.ReplaceKey(ref template, "X", coordinates.X); GeneratorTools.ReplaceKey(ref template, "Y", coordinates.Y); GeneratorTools.ReplaceKey(ref template, "Colour", colour.ToValue()); GeneratorTools.ReplaceKey(ref template, "FillColour", fillColour.ToValue()); LuaDrawings.Add(template); }
private string ApplyAircraftFields(string groupLua, DBEntryUnit firstUnitDB, params KeyValuePair <string, object>[] extraSettings) { GeneratorTools.ReplaceKey(ref groupLua, "Altitude", firstUnitDB.AircraftData.CruiseAltitude); GeneratorTools.ReplaceKey(ref groupLua, "AltitudeHalf", firstUnitDB.AircraftData.CruiseAltitude / 2); GeneratorTools.ReplaceKey(ref groupLua, "EPLRS", firstUnitDB.Flags.HasFlag(DBEntryUnitFlags.EPLRS)); GeneratorTools.ReplaceKey(ref groupLua, "RadioBand", (int)firstUnitDB.AircraftData.RadioModulation); GeneratorTools.ReplaceKey(ref groupLua, "RadioFrequency", firstUnitDB.AircraftData.RadioFrequency); GeneratorTools.ReplaceKey(ref groupLua, "Speed", firstUnitDB.AircraftData.CruiseSpeed); return(groupLua); }
private void AddTextBox(string UIName, Coordinates coordinates, params KeyValuePair <string, object>[] extraSettings) { string drawingLuaTemplate = File.ReadAllText($"{BRPaths.INCLUDE_LUA_MISSION}\\Drawing\\TextBox.lua"); GeneratorTools.ReplaceKey(ref drawingLuaTemplate, "Text", extraSettings.First(x => x.Key == "Text").Value); DrawingColour colour = (DrawingColour)(extraSettings.FirstOrDefault(x => x.Key == "Colour").Value ?? DrawingColour.Red); DrawingColour fillColour = (DrawingColour)(extraSettings.FirstOrDefault(x => x.Key == "FillColour").Value ?? DrawingColour.White); AddToList(UIName, drawingLuaTemplate, coordinates, colour, fillColour); }
private static void CreateTaskString(DCSMission mission, int pluralIndex, ref string taskString, string objectiveName, UnitFamily objectiveTargetUnitFamily) { // Get tasking string for the briefing if (string.IsNullOrEmpty(taskString)) { taskString = "Complete objective $OBJECTIVENAME$"; } GeneratorTools.ReplaceKey(ref taskString, "ObjectiveName", objectiveName); GeneratorTools.ReplaceKey(ref taskString, "UnitFamily", Database.Instance.Common.Names.UnitFamilies[(int)objectiveTargetUnitFamily][pluralIndex]); mission.Briefing.AddItem(DCSMissionBriefingItemType.Task, taskString); }
private void AddToList(string UIName, Coordinates coordinates, int radius) { string template = File.ReadAllText($"{BRPaths.INCLUDE_LUA_MISSION}\\Zone.lua"); GeneratorTools.ReplaceKey(ref template, "NAME", UIName); GeneratorTools.ReplaceKey(ref template, "RADIUS", radius); GeneratorTools.ReplaceKey(ref template, "X", coordinates.X); GeneratorTools.ReplaceKey(ref template, "Y", coordinates.Y); GeneratorTools.ReplaceKey(ref template, "zoneId", new Random().Next(100, 500)); LuaZones.Add(template); }
private static void SaveFlightGroup(DCSMission mission, UnitMakerGroupInfo?groupInfo, MissionTemplateFlightGroupRecord flightGroup, DBEntryUnit unitDB, string homeBase) { mission.Briefing.AddItem(DCSMissionBriefingItemType.FlightGroup, $"{groupInfo.Value.Name}(P)\t" + $"{flightGroup.Count}× {unitDB.UIDisplayName}\t" + $"{GeneratorTools.FormatRadioFrequency(unitDB.AircraftData.RadioFrequency)}\t" + $"{Toolbox.FormatPayload(flightGroup.Payload)}\t" + $"{homeBase}"); for (int i = 0; i < flightGroup.Count; i++) { mission.AppendValue("SCRIPTCLIENTPILOTNAMES", $"\"{groupInfo.Value.Name} {i + 2}\","); } }
internal string GetLuaDrawings() { string luaDrawings = ""; var index = 1; foreach (var drawing in LuaDrawings) { var drawingLua = drawing; GeneratorTools.ReplaceKey(ref drawingLua, "Index", index); luaDrawings += $"{drawingLua}\n"; index++; } return(luaDrawings); }
internal string GetLuaZones() { string luaDrawings = ""; var index = 1; foreach (var zone in LuaZones) { var zoneLua = zone; GeneratorTools.ReplaceKey(ref zoneLua, "Index", index); luaDrawings += $"{zoneLua}\n"; index++; } return(luaDrawings); }
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()); } }
private string GetExtraSettingsFromFeature(T featureDB, ref Dictionary <string, object> extraSettings) { // TODO: Improve if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.TACAN) && (featureDB.UnitGroupFamilies.Length > 0)) { var callsign = $"{GeneratorTools.GetTACANCallsign(featureDB.UnitGroupFamilies[0])}{TACANIndex}"; var channel = ((GetType() == typeof(MissionGeneratorFeaturesObjectives)) ? 30 : 20) + TACANIndex; extraSettings.AddIfKeyUnused("TACANFrequency", 1108000000); extraSettings.AddIfKeyUnused("TACANCallsign", callsign); extraSettings.AddIfKeyUnused("TACANChannel", channel); if (TACANIndex < 9) { TACANIndex++; } return($",\n{channel}X (callsign {callsign})"); } return(""); }
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); }
private void SpawnExtraGroups(T featureDB, DCSMission mission, Side groupSide, UnitMakerGroupFlags groupFlags, Coordinates coordinates, Coordinates coordinates2, Dictionary <string, object> extraSettings) { foreach (var i in Enumerable.Range(1, featureDB.ExtraGroups.GetValue())) { var groupLua = featureDB.UnitGroupLuaGroup; var unitCount = featureDB.UnitGroupSize.GetValue(); var unitFamily = Toolbox.RandomFrom(featureDB.UnitGroupFamilies); var luaUnit = featureDB.UnitGroupLuaUnit; var spawnCoords = _unitMaker.SpawnPointSelector.GetRandomSpawnPoint( featureDB.UnitGroupValidSpawnPoints, coordinates, new MinMaxD(0, 5), coalition: GeneratorTools.GetSpawnPointCoalition(_template, groupSide) ); if (!spawnCoords.HasValue) { continue; } SetAirbase(featureDB, unitFamily, ref groupLua, ref luaUnit, groupSide, ref coordinates, coordinates2, unitCount, ref extraSettings); var groupInfo = _unitMaker.AddUnitGroup( unitFamily, unitCount, groupSide, groupLua, luaUnit, spawnCoords.Value, groupFlags, extraSettings.ToArray()); if ( groupSide == Side.Ally && groupInfo.HasValue && groupInfo.Value.UnitDB != null && groupInfo.Value.UnitDB.IsAircraft) { mission.Briefing.AddItem(DCSMissionBriefingItemType.FlightGroup, $"{groupInfo.Value.Name}\t" + $"{unitCount}× {groupInfo.Value.UnitDB.UIDisplayName}\t" + $"{GeneratorTools.FormatRadioFrequency(groupInfo.Value.Frequency)}\t" + $"{Toolbox.FormatPayload(featureDB.UnitGroupPayload)}"); } } }
internal static void GenerateWarehouses(DCSMission mission) { string warehousesAirportLua = ""; if (!File.Exists(AIRPORT_TEMPLATE_FILEPATH)) { throw new Exception("Airport warehouse template file (Include\\Lua\\Warehouses\\Airport.lua) not found."); } string airportLuaTemplate = File.ReadAllText(AIRPORT_TEMPLATE_FILEPATH); foreach (int airbaseID in mission.Airbases.Keys) { string airportLua = airportLuaTemplate; GeneratorTools.ReplaceKey(ref airportLua, "index", airbaseID); GeneratorTools.ReplaceKey(ref airportLua, "coalition", mission.Airbases[airbaseID].ToString().ToUpperInvariant()); warehousesAirportLua += airportLua + "\r\n"; } mission.SetValue("WarehousesAirports", warehousesAirportLua); }
internal static void GenerateMissionBriefingDescription(DCSMission mission, MissionTemplateRecord template, List <UnitFamily> objectiveTargetUnitFamilies, DBEntrySituation situationDB) { // Try to get the provided custom mission description. string briefingDescription = (template.BriefingMissionDescription ?? "").Replace("\r\n", "\n").Replace("\n", " ").Trim(); // No custom description found, generate one from the most frequent objective task/target combination. if (string.IsNullOrEmpty(briefingDescription)) { if (template.Objectives.Count == 0) { briefingDescription = ""; } else { var familyCount = 0; Dictionary <string, List <string> > descriptionsMap = new Dictionary <string, List <string> >(); foreach (var obj in template.Objectives) { DBEntryBriefingDescription descriptionDB = Database.Instance.GetEntry <DBEntryBriefingDescription>( Database.Instance.GetEntry <DBEntryObjectiveTask>(obj.Task).BriefingDescription); AppendDescription(obj.Task, descriptionDB.DescriptionText[(int)objectiveTargetUnitFamilies[familyCount]], ref descriptionsMap); familyCount++; AddSubTasks(obj, objectiveTargetUnitFamilies, ref descriptionsMap, ref familyCount); } briefingDescription = ConstructTaskDescriptions(descriptionsMap, mission); } } if (situationDB.BriefingDescriptions != null && situationDB.BriefingDescriptions.Count > 0) { briefingDescription = GeneratorTools.ParseRandomString(string.Join(" ", Toolbox.RandomFrom(situationDB.BriefingDescriptions), briefingDescription), mission); } mission.Briefing.Description = briefingDescription; mission.SetValue("BRIEFINGDESCRIPTION", briefingDescription); }
private void AddFree(string UIName, Coordinates coordinates, params KeyValuePair <string, object>[] extraSettings) { string drawingLuaTemplate = File.ReadAllText($"{BRPaths.INCLUDE_LUA_MISSION}\\Drawing\\Free.lua"); string freePosLuaTemplate = File.ReadAllText($"{BRPaths.INCLUDE_LUA_MISSION}\\Drawing\\FreePos.lua"); var points = ""; var index = 1; foreach (Coordinates pos in (List <Coordinates>)extraSettings.First(x => x.Key == "Points").Value) { var templateLua = new String(freePosLuaTemplate); GeneratorTools.ReplaceKey(ref templateLua, "Index", index); GeneratorTools.ReplaceKey(ref templateLua, "X", pos.X); GeneratorTools.ReplaceKey(ref templateLua, "Y", pos.Y); points += $"{templateLua}\n"; index++; } GeneratorTools.ReplaceKey(ref drawingLuaTemplate, "POINTS", points); DrawingColour colour = (DrawingColour)(extraSettings.FirstOrDefault(x => x.Key == "Colour").Value ?? DrawingColour.Red); DrawingColour fillColour = (DrawingColour)(extraSettings.FirstOrDefault(x => x.Key == "FillColour").Value ?? DrawingColour.RedFill); AddToList(UIName, drawingLuaTemplate, coordinates, colour, fillColour); }
private static string GenerateFlightPlanLua(List <Waypoint> waypoints) { string flightPlanLua = ""; string waypointLuaTemplate = File.ReadAllText($"{BRPaths.INCLUDE_LUA_MISSION}WaypointPlayer.lua"); for (int i = 0; i < waypoints.Count; i++) { string waypointLua = waypointLuaTemplate; GeneratorTools.ReplaceKey(ref waypointLua, "Index", i + 2); GeneratorTools.ReplaceKey(ref waypointLua, "Name", waypoints[i].Name); GeneratorTools.ReplaceKey(ref waypointLua, "X", waypoints[i].Coordinates.X); GeneratorTools.ReplaceKey(ref waypointLua, "Y", waypoints[i].Coordinates.Y); if (waypoints[i].OnGround) { GeneratorTools.ReplaceKey(ref waypointLua, "Altitude", "0"); } flightPlanLua += waypointLua + "\n"; } return(flightPlanLua); }
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 UnitMakerGroupInfo?AddUnitGroup( List <UnitFamily> families, int unitCount, Side side, string groupLua, string unitLua, Coordinates coordinates, UnitMakerGroupFlags unitMakerGroupFlags = 0, params KeyValuePair <string, object>[] extraSettings) { if (unitCount <= 0) { throw new BriefingRoomException("Asking for a zero units"); } if (families.Count <= 0) { throw new BriefingRoomException("No Unit Families Provided"); } DBEntryCoalition unitsCoalitionDB = CoalitionsDB[(int)((side == Side.Ally) ? PlayerCoalition : PlayerCoalition.GetEnemy())]; var(country, units) = unitsCoalitionDB.GetRandomUnits(families, Template.ContextDecade, unitCount, Template.Mods); if (units.Count == 0) { throw new BriefingRoomException($"Found no units for {string.Join(", ", families)} {country}"); } if (country != Country.ALL) { extraSettings = extraSettings.Append("Country".ToKeyValuePair(country)).ToArray(); } if (unitMakerGroupFlags.HasFlag(UnitMakerGroupFlags.EmbeddedAirDefense) && (families.First().GetUnitCategory() == UnitCategory.Vehicle)) { string[] airDefenseUnits = GeneratorTools.GetEmbeddedAirDefenseUnits(Template, side, country != Country.ALL ? country : null); units.AddRange(airDefenseUnits); } return(AddUnitGroup(Toolbox.ShuffleArray(units.ToArray()), side, families.First(), groupLua, unitLua, coordinates, unitMakerGroupFlags, extraSettings)); }
private void SetAirbase(T featureDB, UnitFamily unitFamily, ref string groupLua, ref string luaUnit, Side groupSide, ref Coordinates coordinates, Coordinates coordinates2, int unitCount, ref Dictionary <string, object> extraSettings) { if ((_template.MissionFeatures.Contains("ContextGroundStartAircraft") || featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.GroundStart)) && Toolbox.IsAircraft(unitFamily.GetUnitCategory())) { if (groupLua != "GroupAircraftParkedUncontrolled") { groupLua += "Parked"; } luaUnit += "Parked"; var(airbase, parkingSpotIDsList, parkingSpotCoordinatesList) = _unitMaker.SpawnPointSelector.GetAirbaseAndParking( _template, coordinates, unitCount, GeneratorTools.GetSpawnPointCoalition(_template, groupSide, true).Value, unitFamily); coordinates = airbase.Coordinates; extraSettings["ParkingID"] = parkingSpotIDsList.ToArray(); extraSettings["GroupAirbaseID"] = airbase.DCSID; extraSettings["UnitX"] = (from Coordinates unitCoordinates in parkingSpotCoordinatesList select unitCoordinates.X).ToArray(); extraSettings["UnitY"] = (from Coordinates unitCoordinates in parkingSpotCoordinatesList select unitCoordinates.Y).ToArray(); var midPoint = Coordinates.Lerp(coordinates, coordinates2, 0.4); extraSettings.AddIfKeyUnused("GroupMidX", midPoint.X); extraSettings.AddIfKeyUnused("GroupMidY", midPoint.Y); } }
protected UnitMakerGroupInfo?AddMissionFeature(T featureDB, DCSMission mission, Coordinates coordinates, Coordinates?coordinates2, ref Dictionary <string, object> extraSettings, Side?objectiveTargetSide = null, bool hideEnemy = false) { // Add secondary coordinates (destination point) to the extra settings if (!coordinates2.HasValue) { coordinates2 = coordinates; // No destination point? Use initial point } extraSettings.AddIfKeyUnused("GroupX2", coordinates2.Value.X); extraSettings.AddIfKeyUnused("GroupY2", coordinates2.Value.Y); var TACANStr = GetExtraSettingsFromFeature(featureDB, ref extraSettings); // Add specific settings for this feature (TACAN frequencies, etc) // Feature unit group UnitMakerGroupInfo?groupInfo = null; if (FeatureHasUnitGroup(featureDB)) { UnitMakerGroupFlags groupFlags = 0; if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.ImmediateAircraftActivation)) { groupFlags |= UnitMakerGroupFlags.ImmediateAircraftSpawn; } if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.RadioAircraftActivation)) { groupFlags |= UnitMakerGroupFlags.RadioAircraftSpawn; } Side groupSide = Side.Enemy; if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.Friendly)) { groupSide = Side.Ally; } else if (featureDB.UnitGroupFlags.HasFlag(FeatureUnitGroupFlags.SameSideAsTarget) && objectiveTargetSide.HasValue) { groupSide = objectiveTargetSide.Value; } if (hideEnemy && groupSide == Side.Enemy) { groupFlags |= UnitMakerGroupFlags.AlwaysHidden; } extraSettings.AddIfKeyUnused("Payload", featureDB.UnitGroupPayload); var groupLua = featureDB.UnitGroupLuaGroup; var unitCount = featureDB.UnitGroupSize.GetValue(); var unitFamily = Toolbox.RandomFrom(featureDB.UnitGroupFamilies); var luaUnit = featureDB.UnitGroupLuaUnit; SetAirbase(featureDB, unitFamily, ref groupLua, ref luaUnit, groupSide, ref coordinates, coordinates2.Value, unitCount, ref extraSettings); groupInfo = _unitMaker.AddUnitGroup( unitFamily, unitCount, groupSide, groupLua, luaUnit, coordinates, groupFlags, extraSettings.ToArray()); if ( groupSide == Side.Ally && groupInfo.HasValue && groupInfo.Value.UnitDB != null && groupInfo.Value.UnitDB.IsAircraft) { mission.Briefing.AddItem(DCSMissionBriefingItemType.FlightGroup, $"{groupInfo.Value.Name}\t" + $"{unitCount}× {groupInfo.Value.UnitDB.UIDisplayName}\t" + $"{GeneratorTools.FormatRadioFrequency(groupInfo.Value.Frequency)}{TACANStr}\t" + $"{Toolbox.FormatPayload(featureDB.UnitGroupPayload)}"); // TODO: human-readable payload name } if (featureDB.ExtraGroups.Max > 1) { SpawnExtraGroups(featureDB, mission, groupSide, groupFlags, coordinates, coordinates2.Value, extraSettings); } } // Feature Lua script string featureLua = ""; // Adds the features' group ID to the briefingRoom.mission.missionFeatures.groupsID table if (this is MissionGeneratorFeaturesMission) { featureLua += $"briefingRoom.mission.missionFeatures.groupsID.{GeneratorTools.LowercaseFirstCharacter(featureDB.ID)} = {(groupInfo.HasValue ? groupInfo.Value.GroupID : 0)}\n"; featureLua += $"briefingRoom.mission.missionFeatures.unitsID.{GeneratorTools.LowercaseFirstCharacter(featureDB.ID)} = {{{(groupInfo.HasValue ? string.Join(",", groupInfo.Value.UnitsID) : "")}}}\n"; } if (!string.IsNullOrEmpty(featureDB.IncludeLuaSettings)) { featureLua = featureDB.IncludeLuaSettings + "\n"; } foreach (string luaFile in featureDB.IncludeLua) { featureLua += Toolbox.ReadAllTextIfFileExists($"{featureDB.SourceLuaDirectory}{luaFile}") + "\n"; } foreach (KeyValuePair <string, object> extraSetting in extraSettings) { GeneratorTools.ReplaceKey(ref featureLua, extraSetting.Key, extraSetting.Value); } if (groupInfo.HasValue) { GeneratorTools.ReplaceKey(ref featureLua, "FeatureGroupID", groupInfo.Value.GroupID); } if (featureDB is DBEntryFeatureObjective) { mission.AppendValue("ScriptObjectivesFeatures", featureLua); } else { mission.AppendValue("ScriptMissionFeatures", featureLua); } // Add feature ogg files foreach (string oggFile in featureDB.IncludeOgg) { mission.AddMediaFile($"l10n/DEFAULT/{oggFile}", $"{BRPaths.INCLUDE_OGG}{oggFile}"); } return(groupInfo); }
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)); }
private string AddUnit( string DCSID, string groupName, UnitCallsign?callsign, int unitLuaIndex, int unitSetIndex, DBEntryUnit unitDB, string unitTypeLua, Coordinates coordinates, UnitMakerGroupFlags unitMakerGroupFlags, params KeyValuePair <string, object>[] extraSettings) { string unitLuaTemplate = File.ReadAllText($"{BRPaths.INCLUDE_LUA_UNITS}{Toolbox.AddMissingFileExtension(unitTypeLua, ".lua")}"); var groupHeading = GetGroupHeading(coordinates, extraSettings); SetUnitCoordinatesAndHeading(unitDB, unitSetIndex, coordinates, groupHeading, out Coordinates unitCoordinates, out double unitHeading); string singleUnitLuaTable = new string(unitLuaTemplate); if (Toolbox.IsAircraft(unitDB.Category) && (unitLuaIndex == 1) && unitMakerGroupFlags.HasFlag(UnitMakerGroupFlags.FirstUnitIsClient)) { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Skill", SinglePlayerMission ? "Player" : "Client"); } foreach (KeyValuePair <string, object> extraSetting in extraSettings) // Replace custom values first so they override other replacements { if (extraSetting.Value is Array) { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, extraSetting.Key, extraSetting.Value, unitLuaIndex - 1); } else { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, extraSetting.Key, extraSetting.Value); } } GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "ExtraLua", unitDB.ExtraLua); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Heading", unitHeading); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "DCSID", DCSID); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "UnitID", UnitID); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "UnitX", unitCoordinates.X); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "UnitY", unitCoordinates.Y); if (Toolbox.IsAircraft(unitDB.Category)) { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Callsign", callsign.Value.GetLua(unitLuaIndex)); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Name", callsign.Value.GetUnitName(unitLuaIndex)); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "OnBoardNumber", Toolbox.RandomInt(1, 1000).ToString("000")); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "PropsLua", unitDB.AircraftData.PropsLua); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "RadioPresetsLua", string.Join("", unitDB.AircraftData.RadioPresets.Select((x, index) => $"[{index + 1}] = {x.ToLuaString()}"))); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Speed", unitDB.AircraftData.CruiseSpeed); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "PayloadCommon", unitDB.AircraftData.PayloadCommon); var payload = unitDB.AircraftData.GetPayloadLua(extraSettings.Any(x => x.Key == "Payload") ? extraSettings.First(x => x.Key == "Payload").Value.ToString() : "default"); if (extraSettings.Any(x => x.Key == "Payload" && x.Value.ToString() == "EMPTY")) { payload = ""; } GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "PayloadPylons", payload); GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Livery", extraSettings.Any(x => x.Key == "Livery") ? extraSettings.First(x => x.Key == "Livery").Value : "default"); } else if (unitDB.Category == UnitCategory.Static || unitDB.Category == UnitCategory.Cargo) { if (unitDB.Shape.Length - 1 > unitSetIndex) { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Shape", unitDB.Shape[unitSetIndex]); } GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Name", $"{groupName} {unitLuaIndex}"); } else { GeneratorTools.ReplaceKey(ref singleUnitLuaTable, "Name", $"{groupName} {unitLuaIndex}"); } var unitString = $"[{unitLuaIndex}] =\n"; unitString += "{\n"; unitString += $"{singleUnitLuaTable}\n"; unitString += $"}}, -- end of [{unitLuaIndex}]\n"; return(unitString); }
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 static Dictionary <string, UnitMakerGroupInfo> GenerateCarrierGroup( UnitMaker unitMaker, ZoneMaker zoneMaker, DCSMission mission, MissionTemplateRecord template, Coordinates landbaseCoordinates, Coordinates objectivesCenter, double windSpeedAtSeaLevel, double windDirectionAtSeaLevel) { Dictionary <string, UnitMakerGroupInfo> carrierDictionary = new Dictionary <string, UnitMakerGroupInfo>(StringComparer.InvariantCultureIgnoreCase); DBEntryTheater theaterDB = Database.Instance.GetEntry <DBEntryTheater>(template.ContextTheater); double carrierSpeed = Math.Max( Database.Instance.Common.CarrierGroup.MinimumCarrierSpeed, Database.Instance.Common.CarrierGroup.IdealWindOfDeck - windSpeedAtSeaLevel); if (windSpeedAtSeaLevel == 0) // No wind? Pick a random direction so carriers don't always go to a 0 course when wind is calm. { windDirectionAtSeaLevel = Toolbox.RandomDouble(Toolbox.TWO_PI); } var carrierPathDeg = ((windDirectionAtSeaLevel + Math.PI) % Toolbox.TWO_PI) * Toolbox.RADIANS_TO_DEGREES; var usedCoordinates = new List <Coordinates>(); foreach (MissionTemplateFlightGroupRecord flightGroup in template.PlayerFlightGroups) { if (string.IsNullOrEmpty(flightGroup.Carrier)) { continue; // No carrier for } if (carrierDictionary.ContainsKey(flightGroup.Carrier)) { continue; // Carrier type already added } if (flightGroup.Carrier.StartsWith("FOB")) { //It Carries therefore carrier not because I can't think of a name to rename this lot GenerateFOB(unitMaker, zoneMaker, flightGroup, carrierDictionary, mission, template, landbaseCoordinates, objectivesCenter); continue; } DBEntryUnit unitDB = Database.Instance.GetEntry <DBEntryUnit>(flightGroup.Carrier); if ((unitDB == null) || !unitDB.Families.Any(x => x.IsCarrier())) { continue; // Unit doesn't exist or is not a carrier } var(shipCoordinates, shipDestination) = GetSpawnAndDestination(unitMaker, template, theaterDB, usedCoordinates, landbaseCoordinates, objectivesCenter, carrierPathDeg); usedCoordinates.Add(shipCoordinates); string cvnID = carrierDictionary.Count > 0 ? (carrierDictionary.Count + 1).ToString() : ""; int ilsChannel = 11 + carrierDictionary.Count; double radioFrequency = 127.5 + carrierDictionary.Count; string tacanCallsign = $"CVN{cvnID}"; int tacanChannel = 74 + carrierDictionary.Count; UnitMakerGroupInfo?groupInfo = unitMaker.AddUnitGroup( new string[] { unitDB.ID }, Side.Ally, unitDB.Families[0], "GroupShipCarrier", "UnitShip", shipCoordinates, 0, "GroupX2".ToKeyValuePair(shipDestination.X), "GroupY2".ToKeyValuePair(shipDestination.Y), "ILS".ToKeyValuePair(ilsChannel), "RadioBand".ToKeyValuePair((int)RadioModulation.AM), "RadioFrequency".ToKeyValuePair(GeneratorTools.GetRadioFrenquency(radioFrequency)), "Speed".ToKeyValuePair(carrierSpeed), "TACANCallsign".ToKeyValuePair(tacanCallsign), "TACANChannel".ToKeyValuePair(tacanChannel), "TACANFrequency".ToKeyValuePair(GeneratorTools.GetTACANFrequency(tacanChannel, 'X', false)), "TACANMode".ToKeyValuePair("X")); if (!groupInfo.HasValue || (groupInfo.Value.UnitsID.Length == 0)) { continue; // Couldn't generate group } mission.Briefing.AddItem( DCSMissionBriefingItemType.Airbase, $"{unitDB.UIDisplayName}\t-\t{GeneratorTools.FormatRadioFrequency(radioFrequency)}\t{ilsChannel}\t{tacanCallsign}, {tacanChannel}X"); carrierDictionary.Add(flightGroup.Carrier, groupInfo.Value); } return(carrierDictionary); }