internal DBCommonCAPLevel(INIFile ini, AmountNR capLevel) { if ((capLevel == AmountNR.None) || (capLevel == AmountNR.Random)) { SkillLevel = new DCSSkillLevel[] { DCSSkillLevel.Average }; UnitCount = new MinMaxI(0, 0); return; } SkillLevel = ini.GetValueArray <DCSSkillLevel>("CAPLevels", $"{capLevel}.SkillLevel").Distinct().ToArray(); if (SkillLevel.Length == 0) { SkillLevel = new DCSSkillLevel[] { DCSSkillLevel.Average, DCSSkillLevel.Good, DCSSkillLevel.High, DCSSkillLevel.Excellent } } ; UnitCount = ini.GetValue <MinMaxI>("CAPLevels", $"{capLevel}.UnitCount"); } }
private string MakeUnitsUnitsLua(DCSMissionUnitGroup group, bool singlePlayer) { string unitsLua = ""; for (int i = 0; i < group.UnitCount; i++) { string singleUnitLua = HQTools.ReadIncludeLuaFile($"Mission\\{group.LuaUnit}.lua"); DCSSkillLevel skillLevel = group.UnitsSkill; if (group.Flags.Contains(UnitGroupFlag.FirstUnitIsClient) && (i == 0)) { skillLevel = DCSSkillLevel.Client; } HQTools.ReplaceKey(ref singleUnitLua, "Name", group.Name); // Must be replaced before "Index" because some unit names contain "$INDEX$" HQTools.ReplaceKey(ref singleUnitLua, "UnitID", UnitID); HQTools.ReplaceKey(ref singleUnitLua, "Unit", group.Units[i]); HQTools.ReplaceKey(ref singleUnitLua, "Heading", group.GetUnitHeading(i)); HQTools.ReplaceKey(ref singleUnitLua, "Skill", skillLevel.ToString()); HQTools.ReplaceKey(ref singleUnitLua, "X", group.GetUnitCoordinates(i).X); HQTools.ReplaceKey(ref singleUnitLua, "Y", group.GetUnitCoordinates(i).Y); foreach (DCSMissionUnitGroupCustomValueKey k in group.CustomValues.Keys) { if (k.UnitIndex != i) { continue; // Replacement does not target this unit, continue } HQTools.ReplaceKey(ref singleUnitLua, k.Key, group.CustomValues[k]); } HQTools.ReplaceKey(ref singleUnitLua, "Index", i + 1); // Must be last, used by other values unitsLua += singleUnitLua + "\r\n"; UnitID++; } return(unitsLua); }
/// <summary> /// Main unit generation method. /// </summary> /// <param name="mission">Mission to which generated units should be added</param> /// <param name="template">Mission template to use</param> /// <param name="objectiveDB">Mission objective database entry</param> /// <param name="coalitionsDB">Coalitions database entries</param> /// <param name="moving">Will the group be moving</param> /// <param name="objectiveGroup">If the group should be tracked as an objective</param> public void SpawnUnitGroups(DCSMission mission, MissionTemplate template, DBUnitGroup unitGroup, DBEntryCoalition[] coalitionsDB, Side side, Coalition coalition) { DCSMissionUnitGroupFlags flags = GeneratorTools.ShouldUnitBeHidden(unitGroup, !template.OptionsPreferences.Contains(MissionTemplatePreferences.HideEnemyUnits)) ? DCSMissionUnitGroupFlags.Hidden : 0; for (int i = 0; i < mission.Objectives.Length; i++) { // This objective requires no unit group generation if (!mission.Objectives[i].TargetFamily.HasValue) { continue; } string[] units = coalitionsDB[(int)coalition].GetRandomUnits( mission.Objectives[i].TargetFamily.Value, mission.DateTime.Decade, unitGroup.Count.GetValue(), template.OptionsUnitMods); if (unitGroup.Flags.HasFlag(DBUnitGroupFlags.EmbeddedAirDefense) && coalition != mission.CoalitionPlayer && (Toolbox.GetUnitCategoryFromUnitFamily(mission.Objectives[i].TargetFamily.Value) == UnitCategory.Vehicle)) { units = GeneratorTools.AddEmbeddedAirDefense(units, template.OppositionAirDefense, coalitionsDB[(int)coalition], mission.DateTime.Decade, template.OptionsUnitMods); } // Pick the skill level once for each objective so not all target groups have the same skill level when a // "random" skill level is chosen. DCSSkillLevel skillLevel = Toolbox.IsUnitFamilyAircraft(mission.Objectives[i].TargetFamily.Value) ? Toolbox.BRSkillLevelToDCSSkillLevel(template.OppositionSkillLevelAir) : Toolbox.BRSkillLevelToDCSSkillLevel(template.OppositionSkillLevelGround); DCSMissionUnitGroup group; DBEntryTheaterSpawnPoint?spawnPoint = null; if (unitGroup.Flags.HasFlag(DBUnitGroupFlags.DestinationObjective)) { spawnPoint = UnitMaker.SpawnPointSelector.GetRandomSpawnPoint( unitGroup.SpawnPoints, mission.Objectives[i].Coordinates, unitGroup.DistanceFromPoint); if (!spawnPoint.HasValue) { throw new Exception($"Failed to find spawn point for moving objective unit"); } } group = UnitMaker.AddUnitGroup( mission, units, side, spawnPoint != null? spawnPoint.Value.Coordinates : mission.Objectives[i].Coordinates, Toolbox.RandomFrom(unitGroup.LuaGroup), unitGroup.LuaUnit, skillLevel, flags, coordinates2: getDestination(unitGroup, mission, i)); // Something went wrong, abort mission generation, objective unit groups are required for the mission to work properly. if (group == null) { throw new Exception($"Failed to create objective unit group for objective #{i + 1} made of the following units: {string.Join(", ", units)}"); } // Add aircraft group to the queue of aircraft groups to be spawned if ((group.Category == UnitCategory.Helicopter) || (group.Category == UnitCategory.Plane) || unitGroup.Flags.HasFlag(DBUnitGroupFlags.DelaySpawn)) { mission.AircraftSpawnQueue.Add(new DCSMissionAircraftSpawnQueueItem(group.GroupID, true)); } if (!unitGroup.Flags.HasFlag(DBUnitGroupFlags.NotObjectiveTarget)) { if (mission.ObjectiveIsStatic) { mission.CoreLuaScript += $"briefingRoom.mission.objectives[{i + 1}].groupID = {group.Units[0].ID}\r\n"; } else { // Add the ID of the unit group associated with this objective to the Lua script mission.CoreLuaScript += $"briefingRoom.mission.objectives[{i + 1}].groupID = {group.GroupID}\r\n"; } } } }
public DCSMissionUnitGroup AddUnitGroup( DCSMission mission, string[] units, Side side, Coordinates coordinates, string groupLua, string unitLua, DCSSkillLevel skill, DCSMissionUnitGroupFlags flags = 0, UnitTaskPayload payload = UnitTaskPayload.Default, Coordinates?coordinates2 = null, int airbaseID = 0, bool requiresParkingSpots = false, bool requiresOpenAirParking = false, Country?country = null, PlayerStartLocation startLocation = PlayerStartLocation.Runway) { if (units.Length == 0) { return(null); // No units database entries ID provided, cancel group creation } // TODO: check for missing units DBEntryUnit[] unitsBP = (from string u in units where Database.Instance.EntryExists <DBEntryUnit>(u) select Database.Instance.GetEntry <DBEntryUnit>(u)).ToArray(); unitsBP = (from DBEntryUnit u in unitsBP where u != null select u).ToArray(); if (unitsBP.Length == 0) { return(null); // All database entries were null, cancel group creation } Coalition coalition = (side == Side.Ally) ? mission.CoalitionPlayer : mission.CoalitionEnemy; // Pick group coalition if (!country.HasValue) { country = coalition == Coalition.Blue? Country.CJTFBlue : Country.CJTFRed; } double groupHeading = unitsBP[0].IsAircraft ? 0 : Toolbox.RandomDouble(Toolbox.TWO_PI); // Generate global group heading // Generate units in the group int unitIndex = 0; Coordinates?lastSpot = null; List <DCSMissionUnitGroupUnit> groupUnits = new List <DCSMissionUnitGroupUnit>(); foreach (DBEntryUnit unitBP in unitsBP) { if (unitBP == null) { continue; } for (int i = 0; i < unitBP.DCSIDs.Length; i++) { // Set unit coordinates and heading Coordinates unitCoordinates = coordinates; double unitHeading = groupHeading; SetUnitCoordinatesAndHeading(ref unitCoordinates, ref unitHeading, unitBP, unitIndex); // Get parking spot for the unit, if unit is parked at an airdrome int parkingSpot = 0; if (airbaseID > 0) { if (requiresParkingSpots) { parkingSpot = SpawnPointSelector.GetFreeParkingSpot(airbaseID, lastSpot, out Coordinates parkingCoordinates, requiresOpenAirParking); if (parkingSpot >= 0) { unitCoordinates = parkingCoordinates; } else { parkingSpot = 0; } lastSpot = unitCoordinates; } } else if (airbaseID == -99) //carrier code always parks 1 maybe will need more { parkingSpot = 1; } // Add unit to the list of units DCSMissionUnitGroupUnit unit = new DCSMissionUnitGroupUnit { Coordinates = unitCoordinates, Heading = unitHeading, ID = NextUnitID, Type = unitBP.DCSIDs[i], ParkingSpot = parkingSpot, Name = unitBP.ID }; groupUnits.Add(unit); unitIndex++; NextUnitID++; } } // Generate group name string groupName; UnitCallsign callsign = new UnitCallsign(); if (unitsBP[0].IsAircraft) // Aircraft group, name is a callsign { callsign = CallsignGenerator.GetCallsign(unitsBP[0].Families[0], coalition); groupName = callsign.GroupName; } else // Vehicle/ship/static group, name is a random group name { groupName = GetGroupName(unitsBP[0].Families[0]); } // Add group to the mission DCSMissionUnitGroup group = new DCSMissionUnitGroup { AirbaseID = airbaseID, CallsignLua = callsign.Lua, Category = unitsBP[0].Category, Coalition = coalition, Country = country.Value, Coordinates = airbaseID != 0? groupUnits[0].Coordinates : coordinates, Coordinates2 = coordinates2 ?? coordinates + Coordinates.CreateRandom(1, 2) * Toolbox.NM_TO_METERS, Flags = flags, GroupID = NextGroupID, LuaGroup = groupLua, Name = groupName, Skill = skill, Payload = payload, UnitID = units[0], LuaUnit = unitLua, Units = groupUnits.ToArray(), StartLocation = startLocation }; mission.UnitGroups.Add(group); NextGroupID++; DebugLog.Instance.WriteLine($"Added \"{group.Units[0].Type}\" unit group \"{group.Name}\" for coalition {group.Coalition.ToString().ToUpperInvariant()}", 2); return(group); }
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); }