예제 #1
0
        public void Generate(CampaignTemplate campaignTemplate, string campaignFilePath)
        {
            string campaignName      = Path.GetFileNameWithoutExtension(campaignFilePath);
            string campaignDirectory = Path.GetDirectoryName(campaignFilePath);

            DCSMissionDateTime date = GenerateCampaignDate(campaignTemplate);

            using (MissionGenerator generator = new MissionGenerator())
            {
                for (int i = 0; i < campaignTemplate.MissionsCount; i++)
                {
                    // Increment the date by a few days for each mission after the first
                    if (i > 0)
                    {
                        IncrementDate(ref date);
                    }

                    MissionTemplate template = CreateMissionTemplate(campaignTemplate, i);

                    DCSMission mission = generator.Generate(template);
                    mission.MissionName  = $"{campaignName}, phase {i + 1}";
                    mission.DateTime.Day = date.Day; mission.DateTime.Month = date.Month; mission.DateTime.Year = date.Year;

                    MizFile miz = mission.ExportToMiz();
                    miz.SaveToFile(Path.Combine(campaignDirectory, $"{campaignName}{i + 1:00}.miz"));
                }
            }

            CreateImageFiles(campaignTemplate, campaignFilePath);
            CreateCMPFile(campaignTemplate, campaignFilePath);
        }
예제 #2
0
        /// <summary>
        /// Generates wind settings for the mission. Must be called once mission weather level has been set, as weather is used for auto wind.
        /// </summary>
        /// <param name="mission">The mission.</param>
        /// <param name="wind">The preferred wind speed.</param>
        /// <param name="theater">Theater definition from which to get wind info for this part of the world.</param>
        public void GenerateWind(DCSMission mission, Wind wind, DefinitionTheater theater)
        {
            DebugLog.Instance.Log("Generating wind...");

            DebugLog.Instance.Log($"  Wind speed should be {wind.ToString().ToUpperInvariant()}");

            // If auto, speed depends on weather, so we never end up with no wind in a storm
            mission.WindLevel = (wind == Wind.Auto) ?
                                (Wind)(HQTools.Clamp((int)mission.WeatherLevel + HQTools.RandomMinMax(-1, 1), 0, (int)Wind.StrongGale))
                : wind;

            DebugLog.Instance.Log($"    Wind speed level set to {mission.WindLevel}");

            for (int i = 0; i < 3; i++)
            {
                mission.WeatherWindSpeed[i]     = Math.Max(0, theater.Wind[(int)mission.WindLevel].Wind.GetValue());
                mission.WeatherWindDirection[i] = (mission.WeatherWindSpeed[i] > 0) ? HQTools.RandomInt(0, 360) : 0;
                DebugLog.Instance.Log($"    Wind speed at {WIND_ALTITUDE[i]} meters set to {mission.WeatherWindSpeed[i]} m/s, direction of {mission.WeatherWindDirection[i]}");
            }

            // Turbulence = max(weatherTurbulence, windTurbulence)
            mission.WeatherTurbulence = Math.Max(mission.WeatherTurbulence, theater.Wind[(int)mission.WindLevel].Turbulence.GetValue());
            DebugLog.Instance.Log($"    Turbulence updated to {mission.WeatherTurbulence} m/s");

            DebugLog.Instance.Log();
        }
예제 #3
0
 internal static void GenerateBullseyes(DCSMission mission, Coordinates objectivesCenter)
 {
     mission.SetValue("BullseyeBlueX", objectivesCenter.X + GetBullseyeRandomDistance());
     mission.SetValue("BullseyeBlueY", objectivesCenter.Y + GetBullseyeRandomDistance());
     mission.SetValue("BullseyeRedX", objectivesCenter.X + GetBullseyeRandomDistance());
     mission.SetValue("BullseyeRedY", objectivesCenter.Y + GetBullseyeRandomDistance());
 }
        /// <summary>
        /// Directly copies some simple values (theater database entry ID, etc.) from the template.
        /// </summary>
        /// <param name="mission">The mission</param>
        /// <param name="template">Mission template to use</param>
        private void CopyTemplateValues(DCSMission mission, MissionTemplate template)
        {
            mission.Coalitions[(int)Coalition.Blue] = template.GetCoalition(Coalition.Blue);
            mission.Coalitions[(int)Coalition.Red]  = template.GetCoalition(Coalition.Red);
            mission.CivilianTraffic      = template.OptionsCivilianTraffic;
            mission.CoalitionPlayer      = template.ContextCoalitionPlayer;
            mission.Weather.CloudsPreset = template.EnvironmentCloudPreset.Get();
            mission.RadioAssists         = !template.Realism.Contains(RealismOption.DisableDCSRadioAssists);
            mission.Theater      = template.ContextTheater;
            mission.CountryBlues = new List <Country> {
                Country.CJTFBlue
            };
            mission.CountryReds = new List <Country> {
                Country.CJTFRed
            };
            var countries = template.PlayerFlightGroups.Select(x => x.Country).Distinct().ToList();

            if (template.ContextCoalitionPlayer == Coalition.Blue)
            {
                mission.CountryBlues.AddRange(countries);
            }
            else
            {
                mission.CountryReds.AddRange(countries);
            }
            mission.CountryBlues   = mission.CountryBlues.Distinct().ToList();
            mission.CountryReds    = mission.CountryReds.Distinct().ToList();
            mission.EndMode        = template.OptionsEndMode;
            mission.RealismOptions = template.Realism;
        }
