Пример #1
0
        private static UnitCallsignFamily GetCallsignFamilyFromUnitFamily(UnitFamily unitFamily)
        {
            switch (unitFamily)
            {
            case UnitFamily.PlaneAWACS:
                return(UnitCallsignFamily.AWACS);

            case UnitFamily.PlaneTankerBasket:
            case UnitFamily.PlaneTankerBoom:
                return(UnitCallsignFamily.Tanker);

            default:
                return(UnitCallsignFamily.Aircraft);
            }
        }
Пример #2
0
        internal static bool IsAirDefense(this UnitFamily unitFamily)
        {
            switch (unitFamily)
            {
            case UnitFamily.VehicleAAA:
            case UnitFamily.VehicleAAAStatic:
            case UnitFamily.VehicleInfantryMANPADS:
            case UnitFamily.VehicleSAMLong:
            case UnitFamily.VehicleSAMMedium:
            case UnitFamily.VehicleSAMShort:
            case UnitFamily.VehicleSAMShortIR:
                return(true);
            }

            return(false);
        }
Пример #3
0
        internal DBCommonCarrierGroup()
        {
            INIFile ini = new($"{BRPaths.DATABASE}CarrierGroup.ini");

            CourseLength        = Math.Max(5.0, ini.GetValue <double>("CarrierGroup", "CourseLength")) * Toolbox.NM_TO_METERS;
            IdealWindOfDeck     = Math.Max(0.0, ini.GetValue <double>("CarrierGroup", "IdealWindOfDeck")) * Toolbox.KNOTS_TO_METERS_PER_SECOND;
            MinimumCarrierSpeed = Math.Max(0.0, ini.GetValue <double>("CarrierGroup", "MinimumCarrierSpeed")) * Toolbox.KNOTS_TO_METERS_PER_SECOND;
            ShipSpacing         = Math.Max(0.1, ini.GetValue <double>("CarrierGroup", "ShipSpacing")) * Toolbox.NM_TO_METERS;

            EscortUnitFamilies = new UnitFamily[ESCORT_FAMILIES_SHIP_COUNT][];
            for (int i = 0; i < ESCORT_FAMILIES_SHIP_COUNT; i++)
            {
                EscortUnitFamilies[i] = ini.GetValueArray <UnitFamily>(
                    "CarrierGroup",
                    "EscortUnitFamilies.CarrierCount" + ((i == ESCORT_FAMILIES_SHIP_COUNT - 1) ? "Max" : $"{i + 1}"));
            }
        }
Пример #4
0
        internal static object GetTACANCallsign(UnitFamily unitFamily)
        {
            switch (unitFamily)
            {
            default:
                return("TCN");

            case UnitFamily.ShipCarrierCATOBAR:
            case UnitFamily.ShipCarrierSTOBAR:
            case UnitFamily.ShipCarrierSTOVL:
                return("CVN");

            case UnitFamily.PlaneTankerBasket:
            case UnitFamily.PlaneTankerBoom:
                return("TKR");
            }
        }
Пример #5
0
        internal static UnitCategory GetUnitCategory(this UnitFamily unitFamily)
        {
            switch (unitFamily)
            {
            case UnitFamily.HelicopterAttack:
            case UnitFamily.HelicopterTransport:
            case UnitFamily.HelicopterUtility:
                return(UnitCategory.Helicopter);

            case UnitFamily.PlaneAttack:
            case UnitFamily.PlaneAWACS:
            case UnitFamily.PlaneBomber:
            case UnitFamily.PlaneDrone:
            case UnitFamily.PlaneFighter:
            case UnitFamily.PlaneInterceptor:
            case UnitFamily.PlaneSEAD:
            case UnitFamily.PlaneStrike:
            case UnitFamily.PlaneTankerBasket:
            case UnitFamily.PlaneTankerBoom:
            case UnitFamily.PlaneTransport:
                return(UnitCategory.Plane);

            case UnitFamily.ShipCarrierCATOBAR:
            case UnitFamily.ShipCarrierSTOBAR:
            case UnitFamily.ShipCarrierSTOVL:
            case UnitFamily.ShipCruiser:
            case UnitFamily.ShipFrigate:
            case UnitFamily.ShipSpeedboat:
            case UnitFamily.ShipSubmarine:
            case UnitFamily.ShipTransport:
                return(UnitCategory.Ship);

            case UnitFamily.StaticStructureMilitary:
            case UnitFamily.StaticStructureProduction:
            case UnitFamily.FOB:
            case UnitFamily.StaticStructureOffshore:
                return(UnitCategory.Static);

            case UnitFamily.Cargo:
                return(UnitCategory.Cargo);

            default:
                return(UnitCategory.Vehicle);
            }
        }
Пример #6
0
        public static DCSMissionUnitGroup FromCoalitionArmyAndUnitFamily(
            string luaGroup, string luaUnit,
            DefinitionCoalition army, TimePeriod timePeriod, UnitFamily family, int unitCount,
            int groupID, Coalition coalition, Coordinates coordinates)
        {
            List <string> unitList = new List <string>();

            UnitCategory category = HQTools.GetUnitCategoryFromUnitFamily(family);

            // FIXME: extendSearchToUnitsOfOtherFamilies and returnDefaultIfNoneFound should be parameters
            string[] availableUnits = army.GetUnits(timePeriod, family, false, false);

            if (availableUnits.Length == 0)
            {
                DebugLog.Instance.Log($"    WARNING: Cannot spawn unit group, no units of type {family.ToString().ToUpperInvariant()} for coalition {army.DisplayName.ToUpperInvariant()} in {timePeriod.ToString().ToUpperInvariant()}.");
                return(null);
            }

            do
            {
                unitList.AddRange((from u in HQTools.RandomFrom(availableUnits).Split('|') select u.Trim()));
            } while (unitList.Count < unitCount);

            // Some unit categories (helicopters and planes) require all units to be the same type
            if ((category == UnitCategory.Helicopter) || (category == UnitCategory.Plane))
            {
                for (int i = 1; i < unitList.Count; i++)
                {
                    unitList[i] = unitList[0];
                }
            }

            DCSMissionUnitGroup uGroup = new DCSMissionUnitGroup(
                luaGroup, luaUnit,
                category, groupID, coalition, coordinates,
                unitList.ToArray());

            return(uGroup);
        }
Пример #7
0
        internal bool IsValidForFamilyCountryAndPeriod(UnitFamily family, Country[] countries, Decade decade)
        {
            // Unit does not belong to the required family
            if (!Families.Contains(family))
            {
                return(false);
            }

            foreach (Country country in countries)
            {
                if (!Operators.ContainsKey(country))
                {
                    continue;
                }
                if ((Operators[country][0] <= decade) && (Operators[country][1] >= decade))
                {
                    return(true); // Found one operator operating the unit during the required decade
                }
            }

            return(false);
        }