예제 #5
0
        private static void SaveWaypointsToBriefing(DCSMission mission, Coordinates initialCoordinates, List <Waypoint> waypoints, bool useImperialSystem, UnitMakerGroupInfo?groupInfo)
        {
            double      totalDistance = 0;
            Coordinates lastWP        = initialCoordinates;

            // Add first (takeoff) and last (landing) waypoints to get a complete list of all waypoints
            List <Waypoint> allWaypoints = new List <Waypoint>(waypoints);

            allWaypoints.Insert(0, new Waypoint(Database.Instance.Common.Names.WPInitialName, initialCoordinates));
            allWaypoints.Add(new Waypoint(Database.Instance.Common.Names.WPFinalName, initialCoordinates));
            mission.Briefing.AddItem(DCSMissionBriefingItemType.Waypoint, $"\t{groupInfo.Value.Name}\t");

            List <string> waypointTextRows = new List <string>();

            foreach (Waypoint waypoint in allWaypoints)
            {
                double distanceFromLast = waypoint.Coordinates.GetDistanceFrom(lastWP);
                totalDistance += distanceFromLast;
                lastWP         = waypoint.Coordinates;

                string waypointText =
                    waypoint.Name + "\t" +
                    (useImperialSystem ? $"{distanceFromLast * Toolbox.METERS_TO_NM:F0} nm" : $"{distanceFromLast / 1000.0:F0} Km") + "\t" +
                    (useImperialSystem ? $"{totalDistance * Toolbox.METERS_TO_NM:F0} nm" : $"{totalDistance / 1000.0:F0} Km");

                mission.Briefing.AddItem(DCSMissionBriefingItemType.Waypoint, waypointText);
                waypointTextRows.Add(waypointText);
            }
            mission.Briefing.FlightBriefings.Add(new DCSMissionFlightBriefing {
                Name      = groupInfo.Value.Name,
                Type      = groupInfo.Value.UnitDB.DCSIDs.First(),
                Waypoints = waypointTextRows
            });
        }
        private void CreateAircraftActivationQueues(DCSMission mission)
        {
            string[] initialQueue = (from DCSMissionAircraftSpawnQueueItem queueItem in mission.AircraftSpawnQueue
                                     where queueItem.SpawnOnStart select queueItem.GroupID.ToString()).ToArray();
            mission.CoreLuaScript += $"briefingRoom.aircraftActivator.currentQueue = {{ {string.Join(",", initialQueue)} }}\r\n";

            List <string> extraQueues = (from DCSMissionAircraftSpawnQueueItem queueItem in mission.AircraftSpawnQueue
                                         where !queueItem.SpawnOnStart select queueItem.GroupID.ToString()).ToList();
            int totalExtraQueues = extraQueues.Count;

            mission.CoreLuaScript += "briefingRoom.aircraftActivator.extraQueues = { ";
            for (int i = 0; i < mission.Objectives.Length; i++)
            {
                int length = (i == mission.Objectives.Length - 1) ? extraQueues.Count : totalExtraQueues / mission.Objectives.Length;
                mission.CoreLuaScript += $" {{ {string.Join(",", extraQueues.Take(length))} }}";
                if (i < mission.Objectives.Length - 1)
                {
                    mission.CoreLuaScript += ", ";
                }
                extraQueues.RemoveRange(0, length);
            }
            mission.CoreLuaScript += "}\r\n";

            mission.CoreLuaScript += $"briefingRoom.aircraftActivator.escortCAP = {mission.EscortCAPGroupId}\r\n";
            mission.CoreLuaScript += $"briefingRoom.aircraftActivator.escortSEAD  = {mission.EscortSEADGroupId}\r\n";
        }
예제 #7
0
        internal DBEntryAirbase SelectStartingAirbase(DCSMission mission, string selectedAirbaseID, int requiredParkingSpots = 0, int requiredRunway = 0)
        {
            // Get total number of required parking spots for flight groups
            if (requiredParkingSpots == 0)
            {
                requiredParkingSpots = _template.PlayerFlightGroups.Sum(x => x.Count);
            }
            // Select all airbases for this theater
            DBEntryAirbase[] airbases = _situationDB.GetAirbases(_template.OptionsMission.Contains("InvertCountriesCoalitions"));
            // If a particular airbase name has been specified and an airbase with this name exists, pick it
            if (!string.IsNullOrEmpty(selectedAirbaseID))
            {
                var airbase = airbases.FirstOrDefault(x => x.ID == selectedAirbaseID);
                if (airbase is null)
                {
                    throw new BriefingRoomException($"No airbase found with ID \"{selectedAirbaseID}\", cannot spawn player aircraft.");
                }

                return(airbase);
            }

            var opts = airbases.Where(x =>
                                      x.ParkingSpots.Length >= requiredParkingSpots &&
                                      x.Coalition == _template.ContextPlayerCoalition &&
                                      x.RunwayLengthFt > requiredRunway &&
                                      (MissionPrefersShoreAirbase() ? x.Flags.HasFlag(AirbaseFlag.NearWater) : true)
                                      ).ToList();

            if (opts.Count == 0)
            {
                throw new BriefingRoomException($"No airbase found, cannot spawn player aircraft.");
            }
            return(Toolbox.RandomFrom(opts));
        }