Пример #8
0
        /// <summary>
        /// Returns the UnitCategory an UnitFamily belongs to.
        /// </summary>
        /// <param name="family">The unit family.</param>
        /// <returns>The unit category.</returns>
        public static UnitCategory GetUnitCategoryFromUnitFamily(UnitFamily family)
        {
            string roleStr = family.ToString().ToLowerInvariant();

            if (roleStr.StartsWith("helicopter"))
            {
                return(UnitCategory.Helicopter);
            }
            if (roleStr.StartsWith("plane"))
            {
                return(UnitCategory.Plane);
            }
            if (roleStr.StartsWith("ship"))
            {
                return(UnitCategory.Ship);
            }
            if (roleStr.StartsWith("static"))
            {
                return(UnitCategory.Static);
            }
            return(UnitCategory.Vehicle);
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        /// <summary>
        /// Add surface-to-air defense groups.
        /// </summary>
        /// <param name="mission">Mission to which generated units should be added</param>
        /// <param name="template">Mission template to use</param>
        /// <param name="airDefenseRange">Air-defense range category</param>
        /// <param name="enemyCoalitionDB">Enemy coalition database entry</param>
        /// <param name="coalition">Coalition of the spawn points air defense must be spawned at, or null to spawn them anywhere</param>
        /// <param name="unitMods">Unit mods the units can belong to</param>
        private void AddAirDefenseUnits(DCSMission mission, AirDefenseRange airDefenseRange, DBEntryCoalition enemyCoalitionDB, Coalition?coalition, string[] unitMods)
        {
            // Get the proper number of groups
            int groupCount = Database.Instance.Common.
                             EnemyAirDefense[(int)airDefense].GroupsInArea[(int)airDefenseRange].GetValue();

            if (groupCount < 1)
            {
                return;                  // No groups to add, no need to go any further
            }
            DCSMissionUnitGroupFlags flags = optionsShowEnemyUnits;

            UnitFamily[] unitFamilies;
            TheaterLocationSpawnPointType[] validSpawnPoints;
            switch (airDefenseRange)
            {
            default:     // case AirDefenseRange.ShortRange:
                unitFamilies     = new UnitFamily[] { UnitFamily.VehicleAAA, UnitFamily.VehicleAAAStatic, UnitFamily.VehicleInfantryMANPADS, UnitFamily.VehicleSAMShort, UnitFamily.VehicleSAMShort, UnitFamily.VehicleSAMShortIR, UnitFamily.VehicleSAMShortIR };
                validSpawnPoints = new TheaterLocationSpawnPointType[] { TheaterLocationSpawnPointType.LandSmall, TheaterLocationSpawnPointType.LandMedium, TheaterLocationSpawnPointType.LandLarge };
                break;

            case AirDefenseRange.MediumRange:
                unitFamilies     = new UnitFamily[] { UnitFamily.VehicleSAMMedium };
                validSpawnPoints = new TheaterLocationSpawnPointType[] { TheaterLocationSpawnPointType.LandMedium, TheaterLocationSpawnPointType.LandLarge };
                break;

            case AirDefenseRange.LongRange:
                unitFamilies     = new UnitFamily[] { UnitFamily.VehicleSAMLong };
                validSpawnPoints = new TheaterLocationSpawnPointType[] { TheaterLocationSpawnPointType.LandLarge };
                break;
            }

            for (int i = 0; i < groupCount; i++)
            {
                // Find spawn point at the proper distance from the objective(s), but not to close from starting airbase
                DBEntryTheaterSpawnPoint?spawnPoint =
                    UnitMaker.SpawnPointSelector.GetRandomSpawnPoint(
                        validSpawnPoints,
                        centerPoint,
                        distsFromCenter[(int)airDefenseRange],
                        opposingPoint,
                        new MinMaxD(minDistFromOpposingPoint[(int)airDefenseRange], 99999),
                        coalition);

                // No spawn point found, stop here.
                if (!spawnPoint.HasValue)
                {
                    DebugLog.Instance.WriteLine($"No spawn point found for {airDefenseRange} air defense unit groups", 1, DebugLogMessageErrorLevel.Warning);
                    return;
                }

                string[] units = enemyCoalitionDB.GetRandomUnits(Toolbox.RandomFrom(unitFamilies), mission.DateTime.Decade, 1, unitMods);

                DCSMissionUnitGroup group = UnitMaker.AddUnitGroup(
                    mission, units, ally? Side.Ally : Side.Enemy,
                    spawnPoint.Value.Coordinates,
                    "GroupVehicle", "UnitVehicle",
                    Toolbox.BRSkillLevelToDCSSkillLevel(skillLevel),
                    flags);

                if (group == null)
                {
                    DebugLog.Instance.WriteLine($"Failed to add {airDefenseRange} air defense unit group of type {units[0]}", 1, DebugLogMessageErrorLevel.Warning);
                }
            }
        }
Пример #11
0
        private Coordinates PlaceInAirbase(MissionTemplateRecord template, DBEntrySituation situationDB, DBEntryAirbase playerAirbase, List <KeyValuePair <string, object> > extraSettings, DBEntryObjectiveTarget targetDB, DBEntryObjectiveTargetBehavior targetBehaviorDB, ref string luaUnit, Coordinates objectiveCoordinates, int unitCount, UnitFamily objectiveTargetUnitFamily)
        {
            int airbaseID                  = 0;
            var parkingSpotIDsList         = new List <int>();
            var parkingSpotCoordinatesList = new List <Coordinates>();
            var targetAirbaseOptions       =
                (from DBEntryAirbase airbaseDB in situationDB.GetAirbases(template.OptionsMission.Contains("InvertCountriesCoalitions"))
                 where airbaseDB.DCSID != playerAirbase.DCSID
                 select airbaseDB).OrderBy(x => x.Coordinates.GetDistanceFrom(objectiveCoordinates));
            DBEntryAirbase targetAirbase = targetAirbaseOptions.FirstOrDefault(x => template.OptionsMission.Contains("SpawnAnywhere") ? true : x.Coalition == template.ContextPlayerCoalition.GetEnemy());

            airbaseID = targetAirbase.DCSID;

            var parkingSpots = UnitMaker.SpawnPointSelector.GetFreeParkingSpots(
                targetAirbase.DCSID,
                unitCount, objectiveTargetUnitFamily,
                targetBehaviorDB.Location == DBEntryObjectiveTargetBehaviorLocation.SpawnOnAirbaseParkingNoHardenedShelter);

            parkingSpotIDsList         = parkingSpots.Select(x => x.DCSID).ToList();
            parkingSpotCoordinatesList = parkingSpots.Select(x => x.Coordinates).ToList();
            luaUnit += "Parked";

            extraSettings.Add("GroupAirbaseID".ToKeyValuePair(airbaseID));
            extraSettings.Add("ParkingID".ToKeyValuePair(parkingSpotIDsList.ToArray()));
            extraSettings.Add("UnitX".ToKeyValuePair((from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.X).ToArray()));
            extraSettings.Add("UnitY".ToKeyValuePair((from Coordinates coordinates in parkingSpotCoordinatesList select coordinates.Y).ToArray()));
            return(targetAirbase.Coordinates);
        }
Пример #12
0
        private bool ValidateAirfieldParking(List <DBEntryAirbaseParkingSpot> parkingSpots, UnitFamily unitFamily, int unitCount)
        {
            var openSpots = parkingSpots.Count(X => X.ParkingType == ParkingSpotType.OpenAirSpawn);

            if (openSpots >= unitCount) //Is there just enough open spaces
            {
                return(true);
            }

            // Helicopters
            if (unitFamily.GetUnitCategory() == UnitCategory.Helicopter)
            {
                return(parkingSpots.Count(X => X.ParkingType == ParkingSpotType.HelicopterOnly) + openSpots > unitCount);
            }

            // Aircraft that can't use bunkers
            if (IsBunkerUnsuitable(unitFamily))
            {
                return(parkingSpots.Count(X => X.ParkingType == ParkingSpotType.AirplaneOnly) + openSpots > unitCount);
            }

            // Bunkerable aircraft
            return(parkingSpots.Count(X => X.ParkingType == ParkingSpotType.HardenedAirShelter) + openSpots > unitCount);
        }
Пример #13
0
 private bool IsBunkerUnsuitable(UnitFamily unitFamily) =>
 LARGE_AIRCRAFT.Contains(unitFamily) || unitFamily.GetUnitCategory() == UnitCategory.Helicopter;
Пример #14
0
        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));
        }
Пример #15
0
        private List <DBEntryAirbaseParkingSpot> FilterAndSortSuitableSpots(DBEntryAirbaseParkingSpot[] parkingspots, UnitFamily unitFamily, bool requiresOpenAirParking)
        {
            var validTypes = new List <ParkingSpotType> {
                ParkingSpotType.OpenAirSpawn,
                ParkingSpotType.HardenedAirShelter,
                ParkingSpotType.AirplaneOnly
            };

            if (unitFamily.GetUnitCategory() == UnitCategory.Helicopter)
            {
                validTypes = new List <ParkingSpotType> {
                    ParkingSpotType.OpenAirSpawn,
                    ParkingSpotType.HelicopterOnly,
                }
            }
            ;
            else if (IsBunkerUnsuitable(unitFamily) || requiresOpenAirParking)
            {
                validTypes = new List <ParkingSpotType> {
                    ParkingSpotType.OpenAirSpawn
                }
            }
            ;

            return(parkingspots.Where(x => validTypes.Contains(x.ParkingType)).OrderBy(x => x.ParkingType).ToList());
        }
Пример #16
0
 public static string GetBriefingStringForUnitFamily(UnitFamily unitFamily, bool plural)
 {
     return(Database.Instance.Common.UnitBriefingNames[(int)unitFamily][plural ? 1 : 0]);
 }