예제 #8
0
        internal void SelectStartingAirbaseForPackages(DCSMission mission, DBEntryAirbase homeBase)
        {
            var missionPackages = new List <DCSMissionPackage>();

            foreach (var package in _template.AircraftPackages)
            {
                if (package.StartingAirbase == "home")
                {
                    missionPackages.Add(new DCSMissionPackage(_template.AircraftPackages.IndexOf(package), homeBase));
                    continue;
                }
                var flights        = _template.PlayerFlightGroups.Where((v, i) => package.FlightGroupIndexes.Contains(i));
                var requiredSpots  = flights.Sum(x => x.Count);
                var requiredRunway = flights.Select(x => Database.Instance.GetEntry <DBEntryUnit>(x.Aircraft).AircraftData.MinimumRunwayLengthFt).Max();
                var airbase        = SelectStartingAirbase(mission, package.StartingAirbase, requiredSpots, requiredRunway);

                if (missionPackages.Any(x => x.Airbase == airbase))
                {
                    mission.Briefing.AddItem(DCSMissionBriefingItemType.Airbase, $"{airbase.Name}\t{airbase.Runways}\t{airbase.ATC}\t{airbase.ILS}\t{airbase.TACAN}");
                }

                missionPackages.Add(new DCSMissionPackage(_template.AircraftPackages.IndexOf(package), airbase));
            }
            mission.MissionPackages.AddRange(missionPackages);
        }
예제 #9
0
        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);
        }