Пример #17
0
        internal List <DBEntryAirbaseParkingSpot> GetFreeParkingSpots(int airbaseID, int unitCount, UnitFamily unitFamily, bool requiresOpenAirParking = false)
        {
            if (!AirbaseParkingSpots.ContainsKey(airbaseID))
            {
                throw new BriefingRoomException($"Airbase {airbaseID} not found in parking map");
            }


            var airbaseDB    = SituationDB.GetAirbases(InvertCoalition).First(x => x.DCSID == airbaseID);
            var parkingSpots = new List <DBEntryAirbaseParkingSpot>();
            DBEntryAirbaseParkingSpot?lastSpot = null;

            for (int i = 0; i < unitCount; i++)
            {
                var viableSpots = FilterAndSortSuitableSpots(AirbaseParkingSpots[airbaseID].ToArray(), unitFamily, requiresOpenAirParking);
                if (viableSpots.Count == 0)
                {
                    throw new BriefingRoomException("Airbase didn't have enough suitable parking spots.");
                }
                var parkingSpot = viableSpots.First();
                if (lastSpot.HasValue) //find nearest spot distance wise in attempt to cluster
                {
                    parkingSpot = viableSpots
                                  .Aggregate((acc, x) => acc.Coordinates.GetDistanceFrom(lastSpot.Value.Coordinates) > x.Coordinates.GetDistanceFrom(lastSpot.Value.Coordinates) ? x : acc);
                }

                lastSpot = parkingSpot;
                AirbaseParkingSpots[airbaseID].Remove(parkingSpot);
                parkingSpots.Add(parkingSpot);
            }

            return(parkingSpots);
        }
Пример #18
0
 public static bool IsUnitFamilyAircraft(UnitFamily value)
 {
     return
         ((GetUnitCategoryFromUnitFamily(value) == UnitCategory.Helicopter) ||
          (GetUnitCategoryFromUnitFamily(value) == UnitCategory.Plane));
 }
Пример #19
0
 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);
 }