예제 #10
0
        internal static int GenerateWeather(DCSMission mission, MissionTemplateRecord template, DBEntryTheater theaterDB, Month month, DBEntryAirbase playerAirbase)
        {
            var baseAlt = template.OptionsMission.Contains("SeaLevelRefCloud") ? 0.0 : playerAirbase.Elevation;

            if (template.OptionsMission.Contains("HighCloud"))
            {
                baseAlt += 2000;
            }
            DBEntryWeatherPreset weatherDB;

            if (string.IsNullOrEmpty(template.EnvironmentWeatherPreset)) // Random weather
            {
                weatherDB = Toolbox.RandomFrom(Database.Instance.GetAllEntries <DBEntryWeatherPreset>());
            }
            else
            {
                weatherDB = Database.Instance.GetEntry <DBEntryWeatherPreset>(template.EnvironmentWeatherPreset);
            }

            mission.SetValue("WeatherName", weatherDB.BriefingDescription);
            mission.SetValue("WeatherCloudsBase", weatherDB.CloudsBase.GetValue() + baseAlt);
            mission.SetValue("WeatherCloudsPreset", Toolbox.RandomFrom(weatherDB.CloudsPresets));
            mission.SetValue("WeatherCloudsThickness", weatherDB.CloudsThickness.GetValue());
            mission.SetValue("WeatherDust", weatherDB.Dust);
            mission.SetValue("WeatherDustDensity", weatherDB.DustDensity.GetValue());
            mission.SetValue("WeatherFog", weatherDB.Fog);
            mission.SetValue("WeatherFogThickness", weatherDB.FogThickness.GetValue());
            mission.SetValue("WeatherFogVisibility", weatherDB.FogVisibility.GetValue());
            mission.SetValue("WeatherQNH", weatherDB.QNH.GetValue());
            mission.SetValue("WeatherTemperature", theaterDB.Temperature[(int)month].GetValue());
            mission.SetValue("WeatherVisibility", weatherDB.Visibility.GetValue());

            return(weatherDB.Turbulence.GetValue());
        }
        /// <summary>
        /// Creates the raw text briefing, to be used for the mission description inside DCS World.
        /// </summary>
        /// <param name="description"></param>
        /// <param name="tasks"></param>
        /// <param name="remarks"></param>
        /// <param name="flightGroups"></param>
        /// <param name="airbaseDB">Airbase player will take off from and land back on</param>
        /// <returns></returns>
        private string CreateTXTBriefing(
            DCSMission mission, string description, List <string> tasks, List <string> remarks,
            List <UnitFlightGroupBriefingDescription> flightGroups, DBEntryTheaterAirbase airbaseDB)
        {
            DebugLog.Instance.WriteLine("Generating raw text mission briefing...", 2);

            string briefing = description + "\n\n";

            briefing += "TASKS:\n";
            foreach (string t in tasks)
            {
                briefing += $"- {t}\n";
            }
            briefing += "\n";

            briefing += "REMARKS:\n";
            foreach (string r in remarks)
            {
                briefing += $"- {r}\n";
            }
            briefing += "\n";

            briefing += "MISSION PACKAGE:\n";
            foreach (UnitFlightGroupBriefingDescription fg in flightGroups)
            {
                briefing += $"- {fg.Callsign} ({fg.Count}×{fg.Type}, {fg.Task}) - {fg.Radio}{(string.IsNullOrEmpty(fg.Remarks) ? "" : $", {fg.Remarks}")}\n";
            }
예제 #12
0
        internal static void GenerateTitle(DCSMission mission, MissionTemplateRecord template)
        {
            ImageMaker imageMaker = new();

            imageMaker.TextOverlay.Alignment = ContentAlignment.MiddleCenter;
            imageMaker.TextOverlay.Text      = mission.Briefing.Name;

            List <ImageMakerLayer> imageLayers = new List <ImageMakerLayer>();

            string[] theaterImages = Directory.GetFiles($"{BRPaths.INCLUDE_JPG}Theaters\\", $"{Database.Instance.GetEntry<DBEntryTheater>(template.ContextTheater).DCSID}*.jpg");
            if (theaterImages.Length == 0)
            {
                imageLayers.Add(new ImageMakerLayer("_default.jpg"));
            }
            else
            {
                imageLayers.Add(new ImageMakerLayer("Theaters\\" + Path.GetFileName(Toolbox.RandomFrom(theaterImages))));
            }

            imageLayers.Add(new ImageMakerLayer($"Flags\\{template.GetCoalitionID(template.ContextPlayerCoalition)}.png", ContentAlignment.TopLeft, 8, 8, 0, .5));

            byte[] imageBytes = imageMaker.GetImageBytes(imageLayers.ToArray());

            mission.AddMediaFile($"l10n/DEFAULT/title_{mission.UniqueID}.jpg", imageBytes);
        }
        /// <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="playerCoalitionDB">Player coalition database entry</param>
        /// <param name="aiEscortTypeCAP">Type of aircraft selected for AI CAP escort</param>
        /// <param name="aiEscortTypeSEAD">Type of aircraft selected for AI SEAD escort</param>
        /// <returns>An array of <see cref="UnitFlightGroupBriefingDescription"/> describing the flight groups, to be used in the briefing</returns>
        public UnitFlightGroupBriefingDescription[] CreateUnitGroups(DCSMission mission, MissionTemplate template, DBEntryObjective objectiveDB, DBEntryCoalition playerCoalitionDB, out string aiEscortTypeCAP, out string aiEscortTypeSEAD)
        {
            List <UnitFlightGroupBriefingDescription> briefingFGList = new List <UnitFlightGroupBriefingDescription>();

            if (template.MissionType == MissionType.SinglePlayer)
            {
                briefingFGList.Add(GenerateSinglePlayerFlightGroup(mission, template, objectiveDB));
            }
            else
            {
                briefingFGList.AddRange(GenerateMultiplayerFlightGroups(mission, template, objectiveDB));
            }

            aiEscortTypeCAP  = "";
            aiEscortTypeSEAD = "";
            UnitFlightGroupBriefingDescription?escortDescription;

            escortDescription = GenerateAIEscort(mission, template, template.SituationFriendlyEscortCAP, MissionTemplateFlightGroupTask.SupportCAP, playerCoalitionDB);
            if (escortDescription.HasValue)
            {
                briefingFGList.Add(escortDescription.Value);
                aiEscortTypeCAP = escortDescription.Value.Type;
            }

            escortDescription = GenerateAIEscort(mission, template, template.SituationFriendlyEscortSEAD, MissionTemplateFlightGroupTask.SupportSEAD, playerCoalitionDB);
            if (escortDescription.HasValue)
            {
                briefingFGList.Add(escortDescription.Value);
                aiEscortTypeSEAD = escortDescription.Value.Type;
            }

            return(briefingFGList.ToArray());
        }
예제 #14
0
        internal static Tuple <double, double> GenerateWind(DCSMission mission, MissionTemplateRecord template, int turbulenceFromWeather)
        {
            var windSpeedAtSeaLevel     = 0.0;
            var windDirectionAtSeaLevel = 0.0;

            Wind windLevel = template.EnvironmentWind == Wind.Random ? PickRandomWindLevel() : template.EnvironmentWind;

            BriefingRoom.PrintToLog($"Wind speed level set to \"{windLevel}\".");

            int windAverage = 0;

            for (int i = 0; i < 3; i++)
            {
                int windSpeed     = Database.Instance.Common.Wind[(int)windLevel].Wind.GetValue();
                int windDirection = windSpeed > 0 ? Toolbox.RandomInt(0, 360) : 0;
                if (i == 0)
                {
                    windSpeedAtSeaLevel     = windSpeed;
                    windDirectionAtSeaLevel = windDirection * Toolbox.DEGREES_TO_RADIANS;
                }
                windAverage += windSpeed;

                mission.SetValue($"WeatherWindSpeed{i + 1}", windSpeed);
                mission.SetValue($"WeatherWindDirection{i + 1}", windDirection);
            }
            windAverage /= 3;

            mission.SetValue($"WeatherWindName", windLevel.ToString()); // TODO: get name from attribute
            mission.SetValue($"WeatherWindSpeedAverage", windAverage);

            mission.SetValue("WeatherGroundTurbulence", Database.Instance.Common.Wind[(int)windLevel].Turbulence.GetValue() + turbulenceFromWeather);
            return(new(windSpeedAtSeaLevel, windDirectionAtSeaLevel));
        }
예제 #15
0
        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);
        }
예제 #16
0
        internal static byte[] ExportToMizBytes(DCSMission mission)
        {
            Dictionary <string, byte[]> MizFileEntries = new Dictionary <string, byte[]>();

            AddStringValueToEntries(MizFileEntries, "briefing.html", mission.Briefing.GetBriefingAsHTML(true));
            AddStringValueToEntries(MizFileEntries, "credits.txt", "Generated with BriefingRoom for DCS World (https://akaagar.itch.io/briefing-room-for-dcs)");
            AddLuaFileToEntries(MizFileEntries, "mission", "Mission.lua", mission);
            AddLuaFileToEntries(MizFileEntries, "options", "Options.lua", null);
            AddStringValueToEntries(MizFileEntries, "theatre", mission.GetValue("TheaterID"));
            AddLuaFileToEntries(MizFileEntries, "warehouses", "Warehouses.lua", mission);

            AddLuaFileToEntries(MizFileEntries, "l10n/DEFAULT/dictionary", "Dictionary.lua", null);
            AddLuaFileToEntries(MizFileEntries, "l10n/DEFAULT/mapResource", "MapResource.lua", mission);
            AddLuaFileToEntries(MizFileEntries, "l10n/DEFAULT/script.lua", "Script.lua", mission);

            foreach (string mediaFile in mission.GetMediaFileNames())
            {
                byte[] fileBytes = mission.GetMediaFile(mediaFile);
                if (fileBytes == null)
                {
                    continue;
                }
                MizFileEntries.Add(mediaFile, fileBytes);
            }

            return(Toolbox.ZipData(MizFileEntries));
        }
        /// <summary>
        /// Generates the title image for the mission.
        /// </summary>
        /// <param name="mission">The misison which requires a title image.</param>
        /// <returns>The mission title image, as an array of bytes for a JPEG file.</returns>
        private byte[] GetTitleImage(DCSMission mission)
        {
            byte[] imageBytes;


            using (ImageMaker imgMaker = new ImageMaker())
            {
                imgMaker.TextOverlay.Text      = mission.MissionName;
                imgMaker.TextOverlay.Alignment = ContentAlignment.BottomCenter;

                List <ImageMakerLayer> layers = new List <ImageMakerLayer>();
                string[] theaterImages        = Directory.GetFiles($"{BRPaths.INCLUDE_JPG}Theaters\\", $"{mission.Theater}*.jpg");
                if (theaterImages.Length == 0)
                {
                    layers.Add(new ImageMakerLayer("_default.jpg"));
                }
                else
                {
                    layers.Add(new ImageMakerLayer("Theaters\\" + Path.GetFileName(Toolbox.RandomFrom(theaterImages))));
                }

                layers.Add(new ImageMakerLayer($"Flags\\{GeneratorTools.RemoveAfterComma(mission.Coalitions[(int)mission.CoalitionPlayer])}.png", ContentAlignment.TopLeft, 8, 8, 0, .5));

                imageBytes = imgMaker.GetImageBytes(layers.ToArray());
            }

            return(imageBytes);
        }