Пример #20
0
        /// <summary>
        /// Adds media files, scripts and units associated with mission features.
        /// </summary>
        /// <param name="mission">Mission to which features and extensions 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>
        public void GenerateExtensionsAndFeatures(DCSMission mission, MissionTemplate template, DBEntryObjective objectiveDB, DBEntryCoalition[] coalitionsDB)
        {
            int i, j;

            DBEntryExtension[] extensions = Database.Instance.GetEntries <DBEntryExtension>(template.ScriptExtensions);
            foreach (DBEntryExtension extension in extensions)
            {
                AddIncludedFiles(mission, extension);
            }

            DBEntryMissionFeature[] features = Database.Instance.GetEntries <DBEntryMissionFeature>(objectiveDB.MissionFeatures);
            foreach (DBEntryMissionFeature feature in features)
            {
                AddIncludedFiles(mission, feature);

                // No unit family in the unit group, so not unit group to add
                if (feature.UnitGroup.Families.Length == 0)
                {
                    continue;
                }

                Side side = feature.UnitGroup.Flags.HasFlag(DBUnitGroupFlags.Friendly) ? Side.Ally : Side.Enemy;

                UnitFamily unitFamily = Toolbox.RandomFrom(feature.UnitGroup.Families);

                // Pick units
                string[] units =
                    coalitionsDB[(int)((side == Side.Ally) ? mission.CoalitionPlayer : mission.CoalitionEnemy)].GetRandomUnits(
                        unitFamily, mission.DateTime.Decade,
                        feature.UnitGroup.Count.GetValue(), template.UnitMods);

                DCSSkillLevel skillLevel;
                if (side == Side.Ally)
                {
                    skillLevel = Toolbox.BRSkillLevelToDCSSkillLevel(template.SituationFriendlyAISkillLevel);
                }
                else
                {
                    skillLevel = Toolbox.IsUnitFamilyAircraft(unitFamily) ?
                                 Toolbox.BRSkillLevelToDCSSkillLevel(template.SituationEnemySkillLevelAir) : Toolbox.BRSkillLevelToDCSSkillLevel(template.SituationEnemySkillLevelGround);
                }

                DCSMissionUnitGroupFlags flags = 0;

                List <int> unitGroupsID = new List <int>();
                for (i = 0; i < mission.Objectives.Length; i++)
                {
                    Coordinates[] coordinates = new Coordinates[2];
                    for (j = 0; j < 2; j++)
                    {
                        switch (feature.UnitGroupCoordinates[j])
                        {
                        case DBEntryMissionFeatureUnitGroupLocation.Homebase:
                            coordinates[j] = mission.InitialPosition + Coordinates.CreateRandom(2, 6) * Toolbox.NM_TO_METERS;
                            break;

                        case DBEntryMissionFeatureUnitGroupLocation.Objective:
                            coordinates[j] = mission.Objectives[i].Coordinates;
                            break;

                        case DBEntryMissionFeatureUnitGroupLocation.ObjectiveNear:
                            coordinates[j] = mission.Objectives[i].Coordinates + Coordinates.CreateRandom(1.5, 4) * Toolbox.NM_TO_METERS;
                            break;

                        case DBEntryMissionFeatureUnitGroupLocation.Waypoint:
                            coordinates[j] = mission.Objectives[i].WaypointCoordinates;
                            break;

                        case DBEntryMissionFeatureUnitGroupLocation.WaypointNear:
                            coordinates[j] = mission.Objectives[i].WaypointCoordinates + Coordinates.CreateRandom(1.5, 4) * Toolbox.NM_TO_METERS;
                            break;
                        }
                    }

                    DCSMissionUnitGroup group = UnitMaker.AddUnitGroup(
                        mission, units, side,
                        coordinates[0],
                        Toolbox.RandomFrom(feature.UnitGroup.LuaGroup), feature.UnitGroup.LuaUnit,
                        skillLevel, flags, UnitTaskPayload.Default, coordinates[1]);

                    if (group == null)
                    {
                        DebugLog.Instance.WriteLine($"Failed to create mission feature unit group for objective #{i + 1} made of the following units: {string.Join(", ", units)}", 1, DebugLogMessageErrorLevel.Warning);
                    }

                    unitGroupsID.Add(group.GroupID);

                    // Add aircraft group to the queue of aircraft groups to be spawned
                    if (!feature.UnitGroup.Flags.HasFlag(DBUnitGroupFlags.ManualActivation) &&
                        ((group.Category == UnitCategory.Helicopter) || (group.Category == UnitCategory.Plane) || feature.UnitGroup.Flags.HasFlag(DBUnitGroupFlags.DelaySpawn)))
                    {
                        mission.AircraftSpawnQueue.Add(new DCSMissionAircraftSpawnQueueItem(group.GroupID, true));
                    }
                }

                if (unitGroupsID.Count > 0)
                {
                    mission.LuaSettings += $"briefingRoom.mission.featuresUnitGroups.{feature.ID} = {{ {string.Join(", ", unitGroupsID)} }}";
                }
            }
        }
        /// <summary>
        /// Spawn a group of support units.
        /// </summary>
        /// <param name="mission">Mission to which generated units should be added</param>
        /// <param name="allyCoalitionDB">Ally coalition database entry</param>
        /// <param name="unitFamily">Family of support unit to spawn</param>
        /// <param name="unitMods">Unit mods selected units can belong to</param>
        /// <param name="TACAN">TACAN info for the unit, if any</param>
        private UnitFlightGroupBriefingDescription AddSupportUnit(DCSMission mission, DBEntryCoalition allyCoalitionDB, UnitFamily unitFamily, string[] unitMods, Tacan TACAN = null)
        {
            DebugLog.Instance.WriteLine($"Adding {unitFamily} support unit...", 1);

            string[] validUnitTypes = allyCoalitionDB.GetRandomUnits(unitFamily, mission.DateTime.Decade, 1, unitMods, false);

            if (validUnitTypes.Length == 0)
            {
                DebugLog.Instance.WriteLine($"No support unit found for this role in coalition \"{allyCoalitionDB.ID}\"", 2);
                return(new UnitFlightGroupBriefingDescription()); // Empty FG info will automatically be discarded
            }

            string groupLua;

            switch (unitFamily)
            {
            case UnitFamily.PlaneAWACS:
                groupLua = "GroupAircraftAWACS";
                break;

            case UnitFamily.PlaneTankerBasket:
            case UnitFamily.PlaneTankerBoom:
                groupLua = "GroupAircraftTanker";
                break;

            default:                                              // Should never happen
                return(new UnitFlightGroupBriefingDescription()); // Empty FG info will automatically be discarded
            }

            Coordinates location  = GeneratorTools.GetCoordinatesOnFlightPath(mission, .5) + Coordinates.CreateRandom(8, 12) * Toolbox.NM_TO_METERS;
            Coordinates location2 = location + Coordinates.CreateRandom(12, 20) * Toolbox.NM_TO_METERS;

            string unitType = Toolbox.RandomFrom(validUnitTypes);

            DCSMissionUnitGroup group = UnitMaker.AddUnitGroup(
                mission, new string[] { unitType },
                Side.Ally, location,
                groupLua, "UnitAircraft",
                DCSSkillLevel.Excellent, 0,
                UnitTaskPayload.Default,
                location2);

            if (group == null)
            {
                return(new UnitFlightGroupBriefingDescription()); // Empty FG info will automatically be discarded
            }
            group.TACAN = TACAN;
            mission.AircraftSpawnQueue.Insert(0, new DCSMissionAircraftSpawnQueueItem(group.GroupID, true)); // Support aircraft must be activated first

            return(new UnitFlightGroupBriefingDescription(
                       group.Name, group.Units.Length, unitType,
                       (unitFamily == UnitFamily.PlaneAWACS) ? "Early warning" : "Refueling",
                       Database.Instance.GetEntry <DBEntryUnit>(unitType).AircraftData.GetRadioAsString(), TACAN != null? $"TACAN: {TACAN.ToString()}":""));
        }