예제 #18
0
        /// <summary>
        /// Sets the coalition to which the various airbases on the theater belong.
        /// </summary>
        /// <param name="mission">Mission for which airbase coalitions must be set</param>
        /// <param name="theaterAirbasesCoalitions">Airbase coalition setting</param>
        /// <param name="theaterDB">Theater database entry</param>
        public void SetupAirbasesCoalitions(DCSMission mission, CountryCoalition theaterAirbasesCoalitions, DBEntryTheater theaterDB)
        {
            mission.AirbasesCoalition.Clear();
            foreach (DBEntryTheaterAirbase ab in theaterDB.Airbases)
            {
                // Airbase ID already exists in the mission
                if (mission.AirbasesCoalition.ContainsKey(ab.DCSID))
                {
                    continue;
                }

                // Airbase is the player starting airbase, always set it to the player coalition
                if (ab.DCSID == mission.InitialAirbaseID)
                {
                    mission.AirbasesCoalition.Add(ab.DCSID, mission.CoalitionPlayer);
                    continue;
                }

                // Other airbases are assigned to a coalition according to the theater and the template settings
                Coalition airbaseCoalition = ab.Coalition;
                switch (theaterAirbasesCoalitions)
                {
                case CountryCoalition.AllBlue: airbaseCoalition = Coalition.Blue; break;

                case CountryCoalition.AllRed: airbaseCoalition = Coalition.Red; break;

                case CountryCoalition.Inverted: airbaseCoalition = (Coalition)(1 - (int)ab.Coalition); break;
                }

                mission.AirbasesCoalition.Add(ab.DCSID, airbaseCoalition);
            }
        }
        /// <summary>
        /// Generate a random mission name if none is provided in the template, or returns the provided name if there is one.
        /// </summary>
        /// <param name="mission">The mission.</param>
        /// <param name="template">The provided mission name in the template.</param>
        public void GenerateMissionName(DCSMission mission, string templateMissionName)
        {
            DebugLog.Instance.Log("Generating mission name...");

            if (templateMissionName == null)
            {
                templateMissionName = "";
            }

            // If a custom mission name was provided, use it...
            if (!string.IsNullOrEmpty(templateMissionName.Trim()))
            {
                mission.BriefingName = templateMissionName.Trim();
                return;
            }

            // ...else generate a random name.
            // First get a random template then replace parts 1 to MAX_MISSION_NAME_PARTS ($PART1$, $PART2$, $PART3$...) by random parts.
            string name = HQTools.RandomFrom(Language.GetStringArray("Mission", "Name.Template"));

            for (int i = 1; i <= MAX_MISSION_NAME_PARTS; i++)
            {
                name = name.Replace(
                    $"$P{i.ToString()}$",
                    HQTools.RandomFrom(Language.GetStringArray("Mission", $"Name.Part{i.ToString()}")));
            }

            mission.BriefingName = name;

            DebugLog.Instance.Log("");
        }
        /// <summary>
        /// Creates the flight group player will lead in a single-player mission.
        /// </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>
        /// <returns>A <see cref="UnitFlightGroupBriefingDescription"/> describing the flight group, to be used in the briefing</returns>
        private UnitFlightGroupBriefingDescription GenerateSinglePlayerFlightGroup(DCSMission mission, MissionTemplate template, DBEntryObjective objectiveDB)
        {
            var  playerFlightGroup = template.PlayerFlightGroups[0];
            bool isCarrier         = !string.IsNullOrEmpty(playerFlightGroup.Carrier);

            DebugLog.Instance.WriteLine($"{playerFlightGroup.Carrier} -> {string.Join(",",mission.Carriers.Select(x => x.Name).ToArray())}");
            DCSMissionUnitGroup group = UnitMaker.AddUnitGroup(
                mission,
                Enumerable.Repeat(playerFlightGroup.Aircraft, playerFlightGroup.Count).ToArray(),
                Side.Ally, isCarrier? mission.Carriers.First(x => x.Units[0].Name == playerFlightGroup.Carrier).Coordinates : mission.InitialPosition,
                isCarrier? "GroupAircraftPlayerCarrier" : "GroupAircraftPlayer", "UnitAircraft",
                Toolbox.BRSkillLevelToDCSSkillLevel(template.SituationFriendlyAISkillLevel), DCSMissionUnitGroupFlags.FirstUnitIsPlayer,
                objectiveDB.Payload,
                null, isCarrier? -99 : mission.InitialAirbaseID, true, country: playerFlightGroup.Country,
                startLocation: playerFlightGroup.StartLocation
                );

            if (group == null)
            {
                throw new Exception($"Failed to create group of player aircraft of type \"{playerFlightGroup.Aircraft}\".");
            }

            if (isCarrier)
            {
                group.CarrierId = mission.Carriers.First(x => x.Units[0].Name == playerFlightGroup.Carrier).Units[0].ID;
            }

            return(new UnitFlightGroupBriefingDescription(
                       group.Name, group.Units.Length, playerFlightGroup.Aircraft,
                       objectiveDB.BriefingTaskFlightGroup,
                       Database.Instance.GetEntry <DBEntryUnit>(playerFlightGroup.Aircraft).AircraftData.GetRadioAsString()));
        }
예제 #21
0
 internal void AddMission(DCSMission mission)
 {
     if (mission == null)
     {
         return;
     }
     Missions.Add(mission);
 }
 /// <summary>
 /// Read values from the mission and make replacements in the Lua file
 /// </summary>
 /// <param name="lua">Lua string</param>
 /// <param name="mission">HQ4DCS mission to use</param>
 private void MakeCommonReplacements(ref string lua, DCSMission mission)
 {
     HQTools.ReplaceKey(ref lua, "UnitNames", CreateUnitNamesTable(mission.UseNATOCallsigns));
     HQTools.ReplaceKey(ref lua, "ObjectiveNames", CreateObjectiveNamesTable(mission));
     HQTools.ReplaceKey(ref lua, "PlayerCoalition", mission.CoalitionPlayer.ToString().ToUpperInvariant());
     HQTools.ReplaceKey(ref lua, "EnemyCoalition", mission.CoalitionEnemy.ToString().ToUpperInvariant());
     HQTools.ReplaceKey(ref lua, "ObjectiveCount", mission.Objectives.Length);
 }
예제 #23
0
        /// <summary>
        /// Generates the <see cref="DCSMissionObjective"/>.
        /// </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>
        public void CreateObjectives(DCSMission mission, MissionTemplate template, DBEntryObjective objectiveDB, DBEntryTheater theaterDB)
        {
            // Set the array for the proper number of objective
            mission.Objectives = new DCSMissionObjective[template.ObjectiveCount];

            GenerateObjectivesData(mission, template, objectiveDB, theaterDB);
            GenerateObjectivesScript(mission);
        }