Пример #22
0
        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));
        }
Пример #23
0
        /// <summary>
        /// Generates the data for the objectives.
        /// </summary>
        /// <param name="mission">The mission for which to generate objectives</param>
        /// <param name="template">Mission template to use</param>
        /// <param name="objectiveDB">Objective database entry</param>
        private void GenerateObjectivesData(DCSMission mission, MissionTemplate template, DBEntryObjective objectiveDB, DBEntryTheater theaterDB)
        {
            // Keep in mind the position of the last objective/player location.
            // Start with initial player location.
            Coordinates lastCoordinates = mission.InitialPosition;

            // Common family to use for all objectives if DBEntryObjectiveFlags.SingleTargetUnitFamily is set
            UnitFamily singleObjectiveUnitFamily = objectiveDB.GetRandomUnitFamily();

            for (int i = 0; i < template.ObjectiveCount; i++)
            {
                // Pick a random unique name, or a waypoint number if objectives shouldn't be named
                string objectiveName = PickUniqueObjectiveName();

                DebugLog.Instance.WriteLine($"Adding objective #{i + 1}, designated {objectiveName}", 1);

                // Compute a random distance from last position, in nautical miles
                double objectiveDistanceNM =
                    (template.ObjectiveDistanceNM == 0) ?
                    Toolbox.RandomInt(TemplateTools.MIN_OBJECTIVE_DISTANCE, TemplateTools.MAX_OBJECTIVE_DISTANCE) :
                    template.ObjectiveDistanceNM;

                if (i > 0) // Objective is not the first one, spawn it close to the previous objective
                {
                    objectiveDistanceNM /= 5.0;
                }

                MinMaxD distanceFromLast =
                    new MinMaxD(OBJECTIVE_DISTANCE_VARIATION_MIN, OBJECTIVE_DISTANCE_VARIATION_MAX) * objectiveDistanceNM;
                Coordinates           objectiveCoordinates;
                DBEntryTheaterAirbase?airbase = null;

                if (objectiveDB.UnitGroup.SpawnPoints[0] != TheaterLocationSpawnPointType.Airbase)
                {
                    // Look for a valid spawn point
                    DBEntryTheaterSpawnPoint?spawnPoint =
                        SpawnPointSelector.GetRandomSpawnPoint(
                            // If spawn point types are specified, use them. Else look for spawn points of any type
                            (objectiveDB.UnitGroup.SpawnPoints.Length > 0) ? objectiveDB.UnitGroup.SpawnPoints : null,
                            // Select spawn points at a proper distance from last location (previous objective or home airbase)
                            lastCoordinates, distanceFromLast,
                            // Make sure no objective is too close to the initial location
                            mission.InitialPosition, new MinMaxD(objectiveDistanceNM * OBJECTIVE_DISTANCE_VARIATION_MIN, 999999999),
                            GeneratorTools.GetEnemySpawnPointCoalition(template));
                    // No spawn point found for the objective, abort mission creation.
                    if (!spawnPoint.HasValue)
                    {
                        throw new Exception($"Failed to find a spawn point for objective {i + 1}");
                    }
                    objectiveCoordinates = spawnPoint.Value.Coordinates;
                }
                else
                {
                    airbase = new MissionGeneratorAirbases().SelectObjectiveAirbase(mission, template, theaterDB, lastCoordinates, distanceFromLast, i == 0);
                    if (!airbase.HasValue)
                    {
                        throw new Exception($"Failed to find a airbase point for objective {i + 1}");
                    }
                    objectiveCoordinates = airbase.Value.Coordinates;
                }


                // Set the waypoint coordinates according the the inaccuracy defined in the objective database entry
                Coordinates waypointCoordinates =
                    objectiveCoordinates +
                    Coordinates.CreateRandom(objectiveDB.WaypointInaccuracy * Toolbox.NM_TO_METERS);

                // Select an objective family for the target if any or default to VehicleTransport.
                UnitFamily objectiveUnitFamily = singleObjectiveUnitFamily;

                if (!objectiveDB.Flags.HasFlag(DBEntryObjectiveFlags.SingleTargetUnitFamily))
                {
                    objectiveUnitFamily = objectiveDB.GetRandomUnitFamily();
                }

                // Set the mission objective
                mission.Objectives[i] = new DCSMissionObjective(
                    objectiveName, objectiveCoordinates, objectiveUnitFamily, waypointCoordinates, airbase.HasValue? airbase.Value.DCSID: 0);

                // Last position is now the position of this objective
                lastCoordinates = objectiveCoordinates;
            }

            // If the target is a static object, make sure the correct flag is enabled as it has an influence of some scripts
            mission.ObjectiveIsStatic = objectiveDB.UnitGroup.Category.HasValue && (objectiveDB.UnitGroup.Category.Value == UnitCategory.Static);

            // Make sure objectives are ordered by distance from the players' starting location
            mission.Objectives = mission.Objectives.OrderBy(x => mission.InitialPosition.GetDistanceFrom(x.WaypointCoordinates)).ToArray();
        }
        /// <summary>
        /// Spawn a group of support units.
        /// </summary>
        /// <param name="mission">Mission to which generated units should be added</param>
        /// <param name="enemyCoalitionDB">Ally coalition database entry</param>
        /// <param name="unitFamily">Family of support unit to spawn</param>
        /// <param name="unitMods">Unit mods selected units can belong to</param>
        /// <param name="TACAN">TACAN info for the unit, if any</param>
        private void AddSupportUnit(DCSMission mission, MissionTemplate template, DBEntryCoalition enemyCoalitionDB, UnitFamily unitFamily, string[] unitMods, Tacan TACAN = null)
        {
            DebugLog.Instance.WriteLine($"Adding {unitFamily} enemy support unit...", 1);

            string[] validUnitTypes = enemyCoalitionDB.GetRandomUnits(unitFamily, mission.DateTime.Decade, 1, unitMods, false);

            if (validUnitTypes.Length == 0)
            {
                DebugLog.Instance.WriteLine($"No support unit found for this role in coalition \"{enemyCoalitionDB.ID}\"", 2);
                return; // Empty FG info will automatically be discarded
            }

            string groupLua;

            switch (unitFamily)
            {
            case UnitFamily.PlaneAWACS:
                groupLua = "GroupAircraftAWACSMortal";
                break;

            case UnitFamily.PlaneTankerBasket:
            case UnitFamily.PlaneTankerBoom:
                groupLua = "GroupAircraftTankerMortal";
                break;

            default:     // Should never happen
                return;  // Empty FG info will automatically be discarded
            }

            DBEntryTheaterSpawnPoint?spawnPoint =
                UnitMaker.SpawnPointSelector.GetRandomSpawnPoint(
                    null,
                    mission.ObjectivesCenter, Database.Instance.Common.EnemyCAPDistanceFromObjectives,
                    mission.InitialPosition, new MinMaxD(Database.Instance.Common.EnemyCAPMinDistanceFromTakeOffLocation, 99999),
                    GeneratorTools.GetEnemySpawnPointCoalition(template));

            if (!spawnPoint.HasValue) // No spawn point found, stop here.
            {
                DebugLog.Instance.WriteLine("No spawn point found for enemy fighter patrol group.", 1, DebugLogMessageErrorLevel.Warning);
                return;
            }

            Coordinates location2 = spawnPoint.Value.Coordinates + Coordinates.CreateRandom(12, 20) * Toolbox.NM_TO_METERS;

            string unitType = Toolbox.RandomFrom(validUnitTypes);

            DCSMissionUnitGroup group = UnitMaker.AddUnitGroup(
                mission, new string[] { unitType },
                Side.Enemy, spawnPoint.Value.Coordinates,
                groupLua, "UnitAircraft",
                Toolbox.BRSkillLevelToDCSSkillLevel(template.SituationEnemySkillLevelAir), 0,
                UnitTaskPayload.Default,
                location2);

            if (group == null)
            {
                return; // Empty FG info will automatically be discarded
            }
            group.TACAN = TACAN;
            mission.AircraftSpawnQueue.Insert(0, new DCSMissionAircraftSpawnQueueItem(group.GroupID, true)); // Support aircraft must be activated first
        }