예제 #24
0
        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
        }
예제 #25
0
        /// <summary>
        /// Exports a BriefingRoom mission to a DCS .miz file.
        /// </summary>
        /// <param name="mission">The mission to export</param>
        /// <returns>A MizFile if everything went well, null if an error happened.</returns>
        public MizFile ExportToMizFile(DCSMission mission)
        {
            string resourceOggString;

            if (mission == null)
            {
                return(null);
            }

            DebugLog.Instance.Clear();
            DebugLog.Instance.WriteLine($"Started MIZ file export...");

            DateTime exportStartTime = DateTime.Now;
            MizFile  miz             = new MizFile();

            miz.AddEntry("Credits.txt", $"Generated with BriefingRoom for DCS World ({BriefingRoom.WEBSITE_URL})");

            DebugLog.Instance.WriteLine(" Adding \"briefing.html\" entry...", 1);
            miz.AddEntry("briefing.html", mission.BriefingHTML);

            DebugLog.Instance.WriteLine(" Adding \"mission\" entry...", 1);
            using (MizMakerLuaMission luaMission = new MizMakerLuaMission())
                miz.AddEntry("mission", luaMission.MakeLua(mission));

            DebugLog.Instance.WriteLine(" Adding \"options\" entry...", 1);
            miz.AddEntry("options", LuaTools.ReadIncludeLuaFile("Options.lua"));

            DebugLog.Instance.WriteLine(" Adding \"theater\" entry...", 1);
            miz.AddEntry("theatre", mission.Theater);

            DebugLog.Instance.WriteLine(" Adding \"warehouses\" entry...", 1);
            using (MizMakerLuaWarehouse luaWarehouses = new MizMakerLuaWarehouse())
                miz.AddEntry("warehouses", luaWarehouses.MakeLua(mission));

            DebugLog.Instance.WriteLine(" Adding \"l10n/DEFAULT/dictionary\" entry...", 1);
            miz.AddEntry("l10n/DEFAULT/dictionary", LuaTools.ReadIncludeLuaFile("Dictionary.lua"));

            DebugLog.Instance.WriteLine(" Adding \"l10n/DEFAULT/script.lua\" entry...", 1);
            using (MizMakerLuaScript luaScript = new MizMakerLuaScript())
                miz.AddEntry("l10n/DEFAULT/script.lua", luaScript.MakeLua(mission), false);

            DebugLog.Instance.WriteLine(" Adding .ogg audio media files...", 1);
            using (MizMakerMediaAudio oggMedia = new MizMakerMediaAudio())
                oggMedia.AddMediaFiles(miz, mission, out resourceOggString);

            DebugLog.Instance.WriteLine(" Adding \"l10n/DEFAULT/mapResource\" entry...", 1);
            using (MizMakerLuaMapResource luaMapResource = new MizMakerLuaMapResource())
                miz.AddEntry("l10n/DEFAULT/mapResource", luaMapResource.MakeLua(mission, resourceOggString));

            DebugLog.Instance.WriteLine(" Adding .jpg image media files...", 1);
            using (MizMakerMediaImages jpgMedia = new MizMakerMediaImages())
                jpgMedia.AddMediaFiles(miz, mission);

            DebugLog.Instance.WriteLine($"Export to .miz file completed in {(DateTime.Now - exportStartTime).TotalSeconds.ToString("F3", NumberFormatInfo.InvariantInfo)} second(s).");

            return(miz);
        }
        /// <summary>
        /// Generates the content of the Lua file.
        /// </summary>
        /// <param name="mission">The mission from which to generate the .Miz file.</param>
        /// <param name="resourceOggString">An string containing the Lua declaring all embedded .ogg files.</param>
        /// <returns>The contents of the Lua file.</returns>
        public string MakeLua(DCSMission mission, string resourceOggString)
        {
            string lua = LuaTools.ReadIncludeLuaFile("MapResource.lua");

            LuaTools.ReplaceKey(ref lua, "OggFiles", resourceOggString);
            LuaTools.ReplaceKey(ref lua, "MissionID", mission.UniqueID);

            return(lua);
        }
예제 #27
0
        /// <summary>
        /// Returns coordinates situated somewhere between the initial airbase and the center point of objectives.
        /// </summary>
        /// <param name="mission">The DCS mission</param>
        /// <param name="lerpValue">Progess on the airbase to objectives center distance (0.0=airbase, 1.0=objective center)</param>
        /// <returns>A set of coordinates</returns>
        public static Coordinates GetCoordinatesOnFlightPath(DCSMission mission, double lerpValue)
        {
            Coordinates coordinates = Coordinates.Lerp(mission.InitialPosition, mission.ObjectivesCenter, lerpValue);
            double      distance    = mission.InitialPosition.GetDistanceFrom(mission.ObjectivesCenter);

            // Create some random variation proportional to the total flight path distance
            distance = Math.Max(20.0, distance);
            return(coordinates + Coordinates.CreateRandom(distance / 8, distance / 4));
        }
        public void AddMediaFiles(MizFile miz, DCSMission mission, out string resourceOggString)
        {
            resourceOggString = "";

            foreach (string ogg in mission.OggFiles)
            {
                AddOggFile(miz, ogg, ref resourceOggString);
            }
        }
예제 #29
0
 /// <summary>
 /// Sets the mission bullseye for both coalitions.
 /// </summary>
 /// <param name="mission">The mission</param>
 public void SetBullseye(DCSMission mission)
 {
     for (int i = 0; i < 2; i++)
     {
         mission.Bullseye[i] =
             mission.ObjectivesCenter +
             Coordinates.CreateRandom(20 * Toolbox.NM_TO_METERS, 40 * Toolbox.NM_TO_METERS);
     }
 }
        /// <summary>
        /// Generates the list of tasks for the mission.
        /// </summary>
        /// <param name="mission"></param>
        /// <param name="template"></param>
        /// <param name="missionTask"></param>
        //public void GenerateMissionTasks(HQMission mission, MissionTemplate template, DefinitionMissionObjective missionTask)
        //{
        //    HQDebugLog.Instance.Log("Generating mission briefing objectives...");

        //    mission.BriefingTasks.Clear();

        //    mission.BriefingTasks.Add(Language.GetStringRandom("BriefingCommon", $"Task.TakeOff").Replace("$AIRBASE$", mission.Airbases[0].Name));

        //    foreach (HQMissionObjectiveLocation o in mission.Objectives)
        //        mission.BriefingTasks.Add(Language.GetStringRandom("BriefingMission", $"Task.{missionTask.BriefingTask}").Replace("$NAME$", o.Name));

        //    mission.BriefingTasks.Add(Language.GetStringRandom("BriefingCommon", $"Task.Land").Replace("$AIRBASE$", mission.Airbases[1].Name));

        //    HQDebugLog.Instance.Log("");
        //}

        //public void GenerateMissionRemarks(HQMission mission, MissionTemplate template, DefinitionMissionObjective missionTask)
        //{
        //    HQDebugLog.Instance.Log("Generating mission briefing remarks...");

        //    mission.BriefingRemarks.Clear();

        //    foreach (string s in missionTask.BriefingRemarks)
        //        mission.BriefingRemarks.Add(Language.GetStringRandom("BriefingMission", $"Remark.{s}"));

        //    HQDebugLog.Instance.Log("");
        //}

        public void GenerateRawTextBriefing(DCSMission mission, MissionTemplate template)
        {
            DebugLog.Instance.Log("Generating raw text MIZ briefing...");

            string text = "";

            if (template.GetPlayerCount() == 1)
            {
                text += $"{Language.GetString("Briefing", "Subtitle.SinglePlayer")}\n\n";
            }
            else
            {
                text += $"{Language.GetString("Briefing", "Subtitle.PvE").Replace("$PLAYERS$", HQTools.ValToString(template.GetPlayerCount()))}\n\n";
            }

            text += mission.BriefingDescription + "\n\n";

            // Tasks
            text += $"{Language.GetString("Briefing", "Section.Tasks").ToUpperInvariant()}{Language.Semicolon}\n";
            foreach (string t in mission.BriefingTasks)
            {
                text += $"- {t}\n";
            }
            if (mission.BriefingTasks.Count == 0)
            {
                text += $"- {Language.GetString("Briefing", "Misc.None")}\n";
            }
            text += "\n";

            // Remarks
            text += $"{Language.GetString("Briefing", "Section.Remarks").ToUpperInvariant()}{Language.Semicolon}\n";
            if (mission.BriefingImperialUnits)
            {
                text += $"- {Language.GetString("Briefing", "Remark.TotalFlightPlanNM", "Distance", (mission.TotalFlightPlanDistance * HQTools.METERS_TO_NM).ToString("F0"))}\n";
            }
            else
            {
                text += $"- {Language.GetString("Briefing", "Remark.TotalFlightPlanKM", "Distance", (mission.TotalFlightPlanDistance / 1000.0).ToString("F0"))}\n";
            }
            foreach (string t in mission.BriefingRemarks)
            {
                text += $"- {t}\n";
            }
            text += "\n";

            // Flight package
            //text += $"{GetString("Section.Package").ToUpperInvariant()}{Language.Semicolon}\n";
            //foreach (HQMissionBriefingFlightGroup fg in (from HQMissionBriefingFlightGroup f in mission.BriefingFlightPackage where !f.IsSupport select f).OrderBy(x => x.Task))
            //    text += $"- {fg.Callsign} ({fg.UnitCount}x {GetUnitName(fg.UnitType)}), {HQTools.ValToString(fg.Frequency, "F1")} Mhz\n";

            // Make sure endlines are in the proper format (escaped LF) or it can cause bugs.
            text = text.Replace("\r\n", "\n").Trim(' ', '\n', '\t').Replace("\n", "\\\n");
            mission.BriefingRawText = text;

            DebugLog.Instance.Log("");
        }